Search code examples
powershellhashtable

Using a variable to define a hashtable name in Powershell


I am reading a series of text files into hashtables so I can reference back to them in a script. The text files are well formatted to do so as name/value pairs. The text file is formatted as:

a b
c d
e f
g h

where 'a, c, e, g' are the keys and 'b,d,f,h' are the values... except there are more than 1000 lines.

For example, I have successfully named an empty hashtable after a portion of my file name with:

$FileName = 'testName' #example

$hashName = new-variable -Name $FileName -Value @{}

Ref. Stack Overflow article Calling/Setting a variable with a variable in the name

I now have an empty hashtable called testName. However, I cannot add to testName through the variable $hashName.

"$hashName".Add(1,2)

fails because [System.String] does not contain a method named 'Add'.

$hashName.Add(1,2)

fails because [System.Management.Automation.PSVariable] does not contain a method named 'Add'. (makes sense)

Note that $testName.Add(1,2) works just fine, but in this does me no good, as I'd like to loop through several variables of $testName that I extract from the multiple files that I'd like to read.


Solution

  • It's probably not the variable you want to name based on file names - you'll want to use the file names as entry keys in the hashtable instead.

    You can then nest other hashtables in the first one, one for each file for example:

    # Create hashtable, assign to a variable named 'fileContents'
    $fileContents = @{}
    
    # Loop through all the text files with ForEach-Object
    Get-ChildItem path\to\folder -File -Filter *.txt |ForEach-Object {
        # Now we can use the file name to create entries in the hashtable
        # Let's create a (nested) hashtable to contain the key-value pairs from the file
        $fileContents[$_.Name] = @{}
    
        Get-Content -LiteralPath $_.FullName |ForEach-Object {
            # split line into key-value pair
            $key,$value = -split $_
    
            # populate nested hashtable
            $fileContents[$_.Name][$key] = $value
        }
    }
    

    $fileContents will now contain a hashtable where each entry has a file name as its key, and another hashtable containing the key-value pairs from the corresponding file as its value.

    To access the contents of key c file named data.txt for example, you'd use the name and key as indices:

    $fileName = 'data.txt'
    $key = 'c'
    $fileContents[$fileName][$key] # this will contain the string `d`, given your sample input