Automatic Deployment Rules (ADR) sind bei der Verteilung von Updates hilfreich, da sie automatisiert für jeden Monat (oder häufiger) neue Software Update Gruppen anlegen können, die nur die benötigten Updates beinhalten und somit die Gruppengrößen klein halten. Eine entsprechende Strategie habe ich bereits 2014 beschrieben. Kommt aber ein Client nach längerer Zeit wieder ans Netz, dann fehlen u.U. in den aktuellen Gruppen notwendige Updates, die erst bei der nächsten automatischen Regelabarbeitung wieder heruntergeladen werden müssen.
Auch im Bereich des OS Deployments können Updates fehlen. Ebenso ist ein Reporting mit vielen einzelnen Gruppen nur schwer zu realisieren.
Daher wird immer empfohlen zusätzlich Baselines zu pflegen, die alle in der Umgebung notwendigen Updates beinhalten.
Auch dafür kann man ADR nutzen:
- eine Baseline pro Produkt (Windows 10, Office 2013, …)
- Beinhaltet alle kritischen und Sicherheitsupdates inkl. Service Packs und Update Rollups
- Beinhaltet nur nicht ersetzte Updates (superseded)
- Keine Einschränkung auf “required”
- Baseline füllt immer die gleiche Software Update Gruppe
Das Ziel der Baseline sollte eine leere Collection sein, da eine ADR immer erzwungen sein muss und die Deadline maximal zwölf Monate in der Zukunft liegen kann. Trotzdem kann man die Update Gruppe zusätzlich an ein OSD Collection oder andere Ziele mit individuellen Installationszeitpunkten verteilen.
Diese ADR erzeugt somit eine Gruppe mit allen für das Produkt relevanten Updates – unabhängig davon, ob sie gerade in der Umgebung benötigt werden.
Um die Einrichtung dieser ADRs zu vereinfachen, habe ich ein kleines Powershell Script geschrieben:
$siteServer='cm01' #name of the configuration manager server $site='MBK' #site name $DeploymentPackageName="Microsoft Updates" #name of the update package to store the updates $products="Windows Server 2012 R2","Windows 10","Office 2013","Windows 7" #array of products to create baseline ADRs $rootFolder='_Software Updates' #Name of the Folder to move the new collections for the baselines $sourcePath='{1}\\{0}\ConfigMgr\Content\Updates' -f $siteServer,'Microsoft.PowerShell.Core\FileSystem::' $DeploymentPackageLocation='{0}\{1}' -f $sourcePath,$deploymentpackagename $namespace='root\SMS\Site_'+$site function initialize{ [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$Site, [Parameter(Mandatory=$true)] [string]$Siteserver ) #Load the ConfigurationManager Module #from http://www.dexterposh.com/2014/06/powershell-sccm-2012-getting-started.html if ((get-module ConfigurationManager) -eq $null) { try { $ConfigMgrModule = "$($env:SMS_ADMIN_UI_PATH | Split-Path -Parent)\ConfigurationManager.psd1" if (!(Test-Path -Path $ConfigMgrModule)) { throw 'Configuration Manager module not found in admin console path' } write-host 'Loading ConfigMgr Module from ' $ConfigMgrModule Import-Module "$ConfigMgrModule" #Get-Module $BeforeLocation = (Get-Location).Path } catch { Write-Error $_.Exception.Message } } $PSDefaultParameterValues =@{"Get-wmiobject:namespace"=("Root\SMS\site_"+$site);"Get-WMIObject:computername"=$siteServer} Set-Location $site":" } function create-DeploymentPackage{ [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$DeploymentPackageName, [Parameter(Mandatory=$true)] [string]$DeploymentPackageLocation ) #existiert swupk schon? $rt=Get-CMSoftwareUpdateDeploymentPackage -Name $DeploymentPackageName if ($rt -eq $null) { #existiert zielpfad schon? if (-not (Test-Path $DeploymentPackageLocation)) { #anlegen write-host $DeploymentPackageLocation new-item -itemtype directory -path $DeploymentPackageLocation } #sudp anlegen New-CMSoftwareUpdateDeploymentPackage -Name $DeploymentPackageName -Path $DeploymentPackageLocation $rt=Get-CMSoftwareUpdateDeploymentPackage -Name $DeploymentPackageName } return $rt } function create-AutomaticDeploymentRule{ [CmdletBinding()] param( [Parameter(Mandatory=$true)] $sudp, [Parameter(Mandatory=$true)] [string]$collectionName, [Parameter(Mandatory=$true)] [string]$ADPName, [Parameter(Mandatory=$true)] [string]$Product ) $rt=get-CMSoftwareUpdateAutoDeploymentRule -Name $adpname if ($rt -eq $null) { $ADPHash = @{ AddToExistingSoftwareUpdateGroup = $true #Indicates whether the rule adds to an existing update group. If this value is $True, each time the rule runs and finds new updates, it adds them to an existing update group. AllowRestart = $false AllowSoftwareInstallationOutsideMaintenanceWindow =$false AllowUseMeteredNetwork = $false AvailableImmediately =$true #AvailableTime =12 #AvailableTimeUnit = "Month" CollectionName = $collectionName DeadlineImmediately =$false DeadlineTime =12 DeadlineTimeUnit ="Month" DeploymentPackageName =$sudp.name DeployWithoutLicense =$false DownloadFromInternet =$true DownloadFromMicrosoftUpdate =$true EnabledAfterCreate =$true MicrosoftAsVendor=$true Name=$ADPName Product=$product RunType = "RunTheRuleAfterAnySoftwareUpdatePointSynchronization" Superseded=$false SuppressRestartServer=$true SuppressRestartWorkstation=$true UpdateClassification="Critical Updates","Security Updates","Service Packs","Update Rollups","Updates" UseBranchCache=$true UserNotification="DisplayAll" #"HideAll" } New-CMSoftwareUpdateAutoDeploymentRule @ADPHash $rt=get-CMSoftwareUpdateAutoDeploymentRule -Name $adpname } return $rt } function create-basecollection{ [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$rootfolder, [Parameter(Mandatory=$true)] [string]$collectionName, [Parameter(Mandatory=$true)] [string]$site ) $folder=Get-CimInstance -ClassName SMS_ObjectContainerNode -Filter "ObjectType=5000 and ParentContainerNodeid=0 and Name='$rootFolder'" -Namespace $namespace if (-not $folder) { $rt=New-CimInstance -ClassName SMS_ObjectContainerNode -Property @{Name=$rootFolder;ObjectType=5000;ParentContainerNodeid=0;SourceSite=$site} -Namespace $namespace $folder=Get-CimInstance -ClassName SMS_ObjectContainerNode -Filter "ObjectType=5000 and ParentContainerNodeid=0 and Name='$rootFolder'" -Namespace $namespace } $collection=Get-CMDeviceCollection -Name $collectionName if (-not $collection) { $collection=New-CMDeviceCollection -Name $collectionName -Comment ('Software Update Baseline Target') -LimitingCollectionName 'All Systems' } Move-CMObject -FolderPath ($site+':\DeviceCollection\'+$rootFolder) -InputObject $collection return $collection } function main { initialize -site $site -siteserver $siteserver $sudp=create-deploymentpackage -DeploymentPackageName $DeploymentPackageName -DeploymentPackageLocation $DeploymentPackageLocation $products | ForEach-Object { $product=$_ $pname='Microsoft {0} Baseline' -f $product $col=create-basecollection -rootfolder $rootFolder -site $site -collectionName $pname $adp=create-AutomaticDeploymentRule -sudp $sudp -collectionName $col.name -ADPName $pname -Product $product } } main