PSH Jobs ? wtf

Due to some hotline call, we need to check if some server doesn’t execute a particular process. We start using this powershell script :

PS > get-xaserver |? { $_.FolderPath -notlike '*INFRA*' -and -not (get-process -name iexplore -computername $_.ServerName -ErrorAction SilentlyContinue) } | select ServerName 
Server029
Server647
Server702

As we have more than 300 servers in this Citrix Farm, we try to find a better way to do this check, using the “oneliner sequential script” execution time as the time reference

PS > Measure-Command { get-xaserver |? { $_.FolderPath -notlike '*INFRA*' -and -not (get-process -name iexplore -computername $_.ServerName -ErrorAction SilentlyContinue) } | select ServerName }

Days              : 0
Hours             : 0
Minutes           : 1
Seconds           : 36
Milliseconds      : 4
Ticks             : 960048037
TotalDays         : 0,00111116670949074
TotalHours        : 0,0266680010277778
TotalMinutes      : 1,60008006166667
TotalSeconds      : 96,0048037
TotalMilliseconds : 96004,8037

1 minute 36 seconde to check more than 300 server, good result! Is there a way to parallelized it ?

Jobs

To Cope with jobs limitations, we dynamically generate the scriptblock when we create the job, and we limit the number of job to 20, as we don’t want to overwhelm the system.

PS >$return = @()
$script = "if( -not (get-process -name iexplore -computername MyComp -ErrorAction SilentlyContinue)){'MyComp'}"
get-xaserver |? { $_.FolderPath -notlike '*INFRA*'} |% {
	$cmd = [scriptblock]::create( $script.replace('MyComp',$_.Servername) )
	Start-Job -ScriptBlock  $cmd
	while( (get-job).Count -gt 20){
		$jobs = get-job -state completed
		if($jobs -ne $null -and $jobs.Count -ne 0 ){
			$return += (receive-job $jobs)
			remove-job $jobs
		}else{
			Start-sleep -s 10
		}
	}
}
$return += (get-job | wait-job | receive-Job)
get-job |remove-job -Force
$return
	
Server647
Server702
Server029


PS > Measure-Command {
$return = @()
$script = "if( -not (get-process -name iexplore -computername MyComp -ErrorAction SilentlyContinue)){'MyComp'}"
get-xaserver |? { $_.FolderPath -notlike '*INFRA*'} |% {
	$cmd = [scriptblock]::create( $script.replace('MyComp',$_.Servername) )
	Start-Job -ScriptBlock  $cmd
	while( (get-job).Count -gt 20){
		$jobs = get-job -state completed
		if($jobs -ne $null -and $jobs.Count -ne 0 ){
			$return += (receive-job $jobs)
			remove-job $jobs
		}else{
			Start-sleep -s 10
		}
	}
}
$return += (get-job | wait-job | receive Job)
get-job |remove-job -Force
$return
}		

Days              : 0
Hours             : 0
Minutes           : 8
Seconds           : 3
Milliseconds      : 224
Ticks             : 4832242340
TotalDays         : 0,0055928730787037
TotalHours        : 0,134228953888889
TotalMinutes      : 8,05373723333333
TotalSeconds      : 483,224234
TotalMilliseconds : 483224,234

Wow! Maybe the generation of the scriptblock take to much time, so we write another version of the script, passing the servername as an argument of the script block.

Measure-Command {
$return = @()
$script = {
	param($server)
	if( -not (get-process -name iexplore -computername $server -ErrorAction SilentlyContinue)){"$server"}
}
get-xaserver |? { $_.FolderPath -notlike '*INFRA*'} |% {

	Start-Job -ScriptBlock  $script -ArgumentList $_.ServerNAme
	while( (get-job).Count -gt 20){
		$jobs = get-job -state completed
		if($jobs -ne $null -and $jobs.Count -ne 0 ){
			$return += (receive-job $jobs)
			remove-job $jobs
		}else{
			Start-sleep -s 10
		}
	}
}
$return += (get-job | wait-job | receive Job)
get-job |remove-job -Force
$return
}

Days              : 0
Hours             : 0
Minutes           : 7
Seconds           : 36
Milliseconds      : 433
Ticks             : 4564330819
TotalDays         : 0,00528279029976852
TotalHours        : 0,126786967194444
TotalMinutes      : 7,60721803166667
TotalSeconds      : 456,4330819
TotalMilliseconds : 456433,0819

Not really better…. Is there an interest in using powershell jobs ?

Some says that this (the jobs management) had been improoved in newest powershell version…

#Server PS 2
PS> $psversiontable

Name                           Value
----                           -----
CLRVersion                     2.0.50727.4984
BuildVersion                   6.1.7600.16385
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           {1.0, 2.0}
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1


PS> measure-command { 1..10 |% { 10..10 |% { $_ } } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 3
Ticks             : 31579
TotalDays         : 3,65497685185185E-08
TotalHours        : 8,77194444444444E-07
TotalMinutes      : 5,26316666666667E-05
TotalSeconds      : 0,0031579
TotalMilliseconds : 3,1579


PS> measure-command { 1..10 |% { Start-Job -Scriptblock {10..10 |% { $_ } } | wait-job | remove-job } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 11
Milliseconds      : 904
Ticks             : 119046146
TotalDays         : 0,000137784891203704
TotalHours        : 0,00330683738888889
TotalMinutes      : 0,198410243333333
TotalSeconds      : 11,9046146
TotalMilliseconds : 11904,6146
#Server PSH 4
PS> $psversiontable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.18408
BuildVersion                   6.3.9600.16406
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2


PS> measure-command { 1..10 |% { 10..10 |% { $_ } } }


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 65
Ticks             : 653817
TotalDays         : 7,56732638888889E-07
TotalHours        : 1,81615833333333E-05
TotalMinutes      : 0,001089695
TotalSeconds      : 0,0653817
TotalMilliseconds : 65,3817



PS> measure-command { 1..10 |% { Start-Job -Scriptblock {10..10 |% { $_ } } | wait-job | remove-job }



Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 33
Milliseconds      : 204
Ticks             : 332047275
TotalDays         : 0,000384313975694444
TotalHours        : 0,00922353541666667
TotalMinutes      : 0,553412125
TotalSeconds      : 33,2047275
TotalMilliseconds : 33204,7275

Split-Pipeline

As an alternative, we can use Split-Pipeline (SplitPipeline ) who allows a fast, simple and reliable parallelization of our processes. (Thanks Marc! )

PS> $script= { process { if( -not (get-process -name iexplore -computername $_ -ErrorAction SilentlyContinue)){"$_"} } }
> Measure-Command {get-xaserver |? { $_.FolderPath -notlike '*INFRA*'} | Split-Pipeline -Count 20 -Script $script }


Days              : 0
Hours             : 0
Minutes           : 1
Seconds           : 9
Milliseconds      : 728
Ticks             : 697284084
TotalDays         : 0,000807041763888889
TotalHours        : 0,0193690023333333
TotalMinutes      : 1,16214014
TotalSeconds      : 69,7284084
TotalMilliseconds : 69728,4084

Leave a Reply

Your email address will not be published. Required fields are marked *