Xao
Xao

Reputation: 601

Powershell list of dictionaries or hashtable

I want to create a list of dictionaries, in order for me to export it to CSV. As you may know in PowerShell if you want to export an array filled with strings to CSV file, it won't work, so I have to create objects for this.

But the way I'm doing it if evasive, and I don't feel it's the correct way of creating a list of dictionaries/hashtable, nevertheless I didn't create a function for repeated code (sorry for this).

#add the log file.
$savegrp = Get-Content "J:\savegrp.dec.2015.log"
#filtering into a var just Succeeded/Failed data then replace  space with ';' and remove ','
$succeded = ($savegrp -cmatch "Succeeded:") -replace "\s+",";" -replace ",",""
$failed = ($savegrp -cmatch " Failed: ") -replace "\s+",";" -replace ",",""

#creating container where all data will be added
$container = @()
#just a date to save the csv file if this script will be scheduled 
$date =  Get-Date -format dd.MMMM.yyyy

#take each line of data with 'Succeeded' match and iterate it
for($i=0;$i -le ($succeded.count-1);$i++) {

    #split each line by ';' to see how many items are per one line
    $s1 = ($succeded[$i]).split(";")

    #if in one 'Succeeded' line are just 6 element then is just one server which is ok
    if ($s1.count -eq 6){

        $PropertyHash = @{}
        $PropertyHash =  @{
            "Date" = $s1[1] + " " + $s1[0]
            "Time" = $s1[2]
            "Client" = $s1[5]
            "Status" = $s1[4].Substring(0,9)
        }
        $container += New-Object -TypeName PSObject -Property $PropertyHash
    }
    #if in one 'Succeeded' line are more servers, then stick all sererers to the same info in the line
    else{
        $count = ($s1.count)

        for($a = $count-1;$a -ge 5){

            $PropertyHash = @{}
            $PropertyHash +=  @{
                "Date" = $s1[1] + " " + $s1[0]
                "Time" = $s1[2]
                "Client" = $s1[$a]
                "Status" = $s1[4].Substring(0,9)
            }
            $container += New-Object -TypeName PSObject -Property $PropertyHash
            $a--
        }
    }
}

Upvotes: 1

Views: 4419

Answers (1)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200373

Something like this should work just fine, provided you have PowerShell v3 or newer:

for ($i = 0; $i -lt $succeded.Count; $i++) {
  $date1, $date2, $time, $null, $status, $clients = $succeded[$i].Split(';')
  $clients | ForEach-Object {
    New-Object -Type PSObject -Property @{
      'Date'   = "$date2 $date1"
      'Time'   = $time
      'Client' = $_
      'Status' = $status.Substring(0,9)
    }
  } | Export-Csv 'C:\path\to\output.csv' -NoType -Append
}

PowerShell allows you to assign arrays to a list of variables, each of which takes a single element from the array, except for the last one, which takes all the remaining array elements. The statement

$date1, $date2, $time, $null, $status, $clients = $succeded[$i].Split(';')

collects date, time and status in the respective variables $date1, $date2, $time and $status. The 4th value is discarded by assigning it to $null. The rest of the array resulting from the split operation (the list of clients) is assigned to the "catch-all" variable $clients. Then you can pipe that variable into a ForEach-Object statement where you create one object for each client and append them to your CSV file (note that you need at least PowerShell v3 to be able to append to a CSV).

Edit: If you're stuck with PowerShell v2 or earlier you could also do the export outside the loop. However, for that to work you need to either run it in a subexpression:

(for ($i = 0; $i -lt $succeded.Count; $i++) {
  $date1, $date2, $time, $null, $status, $clients = $succeded[$i].Split(';')
  $clients | ForEach-Object {
    New-Object -Type PSObject -Property @{
      'Date'   = "$date2 $date1"
      'Time'   = $time
      'Client' = $_
      'Status' = $status.Substring(0,9)
    }
  }
}) | Export-Csv 'C:\path\to\output.csv' -NoType

or collect the results in a variable first:

$container = for ($i = 0; $i -lt $succeded.Count; $i++) {
  $date1, $date2, $time, $null, $status, $clients = $succeded[$i].Split(';')
  $clients | ForEach-Object {
    New-Object -Type PSObject -Property @{
      'Date'   = "$date2 $date1"
      'Time'   = $time
      'Client' = $_
      'Status' = $status.Substring(0,9)
    }
  }
}

$container | Export-Csv 'C:\path\to\output.csv' -NoType

Upvotes: 3

Related Questions