Statements below are executed in Windows PowerShell 5.1
I have a script that executes several runs, during which it creates files and measures the time it takes. The results are stored in an array of PSCustomObject
.
Here's a sample of the data:
> $ResultsCreate | Select-Object -First 10 | ft
Run Folder File Size Create
--- ------ ---- ---- ------
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_1.bin 304087,04 00:00:00.1377073
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_2.bin 608174,08 00:00:00.0776793
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_3.bin 524288 00:00:00.0780064
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_4.bin 922746,88 00:00:00.0759425
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_5.bin 503316,48 00:00:00.0842039
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_6.bin 178257,92 00:00:00.0610860
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_7.bin 1038090,24 00:00:00.0916000
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_8.bin 660602,88 00:00:00.0782461
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_9.bin 293601,28 00:00:00.0612056
1 \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv \\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_10.bin 744488,96 00:00:00.0758247
Here's how the PSCustomObject
is defined:
> $ResultsCreate | Get-Member
TypeName: Selected.System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Create NoteProperty timespan Create=00:00:00.1377073
File NoteProperty string File=\\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv\file_1_1.bin
Folder NoteProperty string Folder=\\opidt660-vxzv\PB-VW_NKB$\Lmneom\vxzv
Run NoteProperty int Run=1
Size NoteProperty double Size=304087,04
What I'd like to do is get aggregates (average, min, max) for the files in each run. Seems easy enough, but for some reason I cannot get Measure-Object
to do what I want.
Here's my attempt to group the array $ResultsCreate
by Run
and then calculate the average. I end up with an empty $stat
hashtable (the keys are there, the values are empty).
> $($ResultsCreate |
Group-Object -Property Run -AsHashTable).GetEnumerator() |
ForEach-Object -Begin {$stat = @{}} -Process { $stat[$_.Key] = $(Measure-Object -Property $_.Value.Duration -Average) }
> $stat
Name Value
---- -----
2
1
Even a simple example (ignoring Run
completely) fails miserably.
> $ResultsCreate | Measure-Object -Property $_.Create.TotalSeconds
Measure-Object : Cannot validate argument on parameter 'Property'. The argument is null or empty. Provide an argument that is not null or empty, and th
en try the command again.
At line:1 char:44
$ResultsCreate | Measure-Object -Property $_.Create.TotalSeconds
~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidData: (:) [Measure-Object], ParameterBindingValidationException
FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.MeasureObjectCommand
I have no clue what's wrong, and it's driving me up the wall. Any help, hints and/or tips would be greatly appreciated!
UPDATE: Finally found a way to make this work. In short, it seems that Measure-Object
cannot access the TotalSeconds
property directly.
> $($ResultsCreate |
select-object -Property *,@{ Name = 'TotalSeconds'; Expression = { $_.Create.TotalSeconds }} |
Group-Object -Property Run -AsHashTable).GetEnumerator() |
ForEach-Object -Begin {$stat = @{}} -Process { $stat[$_.Key] = $_.Value | Measure-Object -Property TotalSeconds -Average }
> $stat
Name Value
---- -----
2 Microsoft.PowerShell.Commands.GenericMeasureInfo
1 Microsoft.PowerShell.Commands.GenericMeasureInfo
Apparently prior to PS 6, hashtables are a bit of an issue:
Beginning in PowerShell 6,
Measure-Object
supports measurement of hashtable input.
CodePudding user response:
Here's how I managed to solve the issue:
$($ResultsCreate |
Select-Object -Property *,@{ Name = 'TotalSeconds'; Expression = { $_.Create.TotalSeconds }} |
Group-Object -Property Run -AsHashTable).GetEnumerator() |
ForEach-Object `
-Begin {$Stats = @()} `
-Process { $Stats = $_.Value |
Measure-Object -Property TotalSeconds -Maximum -Minimum -Average |
Select-Object -Property Count, Average, Maximum, Minimum |
Add-Member -Name 'Run' -Type NoteProperty -Value $_.Key -PassThru }
The end result is this:
> $Stats | ft
Count Average Maximum Minimum Run
----- ------- ------- ------- ---
100 0,082614501 0,1272803 0,0574419 2
100 0,076335947 0,1377073 0,0597995 1
CodePudding user response:
Currently the Measure-Object doesn't support the TimeSpan
structure.
See: #10712
Measure-Object should support TimeSpan.
But you might do this to get e.g. the average timespan of the Run
groups:
$ResultsCreate |Group-Object Run |Select-Object Name,
@{ Name = 'Average'; Expression =
{ [TimeSpan][int]($_.Group.Create.Ticks |Measure-Object -Average).Average }
}