It is a new year and the Chairman is preparing a fiendish new challenge for this year’s PowerShell + DevOps Summit. That time is rapidly. If you partook in last year’s battle then you understand what is expected of you. if you have not already done so align yourself with the faction that best suits you.
In order to prepare you for battle the Chairman has prepared a series of preparatory challenges. It is a foolish warrior who goes into battle unprepared. Just sayin’.
To prepare you for the upcoming battle, see what you can create according to the guiding principles of your faction that solves the following problem. The bottom line is that your solution should work.
The Challenge
The Get-Counter cmdlet is very useful in obtaining performance counter information. Unfortunately, the Chairman feels the output is less than friendly. Especially if you wish to consume the output such as with additional filtering, exporting to a json file or writing to a database.
Your challenge is to create a PowerShell function that takes the output from Get-Counter and transforms it into a more user friendly object. Each counter sample should be a separate object with these properties:
- Timestamp
- Computername
- CounterSet
- Counter
- Value
You are free to use whatever property names you want as long as it is clear what the values represent. A sample might look like this:
PS C:\> Get-Counter -computername server01 | MyFunction
Datetime : 2/6/2019 1:34:30 PM
Computername: SERVER01
Counterset : memory
Counter : cache faults/sec
Value : 0
Datetime : 2/6/2019 1:34:30 PM
Computername: SERVER01
Counterset : physicaldisk(_total)
Counter : % disk time
Value : 5.63389896275325
Advanced Challenge
If you want to really challenge yourself, define a custom type and format view that gives you a result like this:
PS C:\> get-counter -computername server01 | myfunction
Timestamp: 2/6/2019 4:51:34 PM
Computername Counterset Counter Value
------------ ---------- ------- -----
SERVER01 network interface(intel[r] ethernet connection [2] i219-lm) bytes total/sec 63.933330323139
SERVER01 processor(_total) % processor time 2.29286092227079
SERVER01 memory % committed bytes in use 58.2262708009747
SERVER01 memory cache faults/sec 9.98958286299047
SERVER01 physicaldisk(_total) % disk time 0.06629201377444
SERVER01 physicaldisk(_total) current disk queue length 0
All the information you need to know is included in this post. The Chairman will share a possible solution within the week. Good Luck and Good Scripting!
I took a shot at this and here’s what I came up with. The function allows you to specify -tableView $true or $false, and the results will display accordingly as specified by the challenge criteria. If you do not declare -tableView when calling the function, it will default to false and display the list.
function Parse-CounterData($input, [bool]$tableView)
{
$objectArray = @()
$functionData = $input.CounterSamples | Select Path, CookedValue, Timestamp
$functionData | Foreach-Object {
$varPath = $_.Path
$pathObjects = $varPath.Split(‘\’)
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name ComputerName -Value $pathObjects[2]
$object | Add-Member -MemberType NoteProperty -Name CounterSet -Value $pathObjects[3]
$object | Add-Member -MemberType NoteProperty -Name Counter -Value $pathObjects[4]
$object | Add-Member -MemberType NoteProperty -Name Value -Value $_.CookedValue
If ($tableView -ne $true)
{
Return $object
}
else
{
$objectArray += $object
$timestamp = “Timestamp: ” + $_.Timestamp
}
}
If ($tableView -eq $true)
{
Return $timestamp, $objectArray | Format-Table
}
}
Get-Counter | Parse-CounterData -tableView $true
Working nice 🙂 We want more 🙂
Here’s my attempt 🙂
https://github.com/ScriptKiddy99/IronScripter2019-CounterView
Who needs a function
Get-Counter|foreach-object{
$Timestamp = $_ |Select-object -expandproperty Timestamp
$_.CounterSamples | Where-object {$_.path -match “\\\\(.*)\\(.*)\((.*)\)\\(.*)”} | foreach-object{
$_|Select-object @{l=’Timestamp’;e={$Timestamp}},
@{l=’Computername’;e={$matches[1]}},
@{l=’Counterset’;e={$matches[2]}},
@{l=’Instance’;e={$matches[3]}},
@{l=’Counter’;e={$matches[4]}},
@{l=’Value’;e={$_.CookedValue}}
}}|format-table
to simple for a function really
Except that is a lot to type each time you want to run a Get-Counter command. The whole point of a function is ease of use and re-usability.
function MyFunction {
param(
[parameter(Mandatory, ValueFromPipeline)] [object] $InputObject
)
$InputObject.CounterSamples | ForEach-Object {
[void] ($_.Path -match ‘\\\\(?.+?)\\(?.+?)\\(?.+)’)
$_ | Select-Object -Property @{n=’Datetime’; e={$_.Timestamp}},
@{n=’Computername’; e={$matches.Computername}},
@{n=’Counterset’; e={$matches.Counterset}},
@{n=’Counter’; e={$matches.Counter}},
@{n=’Value’; e={$_.CookedValue}}
}
}