none
Unable to reference items in a hashtable RRS feed

  • Question

  • HI,

    I'm having a bad PowerShell day today!

    My sample script to read in a text file and put the data into a hash table works just fine:

    $InputFile=Get-Content C:\Out\ktf06011.REQ
    $CurrentUserHashTable = @{}
    ForEach ($Line in $InputFile)
    {
    $Data=$Line.Split("=")
    $Label=$Data[0].Trim()
    $Label=$Label.Insert(($Label.Length),"`"")
    $Label=$Label.Insert(0,"`"")
    $Value=$Data[1].Trim()
    $Value=$Value.Insert(($Value.Length),"`"")
    $Value=$Value.Insert(0,"`"")
    $CurrentUserHashTable.Add($Label,$Value)
    }
    $CurrentUserHashTable 

    However, when I use this within a script that uses a file system watcher event to discover the presence of the text file, I cannot get anything from the hash table. I can see my variables being created, ready to pass on to the .add statement. I have found a workaround for now - not using a hash table - but would love to know why I see this behaviour and suggestions for getting at the data.

    Here is the code that I'm having trouble with.

    $folder = 'c:\In'
    $OutFolder = 'c:\Out'
    $filter = '*.*'
    $CurrentUserHashTable = $NULL
    $FileSystemWatcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
    Register-ObjectEvent $FileSystemWatcher Created -SourceIdentifier FileCreated -Action {
    $name = $Event.SourceEventArgs.Name
    $InputFile=Get-Content $folder\$name
    ForEach ($Line in $InputFile)
    {
    #Write-Host $Line
    $CurrentUserHashTable = @{}
    $Data=$Line.Split("=")
    #Write-Host "Data: " $Data
    $Label=$Data[0].Trim()
    $Label=$Label.Insert(($Label.Length),"`"")
    $Label=$Label.Insert(0,"`"")
    #Write-Host "Label: " $Label
    $Value=$Data[1].Trim()
    $Value=$Value.Insert(($Value.Length),"`"")
    $Value=$Value.Insert(0,"`"")
    #Write-Host "Value: " $Value
    $CurrentUserHashTable.Add($Label,$Value)
    }
    $CurrentUserHashTable
    Move-Item $folder\$name $OutFolder -Force
    }
    
    #Label:  "ID"
    #Value:  "abc00001"
    #Label:  "PID"
    #Value:  "00001"
    #Label:  "Title"
    #Value:  "Mr"
    #Label:  "Initials"
    #Value:  "XY"
    #Label:  "Forename"
    #Value:  "Mickey"
    #Label:  "Surname"
    #Value:  "Mouse"
    #Label:  "Siteabbrev"
    #Value:  "UK"
    #Label:  "Status"
    #Value:  "STAFF"
    #Label:  "BUabbrev"
    #Value:  "NOBU"
    #Label:  "Department"
    #Value:  "Finance"

    Note the commented bits at the bottom are the output of

    Write-Host "Value: " $Value

     and

    Write-Host "Label: " $Label

    Also, if the following are placed within the loop, I see all data items being returned, so I know that they are added to the hash table. If they are added outside the loop, I just get the final entry "Department"

    Write-Host "Keys:" $CurrentUserHashTable.Keys
    Write-Host "Values:" $CurrentUserHashTable.Values

    Many thanks,

    Jon

    Wednesday, April 30, 2014 12:24 PM

Answers

  • Take the $CurrentUserHashTable = @{} out of the foreach loop and replace the $CurrentUserHashTable = $Null with it.  The first is unecessary, and by initializing the hashtable in the loop it gets reset each loop, so you'd only have the last entry in it.

    I hope this post has helped!

    • Marked as answer by Jon Bryan Wednesday, April 30, 2014 8:59 PM
    Wednesday, April 30, 2014 6:49 PM

All replies

  • Take the $CurrentUserHashTable = @{} out of the foreach loop and replace the $CurrentUserHashTable = $Null with it.  The first is unecessary, and by initializing the hashtable in the loop it gets reset each loop, so you'd only have the last entry in it.

    I hope this post has helped!

    • Marked as answer by Jon Bryan Wednesday, April 30, 2014 8:59 PM
    Wednesday, April 30, 2014 6:49 PM
  • What is wrong with this:

    $ht=@{}
    ForEach ($Line in $InputFile){
          $data=$Line.Split('=')
          $ht.Add($data[0],$data[1])
    }

    Why not use ConvertFrom-StringData.


    ¯\_(ツ)_/¯

    Wednesday, April 30, 2014 7:42 PM
  • Rhys,

    Thanks that was so obvious, I couldn't see it!

    I knew the answer would be simple.

    Made the amendment to my script and can now get at the data in the hashtable, via (e.g.)

    $Department=$CurrentUserHashTable.'"Department"'

    Thanks again.

    Jon

    Wednesday, April 30, 2014 8:59 PM
  • jrv,

    I'm taking a more long winded approach, as I want to ensure that everything is wrapped in double quotes for feeding into another command The data is coming from an 'uncontrolled source' - there are regularly spaces and hyphens in the value data. I will be adding lots of error/format checking into the final script.

    Plus I think that it makes it more readable (stepwise) for my colleagues.

    Thanks,

    Jon

    Wednesday, April 30, 2014 9:06 PM
  • There is no need to do that at this stage.  If you need to output quoted values then there are other facilities we can use to do that.

    Please explain what your input looks like and the desired output requirement.  Noting with a computer should be this difficult or confused.


    ¯\_(ツ)_/¯

    Wednesday, April 30, 2014 10:01 PM
  • jrv,

    Thanks for the alternate suggestions. I have taken a look at both.

    ConvertFrom-StringData was something that I had not heard of before, I have done a little testing with it but don't get the desired result.

    Not to worry though, I have the desired output from my initial question now. I really need to get on with finalising the script now the I have the variables in a useable state.

    Thanks again,

    Jon

     

    Thursday, May 1, 2014 10:34 AM
  • Again you are making unreasonable assumptions.

    What is the inpout and desired output.

    We do not usually convert on load in programming or scripting.  Load native and save converted.  This is  long term computer automation pattern.  You re trying todo everything in onestep whch makes allof thismuchharder or nearly impossible.

    Load the data as is.  Once you can load it the rest is simple.  It will take only one line.  Do not modify the data when loading.  Just load it.  For name/value pairs use ConvertFrom to build anobject collection.

    This is PowerShell.  It is not Excel, Batch or VBScript.  It is an object system.  You are subverting all of its capabilities by trying use it like a batch or VBScript system.


    ¯\_(ツ)_/¯

    Thursday, May 1, 2014 11:23 AM