Fun!
Today was a happy day. One of my co-workers asked me if I can help him with a little PowerShell.
I never say ‘no’ to this.
The Story
So, what’s the story? He needed to get some performance counters from a bunch of remote servers. Those are in different domain so Get-Counter won’t work – no Credential parameter. He wrapped it up in Invoke-Command, but then got some errors. Basically this was the ‘problematic’ part:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
foreach ($server in $ServerList) { | |
#Generate all variables | |
$resultCounters = Invoke-Command –ComputerName $server –Credential $Credential –ScriptBlock { | |
param( | |
$MetricList | |
) | |
Get-Counter –Counter $MetricList –SampleInterval 10 –MaxSamples 10 | |
} –ArgumentList $MetricList | |
$resultCounters | Export-Counter –Path $path –FileFormat $fileFormat | |
#… | |
} |
He wanted to generate counters on the endpoint, get the results through Invoke-Command and export them locally on his machine to further investigate. This is what he got:
The issue here is, that data returned through Invoke-Command is deserialized, which is not the original ‘object’:
So, I came up with a little bit different idea:
- Create several PowerShell Sessions to destination computers (based on xml input)
- Create an array of hashtables defining which counters are processed by which computer (different roles like SQL, IIS etc)
-
Use Invoke-Command to:
- Generate destination file name based on computer name, date and other needed parameters
- Get Counters and export them on the machine directly
- Return object with computer name and destination file location
- Then, once the Invoke finishes, use foreach on processed computers to copy those files to his local machine using Copy-Item -FromSession (luckily, we’re working on Windows 10/2016 machines here)
- And finally clean up all PowerShellSessions created.
This is (nearly) the code we’ve end up:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ComputerPSSession = New-PSSession -ComputerName $ServerList.servers.server.name -Credential $Credential | |
$params =@( | |
@{ | |
ComputerName = 'ComputerName1' | |
Counter = $MetricList | |
SampleInterval = 3 | |
MaxSamples = 3 | |
}, | |
@{ | |
ComputerName = 'ComptuerName2' | |
Counter = $MetricList1 | |
SampleInterval = 3 | |
MaxSamples = 3 | |
} | |
) | |
$processedComputers = invoke-command -Session $ComputerPSSession -ScriptBlock { | |
$fileName = '{0}_{1}_{2}.{3}' -f $USING:currentDate, $env:computername , $USING:profile, $USING:perfmonsOutputFileFormat | |
$destinationFileName = Join-Path -Path $env:temp -ChildPath $fileName | |
$currentParam = $USING:params | where-object {$PSItem.ComputerName -eq $env:computerName} | |
Get-Counter $currentParam | Export-Counter -Path $destinationFileName -FileFormat $USING:perfmonsOutputFileFormat | |
[pscustomobject]@{ | |
FilePath = $destinationFileName | |
ComputerName = $env:ComputerName | |
} | |
} | |
foreach ($Computer in $processedComputers) { | |
$currentSession = $ComputerPSSession | Where-Object {$PSItem.ComputerName -eq $Computer.PSComputerName} | |
Copy-Item -FromSession $currentSession -Path $Computer.FilePath -Destination .\ | |
} | |
if($ComputerPSSession) { $ComputerPSSession | Remove-PSSession } |