0

I have a .csv file (delimiter is |) that has AD fields as the header and the strings to go in there as the data. I'd like to create a hash table from that .csv file that has the column header as the key and the string information as the data.

Here is the file format:

LastName|FirstName|Office|Employeeid|BusinessTitle|CoreSector|Sector|CmbCorePractice|CmbPractice|Region|Committees|SectorLeaderRole|PracticeLeaderRole|AreaCountryRole|FirmLeaderShipRoleOne|FirmLeaderShipRole|generationQualifier|givenName|middlename|sn|extensionAttribute12|homePostalAddress|telephoneNumber|ipPhone|facsimileTelephoneNumber|mobile|homePhone|department|manager|assistant|extensionAttribute13
SMITH|JAMES|AMSTERDAM|0000000000|Leader|Healthcare|#|#|#|Europe|#|#|#|#|#|#|MR|JAMES|#|SMITH|#|#|+1 212 000 7692|0000|#|#|#|Knowledge Management|0001000000|#|#|#|#

The data begins with SMITH and that lines up with LastName.

4
  • 3
    It would help us to see: example CSV data (obfuscated, of course), and the code you've already tried to implement (and where it failed). Commented May 11, 2016 at 19:52
  • 2
    But why? :) an array of objects is so much easier to work with, safer (you know 100% sure which attribute values that belong together) and it is easily imported with $ad = import-csv -path myfile.csv -delimiter "|" Commented May 11, 2016 at 21:27
  • @FrodeF. - I ultimately would like to compare what's in the .csv file to what's in AD so I could update AD only with what is in the file as the file is the source and I thought hash tables would be the best to do it. Right now, my current script goes through the .csv file and updates AD with the information whether it is new or not (information could be the same in the file and AD but file still overwrites AD). Commented May 13, 2016 at 14:59
  • Does it matter that it overwrites attributes as long as the value is the same before and after? Set-ADUser -Replace $ht requires a hashtable of attributes and values. Having it in a hashtable vs. object doesn't make any difference as you still need to check attributes one by one against the AD-object and add changed to a "attributestomodify"-hashtable. If the file may contain multiple users, then it's even more reason to use Import-CSV -Delimiter '|'. :-) Commented May 13, 2016 at 17:00

3 Answers 3

4

That's simple enough. Read the first line of the CSV to get the keys for the hashtable, like this:

$keys = (Get-Content 'C:\path\to\your.csv' -TotalCount 1) -split '\|'

or like this:

$keys = (Get-Content 'C:\path\to\your.csv' -TotalCount 1).Split('|')

Next import the CSV:

$csv = Import-Csv 'C:\path\to\your.csv' -Delimiter '|'

Then collect the columns of the CSV into a hashtable:

$ht = @{}
foreach ($key in $keys) {
  $ht[$key] = $csv | Select -Expand $key
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you @AnsgarWiechers I tried your script but it seems to break up the keys into individual characters. It looks to work with the first record but not subsequent records. I will attach the source file.
@allenr74: Try -split '\|' instead of -split '|'. The -split operator's separator argument is interpreted as a regular expression, so in order to use a literal | it must be \ -escaped.
1

I came across this post while I was trying to determine how to do something similar. My goal was also to take the column names generically from the first line of the CSV (credit to Ansgar Wiechers' excellent answer for solving this issue for me). Ansgar's answer creates a hashtable, where the value of each key is an array of all the values for that key.

For my purposes, I needed an array, where the value of each element is a hashtable. I.e., each element of the array corresponds to a line in the original CSV. This gives me the benefit of being able to iterate through each record in the CSV, and then iterate through each column in the record.

Since the OP's requirements for which format he ultimately needed his data in were nicely ambiguous, I thought I'd post my solution as a supplement to Ansgar's.

Note that to fit the OP's specific use case, it is only necessary to change the value of $DELIM from , to |.

# Constants.
$DELIM = ','
$CSV_F = 'file.csv'

# Parse keys
$keys = (gc "${CSV_F}" -TotalCount 1).Split($DELIM)
$csv = Import-CSV "${CSV_F}"
$data = @()

# Iterate through CSV to build array of hashtables.
ForEach ($r in $csv) {
    $tmp_h = @{}

    # Create hash of key-value pairs.
    ForEach($k in $keys) {
        $tmp_h[$k] = $r.($k)
    }

    # Add hash to array of hashes.
    $data += $tmp_h
}

# Display data
$data.ForEach({[PSCustomObject]$_}) | ft -AutoSize

Given the following sample data in file.csv:

RecordId,Name,Value
1,Alpha,Kilo
2,Bravo,Lima
3,Charlie,Mike
4,Delta,November
5,Echo,Oscar
6,Foxtrot,Papa
7,Golf,Quebec
8,Hotel,Romeo
9,India,Sierra
10,Juliet,Tango

The following output will be generated:

Name    Value    RecordId
----    -----    --------
Alpha   Kilo     1
Bravo   Lima     2
Charlie Mike     3
Delta   November 4
Echo    Oscar    5
Foxtrot Papa     6
Golf    Quebec   7
Hotel   Romeo    8
India   Sierra   9
Juliet  Tango    10

Comments

1

I wanted the same result as Doug's Answer but went about it in a bit more compact way. The goal was to read in from a csv file and to be able to add attributes to each row for use later in the script.

$csv = Import-CSV file.csv
$data = $csv| % {
     $row = @{};
     $_.psobject.Properties | % {$row[$_.name]= $_.value};
     $row;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.