Automating the System Center Configuration Manager 2012 client

When working with the Server Core installation of Windows Server, most GUI applications does not work. This is expected for the most GUI applications, since dependencies for those GUIs is not present on Server Core. One such example is Software Center, which is part of the System Center 2012 Configuration Manager client.

When trying to launch Software Center (C:\Windows\CCM\SCClient.exe) on Server Core you  might get an error such as “SCClient has stopped working”:

image

For the most part you wont have the need to launch the Software Center on a Server Core installation of Windows Server. I recently worked with software updates on Windows Server 2008 R2 Hyper-V with Server Core. Although the WSUS integration in System Center Virtual Machine Manager might be a better option for working with Windows Updates on Hyper-V, System Center Configuration Manager 2012 was used in this particular scenario. As Hyper-V servers need to be in maintenance mode before maintenance work such as Windows patching, triggering the installation of new software updates in the SCCM Client needed to be performed manually in the scenario I worked with.

The first thing I tried was the UDA.CCMUpdatesDeployment COM object, which Boe Prox has written an excellent article about. However, this COM object is part of the System Center Configuration Manager 2007 client, and not available in the System Center Configuration Manager 2012 client.

It turns out there is a new WMI namespace in System Center Configuration Manager 2012, the ROOT\ccm\ClientSDK, which provides similar capabilities. If you have not worked a lot with WMI before, exploring this namespace might be a challenge. There is a project on CodePlex to make this a bit easier, the Client Center for Configuration Manager project:

image

This is a WPF GUI application for working with the ROOT\ccm\ClientSDK remotely, using WinRM. A nice feature of the GUI, is that the underlying PowerShell commands is shown at the bottom:

image

When clicking on “Missing Updates”, the PowerShell command actually running on the remote computer is Get-WmiObject -Query “SELECT * FROM CCM_SoftwareUpdate” -Namespace “ROOT\ccm\ClientSDK”.

When you click Install all, you will see that the InstallUpdates method is used to trigger installation of missing updates:

image

Based on this information, we can create PowerShell functions to make it easier to work with these commands. This is a few basic examples:

These functions can be used on computers with the System Center Configuration Manager 2012 client installed:

image

Ideas for further work:

  • Use the CIM cmdlets available in PowerShell 3.0 and above to create functions that will work with either DCOM (legacy WMI) or WSMan (PowerShell Remoting). You can find excellent examples in some of the 2013 Scripting Games entries. One example is the Get-SystemInventory function from Event 2.
  • Use PowerShell or the Configuration Manager Trace Log Tool to track installation status from SCCM log files such as C:\Windows\CCM\Logs\WUAHandler.log:

image

  • Use the Get-PendingReboot function to track whether a reboot is required after installing updates:

image

Generate an installation-report for specific hotfixes using Windows PowerShell

Windows PowerShell 2.0 contains a cmdlet called Get-HotFix, which retrieves installed hotfixes from the local computer or specified remote computers.

This is quite useful when you need to check if a particular hotfix is installed prior to installing new software that requires a specific set of hotfixes, or when a critical security hotfix is released and you want to make sure the hotfix is installed.

The Get-HotFix cmdlet retrieves all hotfixes installed by Component-Based Servicing. If you would like to know more about CBS, I would recommend the article Understanding Component-Based Servicing on the Windows Server Performance Teams blog.

When you need to check several computers, and maybe also check for several hotfixes, it might be a time consuming process to run Get-HotFix against each computer and also keep track of the status for each computer/hotfix. To ease this scenario, Ive written a script named Get-HotFixReport.ps1.

 

Get-HotFixReport.ps1 overview

  • Retrieves the computers to run Get-HotFix against using the Get-ADComputer cmdlet, which is available in Microsofts PowerShell-module for Active Directory
  • Loops through each computer and creates a custom object for every hotfix, containing information about the installation of the current hotfix for the current computer. Any error that occurs is also stored in the custom object. Get-HotFix are only run if the current computer responds to a ping request.
  • Every custom object are added to an array, which at last are exported to a csv-file.

The following three variables must be customized before running the script:






The example above retrieves all computer objects in Active Directory running a Windows Server operating system. You may specify only one computer, or a secific Organizational Unit, if required.

In the HotFix-variable you need to specify one or more hotfixes to check for. If more than one are specified, they must be separated with a comma. The hotfix-variable in the example above contains all hotfixes that are the prerequisites to install Exchange Server 2010 SP1 on Windows Server 2008 R2.

The csv-file may be opened in Microsoft Office Excel where its possible to apply filters to sort on e.g. “true” in the HotfixInstalled-column:

image

 

Note that the Get-HotFix cmdlet actually leverages the Win32_QuickFixEngineering WMI-class, and thus, it would be possible to run the script under Windows PowerShell 1.0 if you replace Get-HotFix with Get-WmiObject -Class Win32_QuickFixEngineering.

Of course you might also choose other ways to retrieve the computer-list, e.g. a csv-file, a txt-file or by using Quest`s PowerShell commands for Active Directory.

Manage Windows Update installations using Windows PowerShell

In most domains Windows Update are controlled by Group Policy and Windows Server Update Services (WSUS). For client computers, its common to download and install updates automatically. For servers, we want to control the installation of Windows Updates inside a scheduled maintenance window, and hence the Windows Update settings are configured not to automatically install updates.

If there are a few servers to manage, it wont be that time consuming to log on to each server with Remote Desktop and do the Windows Update installations manually. In larger environments however, this wont be an option, it must be automated in some way. While enterprise environments typically invest in a commercial product like BigFix for patch management, this might be overkill or too expensive for environments smaller than an enterprise.

To manage Windows Update in an automated way we can access the Windows Update Agent API using a COM-object called Microsoft.Update.Session. Using the New-Object cmdlet in Windows PowerShell, its easy to work with this COM-object. Based on this COM-object and portions of James ONeills functions for managing Windows Update, Ive written a PowerShell-script called Invoke-WindowsUpdate.

This script is intended to be used to download and install Windows Updates on servers. It runs like expected when invoked from a local computer, however, invoking the script using PowerShell Remoting like I was planning turned out to be problematic: Invoke-Command -ComputerName ServerA -FilePath 'C:ps-scriptsWindows UpdateInvoke-WindowsUpdate.ps1'

This will return the following error message:
Exception calling "CreateUpdateDownloader" with "0" argument(s): "Access is denied. (Exception from HRESULT: 0x80070005 E_ACCESSDENIED))"

This issue doesnt seem to be related to PowerShell, as there are several others reporting the same problem in other languages like VBScript.

The common workaround is to schedule the script to run as a scheduled task running as SYSTEM. Ive chosen to use this approach and to use PowerShell Remoting to invoke the scheduled task to run the script. An example:

$servers = Get-Content 'C:ps-scriptsWindows UpdateBulkA.txt'
foreach ($server in $servers) {
Invoke-Command -Computer $server -ScriptBlock {schtasks /run /tn "PowerShell - download and install Windows Updates"}
}

To create the scheduled task I would recommend you to use Group Policy Preferences.
A few sample screenshots from my lab setup:

image

image

image

image

Although its possible to invoke the script on all servers in the domain at once using i.e. the Active Directory-module for PowerShell to get the server names, I would recommend to break down the installations in several bulks. This way you can control that all domain controllers doesnt go offline at the same time and so on.

As you can see in the script its also possible to enable reporting to e-mail or file (HTML) to a central location, in addition to control whether the servers should reboot if required.
Planned improvements include nicer reports, Windows Update settings in the reports and if possible make the script work without having to use scheduled tasks. Suggestions for other improvements are always welcome.