If you are like me, you are always looking for ways to not leave your chair, or for that matter, not switch windows.

When it comes to install Update Rollups on every Exchange 2010 server you have, the same applies. So I set out to find a way and I found one! Even though this requires some work upfront, it will make it easy ever after.

Pre-Requisites:

The cost of making it easier for future is the work you have to do now. Well, let’s get to it. In order to be able to connect to your Exchange servers remotely, you will need to configure winrm (if not configured already). All you need to do is run

winrm quickconfig

from elevated PowerShell session (run as administrator). The command adds an HTTP listener, configures the server to allow remote requests, and creates a Firewall exception rule. I am assuming that you are running Windows Server 2008 R2. I have not tested this on other server versions, however it should work if PowerShell v2 and WinRM is installed correctly.

Script:

So, how do I run the script?

Get-Content “\\server\share\servers.txt” | Foreach-Object {Invoke-Command –ComputerName $_ –FilePath “\\server\share\Install-UpdateRollups.ps1”}

The command will read list of servers from servers.txt (specify your path where it reads \\server\share\servers.txt) and call script to install Update Rollup specified in the script. Notice that I am user serialization by piping. This way I am running update only on one server at a time. The command could be change to look like this:

Invoke-Command –ComputerName (Get-Content “\\server\share\servers.txt”) –FilePath “\\server\share\Install-UpdateRollups.ps1”

however, I have not tested it on multiple computers and unsure of the success using this method.

After the installation of Update Rollup, the script will prompt user for reboot and if user approves, script will also reboot the server.

So, a million dollar question is, where is this script? You can download it here: Install-UpdateRollups.ps1

The code is pasted below for reference:

#############################################################################
# Install-UpdateRollups.ps1
# Remotely installs Update Rollups on Exchange 2007 or Exchange 2010 servers
#
# Pre-requisites
# --------------
# Requires winrm enabled on destination servers. Run winrm quickconfig to enable.
# Requires write access to $Log_Drive folder and $Install_Drive folder if "Logs"
#   folder doesn't exist in $Install_Drive.
#
# Created by 
# Bhargav Shukla
# http://blogs.technet.com/bshukla
# https://www.bhargavs.com
# 
# DISCLAIMER
# ==========
# THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE 
# RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
#############################################################################

#Update variables to reflect correct locations and Update Rollup installer file name
$Install_Drive = "\\server\share"
$RU_File = "installer.msp"
$Log_Drive = "$Install_Drive\Logs"
$ServerName = $Env:COMPUTERNAME

# Check for RU install file
$CheckRUPath = "$Install_Drive\$RU_File"
Write-Host -ForegroundColor Green "Checking for $CheckRUPath"
if (-not (Test-Path $CheckRUPath))
{
	Write-Host -ForegroundColor Red "ERROR: Update Rollup File not found!"
	Write-Host -ForegroundColor Red "ERROR: Exiting."
	exit
}

# Check for Logs path, create folder if doesn't exist
$CheckLogPath = "$Log_Drive"
Write-Host -ForegroundColor Green "Checking for $CheckLogPath"
if (-not (Test-Path $CheckLogPath))
{
	Write-Host -ForegroundColor Yellow "ERROR: Log Folder not found!"
	Write-Host -ForegroundColor Yellow "INFO:  Creating Log Folder..."
	New-Item -Path $Install_Drive -Name Logs -itemtype directory -Force
}

# Disable "Check for publisher's certificate revocation"
Write-Host ""
Write-Host -ForegroundColor Green "Disabling publisher's certificate revocation check..."
set-ItemProperty -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -name State -value 146944

Write-Host -ForegroundColor Green "Installing Exchange Update Rollup..."
	$oProcess = [System.Diagnostics.Process]::Start("$Install_Drive\$RU_File", " /passive /lv $Log_Drive\$ServerName-InstallRollup.log /norestart")
	$oProcess.WaitForExit() 

# Enable "Check for publisher's certificate revocation"
Write-Host -ForegroundColor Green "Re-enabling Check for publisher's certificate revocation..."
Set-ItemProperty -path "HKCU:Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -name State -value 146432

# Reboot if user responds [Y]es
if ((Read-Host "Reboot? [Y/N]") -eq "Y")
{
write-host -ForegroundColor Red "Rebooting Server $ServerName."
Restart-Computer
}
Update:

I failed to mention the effect of double-hops and delegation of authentication for the remote installation mentioned above to work. Here’s why it is a problem:

Your install files and list of servers are located on a server (let’s call it ServerA). You are running the invoke-command from a client computer (let’s call it ClientA) and you are going to install RU on Exchange servers (let’s call it EXA, EXB and EXC). When you run the command, get-content is run is local runspace of ClientA and works fine. The next step is to pipe the servernames to invoke-command. The install script mentioned above is then called from share on ServerA. However, this is now remote runspace on exchange servers EXA, EXB and EXC. The error you will notice is when the install script checks for existence of RU file. Even if the RU file exists in mentioned share and permissions are given to account you are using to run the commands from ClientA, you will see that script errors and exits unexpectedly. It thinks the RU file doesn’t exist when it actually does!

That is because, your credentials from ClientA are passed to EXA, however, to access the file on ServerA, your credentials needs to be passed on to it. This is delegation. And we have not configured any delegation yet! This will cause script block to fail since it can’t access the RU file without access.

How can you solve this? Here are the steps:

1. on ClientA run:

Enable-wsmancredssp -role client –delegatecomputer *

This will enable credssp delegation from ClientA to computers you define in –delegatecomputer. In our example, we allowed delegation to all computer by using * which is ok for lab. In production environment, you may want to restrict it to your domain name (i.e. *.domain.com) or list of servers (i.e. EXA.domain.com, EXB.domain.com, EXC.domain.com).

2. on all target servers, EXA, EXB and EXC in our example, run:

Enable-wsmancredssp -role server

This will allow target servers to use credentials specified by ClientA using CredSSP to access files on ServerA.

3. on ClientA, run the install command:

$cred = Get-Credential
Get-Content “\\server\share\servers.txt” | Foreach-Object {Invoke-Command –ComputerName $_ –FilePath “\\server\share\Install-UpdateRollups.ps1” –Authentication CredSSP –Credential $cred}

Notice the use of CredSSP and explicit specification of credentials. This is important and required for the remote install process to work.

One more gotcha. The process above does not work if your ClientA isn’t Windows 7, Vista or Windows Server 2008. This is because CredSSP isn’t available to Windows XP or Windows Server 2003. You can host your share on Windows Server 2003, however, you must run step 1 and 3 from a client that is capable of using CredSSP.

Here are some references for further reading:

Multi-Hop Support in WinRM

Using invoke-command to launch a script on a remote computer which connects to network resources

Enable-WSManCredSSP

 

This article is also posted to https://www.bhargavs.com