Function Skeleton for Invoke-Command –AsJob
PSRemoting jobs are quite amazing. While they are a little complicated to grasp at first, they’re quite powerful. However, with great power usually comes great responsibility. We know we can spawn a gazillion jobs, but how about managing them? How many do we have to do? What did they return, etc.
Here’s a skeleton function that does nothing more than return two [Datetime] objects separated by 10 seconds.
function Get-PsRemotingJobsExample
{
param (
[Parameter(ValueFromPipeLine=$true)][String[]]$ComputerName = @($env:ComputerName),
[int]$TimeoutInterval = 60,
[int]$JobPollingInterval = 5,
[int]$ThrottleLimit = 100,
[switch]$ShowRunspaceID
)
begin
{
$scriptBlock = {
Get-Date; Start-Sleep -Seconds 10; Get-Date;
} # $scriptblock
$jobs = New-Object System.Collections.ArrayList;
} # begin
process
{
foreach ($computer in $ComputerName)
{
if (($Computer -match "^$env:ComputerName\.") -or ($Computer -match "^$env:ComputerName$"))
{
$jobs.Add((Start-Job -ScriptBlock $scriptblock -ArgumentList $arguments)) | Out-Null;
} # if (($Computer -match "^$env:ComputerName\.") -or ($Computer -match "^$env:ComputerName$"))
else
{
$jobs.Add((Invoke-Command -AsJob -ScriptBlock $scriptblock -ArgumentList $arguments -ComputerName $computer -ThrottleLimit $ThrottleLimit )) | Out-Null;
} # if (($Computer -match "^$env:ComputerName\.") -or ($Computer -match "^$env:ComputerName$")) ... else
} # foreach ($computer in $ComputerName)
} # process
end
{
$initialCount = $jobs.Count;
$notAfter = (Get-Date) + (New-TimeSpan -Seconds $TimeoutInterval);
while ($jobs)
{
$now = Get-Date;
if ($now -gt $notAfter) { break; }
Write-Progress $now "$($jobs.Count)/$initialCount jobs and $([int]($notAfter - $now).TotalSeconds) seconds to go.";
Get-Job -Id ($jobs | % { $_.Id }) |
? { $_.State -ne 'Running' } |
% {
if ($_.State -eq 'Completed')
{
if ($data = (Receive-Job -Id $_.Id))
{
if ($ShowRunspaceID)
{
$data;
} # if ($ShowRunspaceID)
else
{
$properties = $data | Get-Member -MemberType *Propert* |
% {
if ($_.name -ne 'RunspaceId')
{
$_.name;
} # if ($_.name -ne 'RunspaceId')
} # $properties = $data | Get-Member -MemberType *Propert* |
$data | Select-Object -Property $properties;
} # if ($ShowRunspaceID) ... else
} # if ($data = (Receive-Job -Id $_.Id))
else
{
Write-Warning "No data-received from job at $($_.Location)";
} # if ($data = (Receive-Job -Id $_.Id)) ... else
Remove-Job -id $_.Id;
} # if ($_.State -eq 'Completed')
else
{
Write-Warning "JobId $($_.Id) failed. Please investigate.";
} # if ($_.State -eq 'Completed') ... else
$jobs.Remove($_) | Out-Null;
} # Get-Job -Id ($jobs | % { $_.Id }) | ? { $_.State -ne 'Running' }
if ($jobs) { start-sleep $JobPollingInterval; }
} # while ($jobs)
} # end
} # function Get-PsRemotingJobsExample
Comments
- Anonymous
May 20, 2014
Updated to mask out RunspaceID property by default, and to add -ThrottleLimit = 100