Project: Setting Up a Server From Scratch

Lately, I’ve been installing enough new servers (or inheriting newly installed servers) that now seems like a good time to show what it’s like to start from scratch with a brand new server. Obviously, no one will have exactly the same implementation as this, but the idea is to show the basics of what it’s like to set up a new server.

This will not cover everything you can do with a server. It’s basically just a way for me to organize my posts into something fun.

This page right here is going to host links that, if followed chronologically, will show what it looks like to build a brand new server straight out of the box. Basically all I’m doing is reordering some of my existing posts, but this page will corral them into a mighty Voltron of a larger project. I will probably go back and edit the old posts to make more sense in the context of this project (or not depending on how much time I have). Don’t worry, the original posts will work as standalones.

Anyway, here’s what it’s like to buy and implement a server!

(This is a work in progress. All of the steps may not be here yet. I’ll remove this disclaimer when I feel it is more complete)

Unboxing the HPE DL380 Gen10 server

Enabling The Third Drive Box On An HPE DL380 Gen10 Server

Installing Windows Server 2019

New Windows Server 2019 Server: Miscellaneous Setup

Automating Windows Server Updates Part 1: Sconfig

Automating Windows Server Updates Part 2: PowerShell

Automating Windows Server Updates Part 3: Scheduling the Task

HPE Server Hardware Alert Emails: Gen 10 Changes

Automating Windows Server Updates Part 3: Scheduling the Task

Automating Windows Server Updates Part 1: Sconfig

Automating Windows Server Updates Part 2: PowerShell

In the previous post I showed how to use PowerShell to find and install Windows Updates. In this one, we will run our PowerShell script every Sunday afternoon using Task Scheduler. The script will install any available Windows Updates, reboot the computer if necessary, and email us the details of the installation.

The Scheduled Task

Open Task Scheduler. One way to do this is to hold the Windows key and press R. In the Run box type: taskschd.msc. In Task Scheduler, right-click on the Task Scheduler Library and choose “Create Basic Task”.

The “Create Basic Task Wizard” will open. Name your task something descriptive.

In my case I want the task to run on Sundays so I choose “Weekly”. Yours may differ.

Your next screen could look different. In my case I chose Weekly so I choose the day of the week here.

Next we choose “Start a Program” because we want to start PowerShell to run our Windows Update script. We will be sending an email also, but that part is in our PowerShell script so we can ignore the “Send and e-mail” option here. It doesn’t work anymore anyway.

For the “Program/Script” field you will either paste in or browse to the .exe for PowerShell. Chances are good it’s the same as mine below. In the “Add Arguments” field you put the path to your .ps1 script file including the file name. For example if it’s on the same computer you’re running the Task Scheduler on it may be C:\Scripts\WUpdate.ps1 or if the script is on a file share it may look like \\Server1\Share\Scripts\WUpdate.ps1. “Start In” can stay blank unless you really need it.

The last page lets you review the task before you create it. If everything looks ok, click “Finish”.

Double-click on the new task. The only thing you should have left to do in the settings is click the radio button next to “Run whether user is logged on or not.” This is important because we will be at the beach on Sunday when the task needs to be run so we will definitely not be logged in. You may also want to change the user account used to run the task, but that depends on your circumstances. Click OK. You will be asked to give the password for the account that will run the task since it will not be logged in at the time the task will run.

Now, to test it! Right-click on the new task and choose “Run”. If everything was done correctly you will get an email that looks like this:

Moving the Scheduled Task to Other Servers

You can export the task to XML so you can import it into another server. All you need to do is right-click the task in Task Scheduler and choose “Export”. Here is my XML. Yours may differ.

<?xml version="1.0" encoding="UTF-16"?>
-<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task" version="1.2">
  -<RegistrationInfo>
    <Date>2018-09-12T13:42:45.1141389</Date>
    <Author>domain\username</Author>
    <URI>\WindowsUpdate</URI>
  </RegistrationInfo>
 -<Triggers>
   -<CalendarTrigger>
      <StartBoundary>2018-09-16T18:00:00</StartBoundary>
      <Enabled>true</Enabled>
     -<ScheduleByWeek>
       -<DaysOfWeek>
          <Sunday/>
        </DaysOfWeek>
        <WeeksInterval>1</WeeksInterval>
      </ScheduleByWeek>
    </CalendarTrigger>
   -<CalendarTrigger>
      <StartBoundary>2018-09-16T20:30:00</StartBoundary>
      <Enabled>true</Enabled>
     -<ScheduleByWeek>
       -<DaysOfWeek>
          <Sunday/>
        </DaysOfWeek>
        <WeeksInterval>1</WeeksInterval>
      </ScheduleByWeek>
    </CalendarTrigger>
   -<TimeTrigger>
      <StartBoundary>2019-02-23T22:00:00</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
</Triggers>
-<Principals>
   -<Principal id="Author">
      <UserId>UserId</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
