Serge Chegorian's System Center Blog

Serge Chegorian's System Center Blog

[SCCM]: Limitation of use of the Orchestration groups

October 15th, 2020

Starting SCCM build 2002 Microsoft have introduced a new feature called Orchestration groups. You can find information about Orchestration groups here:

The principal of Orchestration groups work is: you arrange several machines in a cluster, set an order and during the maintenance window SCCM deploys software updates in a pre-set order. There is also a possibility to run pre- and post-execution PowerShell script on each member.

However what Microsoft have overlooked is that if you are using Windows Defender as your primary Antivirus solution and distribute updates using ADR, Orchestration group would also consider Windows Defender updates as Windows Updates and because Windows Defender updates ADR is set to override the maintenance window, the next Windows Defender update will trigger Orchestration group in the following fashion:

  1. Windows Defender update triggers Orchestration group on Node 1 or Set 1.
  2. Orchestration group executes pre-deployment script on Node 1 or Set 1.
  3. Windows Defender update is deployed.
  4. There is no maintenance window so security updates are not deployed.
  5. Orchestration group timeout has expired and the group goes to ‘Failed’ state.

This issue is repeatable and was reported to Microsoft.

[PS]: Running parallel processes in PowerShell

October 15th, 2020

Many of you were in the situation when you have to run the same routine against multiple end points. If you run them in sequence, the process might take very long time depending on the routine complexity and the network performance. The wiser solution is to run all routines in parallel and than to collate data. The following cmdlets will help you:


So what each of them does?

Start-Job -ScriptBlock $scriptBlock -ArgumentList($ArgumentList)

Start-Job has two main parameters: ScriptBlock and ArgumentList. ScriptBlock is the main piece of code of your routine. This is what will be executed independently using ArgumentList as a parameter.

Get-Job gets the list of active jobs created by Start-Job and their status which could be ‘running’, ‘completed’ or ‘failed’.

Receive-Job uses Job ID as a parameter and gets all output from the $job created by Start-Job. This is important because Receive-Job simply returns the content of $job buffer. Whatever you put there using Write-Host, return or any other function will be returned as unindexed block of data.

Remove-Job uses $job handler or $job ID as a parameter and deletes the job. Remember that the job is not deleted automatically once it is completed and job results are sitting in the buffer until the job is deleted by Remove-Job cmdlet.

So the structure of your script should be as follows:

#Script Block
$scriptBlock = {
param ($MyParam)
function MyFunction
            return $Return
            MyFunction -MyParam $MyParam
#Starting jobs with variable parameter
for ($k=0;$k -lt $Something; $k++){
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList(MyParam)
# Checking jobs status. If at least one is running waiting for 10 seconds and checking again
While (Get-Job -State "Running") { 
foreach($job in Get-Job) {
if ([string]$job.JobStateInfo -eq "Completed") {$iCompleted++}
if ([string]$job.JobStateInfo -eq "Running") {$iRunning++}
if ([string]$job.JobStateInfo -eq "Failed") {$iFailed++}
Write-Host "Total jobs: $iTotalJobs, $iRunning jobs are running... Completed:
$iCompleted, failed: $iFailed"
Start-Sleep 10 
#All jobs have fiinished. Adding job results to the array and deleting the job
$AllJobResults= @()
foreach($job in Get-Job){
$AllJobResults += Receive-Job -Job $job 
Remove-Job -Job $job 

One more bit. As I have mentioned Receive-Job returns unindexed results. What I have found practical is to return data in a form of generic PowerShell object. This will allow you later to sort your data and display them in a form of the table:

$objReturn = New-Object -Type PSObject -Property @{
  'DataFiled1' = $Data1
  'DataFiled2' = $Data2
  'DataFiledN' = $DataN
$AllJobResults | Sort-Object -Property Data1,Data2 |Format-Table -property Data1,Data2,DataN

Serge Chegorian's System Center Blog

Serge Chegorian's System Center Blog