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