Software Update Baselines

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
This entry was posted in Configuration Manager, Deutsch, System Center, System Center 2012 and tagged , , , , , , . Bookmark the permalink.

Leave a Reply