I’m going to continue writing about PowerShell because it’s fun to talk about and fun to use.
Today I decided to try and analyze some data in text files using a PowerShell script. The files were simulations of a betting strategy in a coin-toss scenario. The first line represented the final balance and every line thereafter represented the balance after a bet was completed. I was interested in the average balance over time and the average minimum balance for all files. The script itself was pretty uninteresting until I got to the output:
$files = get-childitem *.txt $sum = 0 $count = 0 $minSum = 0 foreach ($file in $files) { Write-Verbose "Processing file: $file" $sum += [long](get-content $file -totalCount 1) $count += 1 $values = get-content $file $minimum = 0 foreach ($line in $values) { $value = [int]$line $minimum = [Math]::Min($value, $minimum) } $minSum += $minimum } $average = $sum / $count $averageMinimum = $minSum / $count
Now is when it gets fun. I originally just wrote the output using write-output:
write-output "Average: $average" write-output "MinAverage: $minAverage"
This didn’t seem very PowerShell-like. I wanted to output an object that could be used by other scripts (for the heck of it at least.) I knew how to do this from a cmdlet, but had to search to find how to do it from a script. There seems to be two ways to make objects or object-like things to write.
Associative Arrays
Perl hackers love their hashes, and with good reason: this little data structure is very powerful. In the .NET world, we call them "dictionaries" for some reason. PowerShell associative arrays are declared with this syntax:
$array = @{name = value; name2 = value2}
If I wrote one of these using write-object, I got a nice list format with headers and could access the individual values via property syntax. Joy! Still, this isn’t really what I was looking for because I was really fishing for a way to output a PSObject.
PSObjects
You can create a PSObject using New-Object, but at first I couldn’t figure out how to let this object know it should have the properties I wanted. This is something you can use Add-Member for. You have to specify the type of member you are adding, and I believe the valid member types are listed in the PSMemberTypes enumeration. In this case, I needed NoteProperty since there’s no base object:
$output = New-Object PSObject $output | add-member NoteProperty -name Count -value $count $output | add-member NoteProperty -name Average -value $average $output | add-member NoteProperty -name AverageMinimum -value $averageMinimum write-output $output