</Principals>
-<Settings>
   <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
   <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
   <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
   <AllowHardTerminate>true</AllowHardTerminate>
   <StartWhenAvailable>false</StartWhenAvailable>
   <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
  -<IdleSettings>
     <StopOnIdleEnd>true</StopOnIdleEnd>
     <RestartOnIdle>false</RestartOnIdle>
   </IdleSettings>
   <AllowStartOnDemand>true</AllowStartOnDemand>
   <Enabled>true</Enabled>
   <Hidden>false</Hidden>
   <RunOnlyIfIdle>false</RunOnlyIfIdle>
   <WakeToRun>false</WakeToRun>
   <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>
   <Priority>7</Priority>
</Settings>
-<Actions Context="Author">
  -<Exec>
 <Command>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
       <Arguments>PathToFile</Arguments>
     </Exec>
   </Actions>
</Task>

To import the task into the second server open Task Scheduler on that server and right-click on “Task Scheduler Library”. This time choose “Import Task” and browse to your XML file that you exported. The settings of the task will automatically open so you can review or change them.

Automating Windows Server Updates Part 2: PowerShell

Automating Windows Server Updates Part 1: Sconfig

Automating Windows Server Updates Part 3: Scheduling the Task 

Windows updates can be a blessing and a curse. On the one hand, it’s great that Microsoft is proactive in fixing issues with their operating system. On the other hand many of the issues with their operating system come from botched Windows Updates. Like deleting your files, for example:
https://www.howtogeek.com/fyi/bug-in-windows-10s-latest-update-might-be-deleting-files-back-up-your-data-now/

Another annoying thing about Windows Updates is that they often require a reboot and a long time watching percentages slowly rise (Often we find ourselves staring at 100% complete for a half an hour). This is especially bad when dealing with production servers that can only be rebooted on a Sunday.

Windows does have a built-in scheduling for installing Windows Updates, but it often just doesn’t work and you don’t have much flexibility about the timing of when things end up happening. In the newest version of Windows 10 you can delay updates for up to a week, but that’s it. Working hours can be set so the thing doesn’t reboot during the day, but there are limits to that, too.

Another, more fun way to handle Windows Updates is, of course, PowerShell! In this article we are going to learn how to use PowerShell to install Windows Updates and in the next article we will use Task Scheduler to run the script on Sunday afternoon when no one is at work.

(See my previous post for instructions on setting Windows Updates to manual only with Sconfig. Keep in mind Sconfig is only for Windows Server, not Windows 10.)

Installing the Windows Update PowerShell Module

First we will need to download the PowerShell module that controls Windows Updates. Download the required module here: tp://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc/
It’s small so it won’t take long.

Unzip the file to C:\Windows\System32\WindowsPowerShell\v1.0\Modules\ and then open PowerShell as an administrator (Right-click to find that option). I like to use PowerShell ISE because it’s got the nice “script pane” built in so you can copy and paste my examples in there and modify them to suit your environment.

To make sure it installed correctly and to see what new functions we have run:

Get-Command –module PSWindowsUpdate

If you get an error like: ” FullyQualifiedErrorId : CommandNotFoundException Get-WUInstall : The term ‘Get-WUInstall’ is not recognized as the name of a cmdlet, function, script file, or operable program” then run this:

Import-Module PSWindowsUpdate

This next command will list all of the Windows Updates you can install on your computer, but does not install them.

Get-WUInstall
–WindowsUpdate –ListOnly

You may know that in the Settings GUI version of Windows Update you can use Windows Update to get updates for other things besides Windows, like Microsoft Office. You can do that with PowerShell, too! It just requires one extra step in the initial setup.

The command for the wider search of Microsoft (as opposed to Windows) Updates is:

Get-WUInstall –MicrosoftUpdate –ListOnly

If you run that one now you will get an error:

Luckily, this is easy to fix. Just run this to register the proper service:

Add-WUServiceManager -ServiceID
7971f918-a847-4430-9279-4a52d1efe18d

Now run Get-WUInstall –MicrosoftUpdate –ListOnly again:

As you can see, I now have an update for Silverlight in addition to the Windows Defender updates.

Installing The Updates With PowerShell

Now that you’ve seen what updates are ready to install you can install them simply by running:

Get-WUInstall –MicrosoftUpdate

You will get a popup asking for permission to install the update:

You can click “Yes” or “No” for each indvidual update or click “Yes to All” to install all of them from the first popup. Another approach would be to run this so you don’t have to approve them and they will just install:

Get-WUInstall –MicrosoftUpdate –AcceptAll

You can even add -AutoReboot at the end to have the server automatically reboot after installing the updates if required to do so. This is what we will be doing in our scheduled task so we don’t have to remote in to the server on a Sunday when we’d rather be at the beach:

Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot

This what it will look like as it does its thing. Notice the message displayed above the code window as it goes through the steps of Accepted, Downloaded, and Installed:

And when it’s finished installing it will look like this (assuming everything installed correctly):

There is a chance that an update could fail. If one does you will get output like:

