Automating WSUS 2016 Installation with PowerShell

PowerShell-Text-Purple-hero
In a previous article I went through the manual process of installing Windows Software Update Services (WSUS) on a new Windows Server 2016 box. I don’t expect many of you to have to go through this process more than once or twice, so a manual installation is not that much effort. But, some of you may want to automate the process. Perhaps as part of a larger server automation effort. So let’s see how we can achieve the same result using PowerShell.
 

 
As before, I want to be able to achieve all of this from my Windows 10 desktop, which has the latest Remote Server Administration Toolkit (RSAT) installed. For the sake of this article, I’ve rolled my new server back to a fresh, domain-joined installation. I’m also logged on with a domain admin credential.
Perhaps the easiest way to automate this process is with an existing XML configuration file. If you recall from the previous article, at the very end of the manual process there was an option to export the configuration to an XML file, which I did. Here’s what part of that file looks like:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Collections.ObjectModel.Collection`1[[System.Management.Automation.PSObject, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]</T>
      <T>System.Object</T>
    </TN>
    <LST>
      <Obj RefId="1">
        <TN RefId="1">
          <T>Microsoft.Management.Infrastructure.CimInstance#root/Microsoft/Windows/ServerManager/ServerComponent_NET_Framework_45_ASPNET</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#root/Microsoft/Windows/ServerManager/MSFT_ServerManagerServerComponentDescriptor</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#ServerComponent_NET_Framework_45_ASPNET</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#MSFT_ServerManagerServerComponentDescriptor</T>
          <T>Microsoft.Management.Infrastructure.CimInstance</T>
          <T>System.Object</T>
        </TN>
        <ToString>ServerComponent_NET_Framework_45_ASPNET</ToString>
        <Props>
          <S N="PSComputerName">CHI-WSUS.GLOBOMANTICS.local</S>
        </Props>
        <MS>
          <I32 N="NumericId">429</I32>
          <Obj N="__ClassMetadata" RefId="2">
            <TN RefId="2">
              <T>System.Collections.ArrayList</T>
              <T>System.Object</T>
            </TN>
            <LST>
              <Obj RefId="3">
                <MS>
                  <S N="ClassName">MSFT_ServerManagerServerComponentDescriptor</S>
                  <S N="Namespace">root/Microsoft/Windows/ServerManager</S>
                  <S N="ServerName">CHI-WSUS.GLOBOMANTICS.local</S>
                  <I32 N="Hash">-271270728</I32>
                  <S N="MiXml"><CLASS NAME="MSFT_ServerManagerServerComponentDescriptor"><QUALIFIER NAME="ClassVersion" TYPE="string" TOSUBCLASS="false"><VALUE>4.5.0</VALUE></QUALIFIER><QUALIFIER NAME="DisplayName" TYPE="string" TOSUBCLASS="false"><VALUE>NET-Framework-45-ASPNET</VALUE></QUALIFIER></CLASS></S>
                </MS>
              </Obj>
              <Obj RefId="4">
                <MS>
                  <S N="ClassName">ServerComponent_NET_Framework_45_ASPNET</S>
                  <S N="Namespace">root/Microsoft/Windows/ServerManager</S>
                  <S N="ServerName">CHI-WSUS.GLOBOMANTICS.local</S>
                  <I32 N="Hash">-271285288</I32>
                  <S N="MiXml"><CLASS NAME="ServerComponent_NET_Framework_45_ASPNET" SUPERCLASS="MSFT_ServerManagerServerComponentDescriptor"><QUALIFIER NAME="ClassVersion" TYPE="string" TOSUBCLASS="false"><VALUE>4.5.0</VALUE></QUALIFIER><QUALIFIER NAME="DisplayName" TYPE="string" TOSUBCLASS="false"><VALUE>NET-Framework-45-ASPNET</VALUE></QUALIFIER></CLASS></S>
                </MS>
              </Obj>
            </LST>
          </Obj>
        </MS>
      </Obj>
      <Obj RefId="5">
        <TN RefId="3">
          <T>Microsoft.Management.Infrastructure.CimInstance#root/Microsoft/Windows/ServerManager/ServerComponent_NET_WCF_HTTP_Activation45</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#root/Microsoft/Windows/ServerManager/MSFT_ServerManagerServerComponentDescriptor</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#ServerComponent_NET_WCF_HTTP_Activation45</T>
          <T>Microsoft.Management.Infrastructure.CimInstance#MSFT_ServerManagerServerComponentDescriptor</T>
          <T>Microsoft.Management.Infrastructure.CimInstance</T>
          <T>System.Object</T>
        </TN>
        <ToString>ServerComponent_NET_WCF_HTTP_Activation45</ToString>
        <Props>
          <S N="PSComputerName">CHI-WSUS.GLOBOMANTICS.local</S>
        </Props>
        <MS>
          <I32 N="NumericId">421</I32>
          <Obj N="__ClassMetadata" RefId="6">
            <TNRef RefId="2" />
            <LST>
              <Obj RefId="7">
                <MS>
                  <S N="ClassName">MSFT_ServerManagerServerComponentDescriptor</S>
                  <S N="Namespace">root/Microsoft/Windows/ServerManager</S>
                  <S N="ServerName">CHI-WSUS.GLOBOMANTICS.local</S>
                  <I32 N="Hash">-276641992</I32>
                  <S N="MiXml"><CLASS NAME="MSFT_ServerManagerServerComponentDescriptor"><QUALIFIER NAME="ClassVersion" TYPE="string" TOSUBCLASS="false"><VALUE>4.5.0</VALUE></QUALIFIER><QUALIFIER NAME="DisplayName" TYPE="string" TOSUBCLASS="false"><VALUE>NET-WCF-HTTP-Activation45</VALUE></QUALIFIER></CLASS></S>
                </MS>
              </Obj>
              <Obj RefId="8">
                <MS>
                  <S N="ClassName">ServerComponent_NET_WCF_HTTP_Activation45</S>
                  <S N="Namespace">root/Microsoft/Windows/ServerManager</S>
                  <S N="ServerName">CHI-WSUS.GLOBOMANTICS.local</S>
                  <I32 N="Hash">-276640952</I32>
                  <S N="MiXml"><CLASS NAME="ServerComponent_NET_WCF_HTTP_Activation45" SUPERCLASS="MSFT_ServerManagerServerComponentDescriptor"><QUALIFIER NAME="ClassVersion" TYPE="string" TOSUBCLASS="false"><VALUE>4.5.0</VALUE></QUALIFIER><QUALIFIER NAME="DisplayName" TYPE="string" TOSUBCLASS="false"><VALUE>NET-WCF-HTTP-Activation45</VALUE></QUALIFIER></CLASS></S>
                </MS>
              </Obj>
            </LST>
          </Obj>

Yeah, it’s scary looking XML, but we’re not going to do anything with it. Although if you are using this for a different computer you’ll need to do a search and replace on the server name. Mine will remain the same, so I’m good. You’ll be amazed at how easy this is. All it takes is one line to stand up my new WSUS server.

Install-WindowsFeature -ComputerName chi-wsus.globomantics.local -ConfigurationFilePath C:\work\DeploymentConfigTemplate.xml

That’s it! After a short period of time the installation will complete.
Installing with a deployment file
It is also pretty simple to see what is now installed.
Installed features
However, be very, very careful with this approach. Any item that wasn’t in the XML file ends up being removed. If you look closely you’ll see PowerShell is no longer installed. That won’t work for me, so I’ll have to quickly add it back.

Install-WindowsFeature -ComputerName chi-wsus.globomantics.local -Name PowerShell

But as before, all I’ve done is install WSUS. I still need to go through the configuration process. Let’s skip that for now and assume, as is most likely the case, that you don’t have a configuration XML file to use.  You can still use PowerShell.

One thing to be careful of is that you can’t simply install the UpdateServices feature and all subfeatures.
UpdateServices features
WID (Windows Internal Database) Connectivity and SQL Server Connectivity are mutually exclusive, so you need to be a bit more granular.

Install-WindowsFeature -ComputerName chi-wsus.globomantics.local -Name Updateservices,UpdateServices-WidDB,UpdateServices-services  -IncludeManagementTools

Let’s see the result.
Installation results
Looks pretty complete to me. Typically, you would jump to Server Manager and run the post-installation tasks. However, when installing the feature manually through PowerShell, you have to also manually run through the post-install tasks. This needs to be done on the WSUS server using the wsusutil.exe command line tool. Once you know the command, you can use Invoke-Command but I went into an interactive PSSession to run it.
Running postinstall
Since I’m using the internal database, all I need to do is specify the content location. The other step you will probably need is to note what port the service is using. You can get that with Get-Website.
Checking WSUS web sites
Now on my Windows 10 client I can open the Update Services Manager.
Connecting to the new server

From here it is business as usual. There is a module for managing WSUS from PowerShell, and perhaps we’ll look at that in more detail one of these days. But before we get to that, because we can install a new WSUS server through PowerShell, we could also use Desired State Configuration. We’ll look at that next time.