4 Failed                63 KB Microsoft driver update for MS Publisher 

If you have an update that repeatedly fails to install you could download it from the Microsoft Update Catalog (https://www.catalog.update.microsoft.com/Home.aspx ) and install it manually or you could disable installing the one specific update if you decide you don’t need it.

Disabling Specific Windows Updates

One of the other useful commands is Get-WUHistory. This will show you all of the Windows Updates that installed on the computer, their KB, and the date and time of installation. This is handy for finding updates that broke your computer and need to be uninstalled. You can always Google the KB to find out exactly what the update entails.

If you find one that you want to uninstall, here’s how to do it (replace the KB with the one you want to uninstall):

Get-WUUninstall -KBArticleID KB4501375

Sometimes the KB isn’t listed so you have to use the title. Here is a way to disable an update easily assuming it’s the only update left:

$u = Get-WUInstall –WindowsUpdate –ListOnly
$t = $u.title
Hide-WUUpdate –title $t –MicrosoftUpdate –Confirm:$false

To keep Windows from installing that update again you will have to “hide” it or it will install it again later:

 Hide-WUUpdate –KBArticleID KB4501375–MicrosoftUpdate –Confirm:$false

If you change your mind and want to “un-hide” an update:

Hide-WUUpdate -KBArticleID KB4501375-hidestatus:$false

The PowerShell Script

Ok, lets build our script that we want the task to run for us. I’ll give you the whole thing, then break it down into its parts.

$file = "PathToTranscriptFile"  
$from = "from@domain.com"
$to = "to@domain.com"
$subject = "Windows Update Report"
$smtp = "smtpserver.domain.com"
Start-Transcript -path $file
Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot
#Get-WUInstall –MicrosoftUpdate –ListOnly
Stop-Transcript
$body = [IO.File]::ReadAllText($file)
send-mailmessage -from "$from" -to "$to" -subject "$subject" -smtpserver "$smtp" -body "$body"

You can copy and paste this into a text editor and then change the variables in bold to values that make sense for your environment. Save the text file with a .ps1 file extension.

If you don’t need the details of the script explained you can skip to the next section.

$file = "PathToTranscriptFile"  
$from = "from@domain.com"
$to = "to@domain.com"
$subject = "Windows Update Report"
$smtp = "smtpserver.domain.com"

Anything beginning with a dollar sign ($) is a variable in PowerShell. The ones above are our email settings. PowerShell will need to know how to send the email so you will need to swap out your values for the parts in bold.

$file = "PathToTranscriptFile" 

This variable stores the path to the transcript file to simplify adding it into the body of the email.

Start-Transcript -path $file

Start-Transcript does pretty much what you’d think: it saves what happens in the PowerShell window to a file. This is how we’re going to harvest the status of the Windows Updates so we know what got installed.

Get-WUInstall –MicrosoftUpdate –AcceptAll –AutoReboot

This is the command we learned in the last post. It installs all of the available Windows Updates and reboots the computer if necessary.

#Get-WUInstall –MicrosoftUpdate –ListOnly

This line with the “#” in front of it will not run. The “#” tells PowerShell to ignore the line and go to the next line. I have this line in here for testing purposes. When I only want to get an email about the available updates, but I don’t want to install them (and I DEFINITELY don’t want to reboot the server) I will move the “#” up one line to expose this test line and hide the one that does the real update. You might want this line for initial testing just in case the email doesn’t work how you need it to at first. When you get everything how you like it you can move the “#” back down a line.

Stop-Transcript

Then we stop the transcript so we can get the file the transcript created and put it in the body of an email.

$server = $env:COMPUTERNAME

In this line we are creating a variable that holds the name of the server we are running the Windows Updates on. The server name is only useful if you are running this script on multiple computers, which I am.

$env is basically a list of variables that you can use to get (or set) information about your computer. You can run Get-ChildItem Env: to see a list of all of the Environment variables. COMPUTERNAME is the name of the computer, of course, and using the Environment Variable for it enables us to use this same script on any computer; we don’t need to supply the computer’s name because the script gets it for us at runtime!

$body = [IO.File]::ReadAllText($file)

The $body variable reads the $file variable that has our Update info and stores it to use in our email alert.

send-mailmessage -from "lslerts@lslog.com" -to "twood@lslog.com" -subject "Windows Update Report" -smtpserver "xserver.lslog.com" -body "$body"

Finally, we send the email alert. Send-mailmessage is the commandlet that sends an email. It requires a sending email address, a destination email address, a subject line, an email server and the body of the email which contains the details of our Windows Updates.

You can test this script by opening PowerShell ISE as an administrator and loading the script from “File” > “Open” or the folder icon.
Don’t forget to move the “#” up to the -AutoReboot line if you don’t actually want to install and reboot the server. Press the green “play” icon to run the script.

If everything was done correctly you should get an email that looks like this:

In the next post I will show you how to set up a scheduled task that will run Windows Updates every Sunday afternoon.

Automating Windows Server Updates Part 3: Scheduling the Task