Microsoft KB3124557: MS16-010: Security update in Microsoft Exchange Server to address spoofing: January 12, 2016

First thing to be aware of is that this update definitely does come down through WSUS, which was my first mistake (I’m so used to Exchange updates being full-blown CUxx-style, download-the-entire-ISO-again that I didn’t expect this to show up).

We have a 3-node DAG, and of course I hit “install all updates” on all 3 nodes. Meaning Exchange services got disabled (and I mean disabled. not just stopped) on all nodes. My thinking for this was that as Node 1 wasn’t managing any mailbox databases, I could patch it (not realising it had an Exchange update), reboot it, move some DBs, then reboot the other two nodes one at a time, juggling DBs as necessary.

Once I saw what was going on, I cancelled the update which is a bad idea, because it neither continued to install the patch nor rolled back the patch by re-enabling and starting Exchange services. So after cancellation, I had 3 nodes, none of which had the patch and all of which had Exchange disabled.

At this point, my “bads” were a) I should have checked whether the updates included anything for Exchange and b) not cancelled the update jobs.

To make matters worse, I’ve got 2 mailboxes but they’re both in the same mailbox database, and this database was on mounted on Node 3 which still had all of its services disabled. So when I logged on to ECP with my admin account, all I got was a blank screen.

After raising an incident, and then getting a phone call from Microsoft (http://support.microsoft.com/oas) it turns out that basically all I had to do was switch all the services to automatic on Node 3, and then start them. Suddenly, I could get to ECP, my mailboxes were accessible etc etc (and yes, I should have been using PowerShell, not ECP).

Trawl AD for devices running Windows Server, pull out hardware details, list them in PowerShell window

This is pretty much identical to the other two scripts but it displays the output in PowerShell. It’s got a few bits of colouring to differentiate between servers that can/ can’t be ping’d.

—————————————————
[string]$serverList
[string]$serverNames
[string]$serverArray
[int]$xAxis
[int]$yAxis
[int]$responsiveCounter
[int]$unresponsiveCounter
[string]$detail00
[string]$detail01
[string]$detail02
[string]$detail03

$serverList = Get-ADComputer -LDAPFilter “(&(ObjectCategory=Computer)(OperatingSystem=*server*))” | Select-Object Name
$serverNames = $serverList.Name

$serverArray = New-Object ‘object[,]’ $serverList.Count,4
$xAxis = 0
$yAxis = 0
[int]$responsiveCounter = 0
[int]$unresponsiveCounter = 0

Clear-Host

ForEach ($server in $serverNames)
{
$isAlive = Test-Connection $server -Count 1 -Quiet

If($isAlive -eq $true)
{
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $server | Select-Object CSName -ExpandProperty CSName
$detail00 = $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer
$detail01 = $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Model -ExpandProperty Model
$detail02 = $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_SystemEnclosure -ComputerName $server | Select-Object SerialNumber -ExpandProperty SerialNumber
$detail03 = $serverArray[$xAxis,$yAxis]

$userInterface.ForegroundColor = “DarkGreen”
$userInterface.BackgroundColor = “DarkRed”

“{0, -20}”,”{1, -25}”,”{2, -20}”,”{3, -40}” -f $detail00, $detail01, $detail02, $detail03

$responsiveCounter++

}
ElseIf($isAlive -eq $false)
{
$userInterface.ForegroundColor = “Blue”
$userInterface.BackgroundColor = “Yellow”

$mergeDetails = “`n” + $server + ” is not responding so I can’t retrieve any data” + “`n”
$mergeDetails

$unresponsiveCounter++
}

$yAxis=0
$xAxis++
}

$userInterface.ForegroundColor = “DarkGreen”
$userInterface.BackgroundColor = “DarkRed”
Write-Host “`n`nThe total number of responsive servers is ” $responsiveCounter

$userInterface.ForegroundColor = “Blue”
$userInterface.BackgroundColor = “Yellow”
Write-Host “The total number of unresponsive servers is ” $unresponsiveCounter

$userInterface.BackgroundColor = “DarkGreen”
$userInterface.ForegroundColor = “Cyan”

Trawl AD for devices running Windows Server, pull out hardware details (Dell specific)

This is pretty much identical to the last script, but it filters the output to return only Dell servers. It’s just the extra chunk that starts “If($madeBy -eq “Dell Inc.”)”. This could be replaced with any manufacturer. I neede to send our live estate to our account manager.

Because WMI is a bit weird, this script has to pull data out of different classes so looks worse than it is. It has to use the NETBIOS name to get all this data. It’s based around an array that is created from the number of servers it find (“OperatingSystem=*server*”). The $mergeDetails looks complicated, but it’s the only way I could find of presenting the results neatly, so the details of each server is on a seperate line. It’s very easy to just output the array in a list format but is horrible to read.

The main “If” loop just determines whether the server is respoding- if not, it writes to the same file that it can’t retrieve any data.
————————————————–
Remove-Item .\Dell_Name_ST_Model.csv

[string]$serverList
[string]$serverNames
[string]$serverArray
[int]$xAxis
[int]$yAxis
[string]$mergeDetails

$serverList = Get-ADComputer -LDAPFilter “(&(ObjectCategory=Computer)(OperatingSystem=*server*))” | Select-Object Name | Sort-Object Name
$serverNames = $serverList.Name

$serverArray = New-Object ‘object[,]’ $serverList.Count,4
$xAxis = 0
$yAxis = 0

ForEach ($server in $serverNames)
{

$isAlive = Test-Connection $server -Count 1 -Quiet

If($isAlive -eq $true)
{
$madeBy = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server -ErrorAction ‘SilentlyContinue’ | Select-Object Manufacturer -ExpandProperty Manufacturer

If($madeBy -eq “Dell Inc.”)
{
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $server | Select-Object CSName -ExpandProperty CSName
$mergeDetails = $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Model -ExpandProperty Model
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_SystemEnclosure -ComputerName $server | Select-Object SerialNumber -ExpandProperty SerialNumber
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$mergeDetails | Out-File .\Dell_Name_ST_Model.csv -Append
}
}
ElseIf($isAlive -eq $false)
{
$mergeDetails = $server + ” ,is not responding so I can’t retrieve any data” | Out-File .\Dell_Name_ST_Model.csv -Append
}

$yAxis=0
$xAxis++
}

Trawl AD for devices running Windows Server, pull out hardware details

Because WMI is a bit weird, this script has to pull data out of different classes so looks worse than it is. It has to use the NETBIOS name to get all this data. It’s based around an array that is created from the number of servers it find (“OperatingSystem=*server*”). The $mergeDetails looks complicated, but it’s the only way I could find of presenting the results neatly, so the details of each server is on a seperate line. It’s very easy to just output the array in a list format but is horrible to read.

The main “If” loop just determines whether the server is respoding- if not, it writes to the same file that it can’t retrieve any data.
———————————————–
Remove-Item .\allServers_Name_ST_Model.csv

[string]$serverList
[string]$serverNames
[string]$serverArray
[int]$xAxis
[int]$yAxis
[string]$mergeDetails

$serverList = Get-ADComputer -LDAPFilter “(&(ObjectCategory=Computer)(OperatingSystem=*server*))” | Select-Object Name | Sort-Object Name
$serverNames = $serverList.Name

$serverArray = New-Object ‘object[,]’ $serverList.Count,4
$xAxis = 0
$yAxis = 0

ForEach ($server in $serverNames)
{

$isAlive = Test-Connection $server -Count 1 -Quiet

If($isAlive -eq $true)
{
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $server | Select-Object CSName -ExpandProperty CSName
$mergeDetails = $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Model -ExpandProperty Model
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$yAxis++

$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_SystemEnclosure -ComputerName $server | Select-Object SerialNumber -ExpandProperty SerialNumber
$mergeDetails = $mergeDetails + “,” + $serverArray[$xAxis,$yAxis]
$mergeDetails | Out-File .\allServers_Name_ST_Model.csv -Append
}
ElseIf($isAlive -eq $false)
{
$mergeDetails = $server + ” ,is not responding so I can’t retrieve any data” | Out-File .\allServers_Name_ST_Model.csv -Append
}

$yAxis=0
$xAxis++
}

PowerShell: Retrieve all “live” (pingable) Dell server names, models & serial number

Here’s the other script that filters out anything non-Dell- easy enough to modify so it would focus on any manufacturer (I’ve just noticed that this code would GWMI first, then ping. I’ll change this, otherwise it’ll try to retrieve WMI data from a server it can’t reach.)
=============================================================================
Remove-Item .\Dell_Name_ST_Model.csv

[string]$serverList
[string]$serverArray
[int]$xAxis
[int]$yAxis

$serverList = Get-ADComputer -LDAPFilter “(&(ObjectCategory=Computer)(OperatingSystem=*server*))” | Select-Object Name | Sort-Object Name
$serverNames = $serverList.Name

$serverArray = New-Object ‘object[,]’ $serverList.Count,4
$xAxis = 0
$yAxis = 0

ForEach ($server in $serverNames)
{

$madeBy = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer

If($madeBy -eq “Dell Inc.”)
{
$isAlive = Test-Connection $Server -Count 1 -Quiet
If($isAlive -eq $true)
{
Write-Host “Server $server is fine”
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $server | Select-Object CSName -ExpandProperty CSName
$yAxis++
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer
$yAxis++
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Model -ExpandProperty Model
$yAxis++
$serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_SystemEnclosure -ComputerName $server | Select-Object SerialNumber -ExpandProperty SerialNumber
}
ElseIf($isAlive -eq $false)
{
Write-Host “Server $server is not responding”
}
}
$yAxis=0
$xAxis++
}

$yAxis=0
$xAxis=0

ForEach($item in $serverArray)
{
$gatherServerArrayContent = $csName = $serverArray[$xAxis,$yAxis]
$gatherServerArrayContent += “,”
$gatherServerArrayContent += $manufacturer = $serverArray[$xAxis,($yAxis+1)]
$gatherServerArrayContent += “,”
$gatherServerArrayContent += $model = $serverArray[$xAxis,($yAxis+2)]
$gatherServerArrayContent += “,”
$gatherServerArrayContent += $serialNumber = $serverArray[$xAxis,($yAxis+3)]

$gatherServerArrayContent | Out-File .\Dell_Name_ST_Model.csv -Append

$yAxis = 0
$xAxis++
}

PowerShell: ping an arbitrary IP subnet

This will ping an arbitrary subnet; feed it an ip range + subnet mask and it will ping all the hosts. Written primarily to handle “hidden” SAN IPs that wouldn’t show up on DHCP.
=======================
Clear-Host #clears the screen, just like CLS does in MS-DOS

#initialises counters to keep track of the various subnet octets. Octet 3 (4th octet) has to be at least 1, so this gets set to 1 regardelss of user input
[int]$counterOctet0 = 0
[int]$counterOctet1 = 0
[int]$counterOctet2 = 0
[int]$counterOctet3 = 1

[int]$singleHostOctet0 = 255
[int]$singleHostOctet1 = 255
[int]$singleHostOctet2 = 255
[int]$singleHostOctet3 = 255

[int]$customIPRange0 = Read-Host -Prompt “Please enter the 1st IP octet”
[int]$customIPRange1 = Read-Host -Prompt “Please enter the 1st IP octet”
[int]$customIPRange2 = Read-Host -Prompt “Please enter the 1st IP octet”
[int]$customIPRange3 = Read-Host -Prompt “Please enter the 1st IP octet”

[int]$customSubnetOctet0 = Read-Host -Prompt “Please enter the 1st subnet octet”
[int]$customSubnetOctet1 = Read-Host -Prompt “Please enter the 2nd subnet octet”
[int]$customSubnetOctet2 = Read-Host -Prompt “Please enter the 3rd subnet octet”
[int]$customSubnetOctet3 = Read-Host -Prompt “Please enter the 4th subnet octet”

$customIPRange3 = $counterOctet3

[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”

$resultOctet0 = $singleHostOctet0 – $customSubnetOctet0
$resultOctet1 = $singleHostOctet1 – $customSubnetOctet1
$resultOctet2 = $singleHostOctet2 – $customSubnetOctet2
$resultOctet3 = $singleHostOctet3 – $customSubnetOctet3

If($resultOctet0 -ne 0)
{
If($resultOctet1 -ne 0)
{
If($resultOctet2 -ne 0)
{
If($resultOctet3 -ne 0)
{
Do
{
Do
{
Do
{
Do
{
$result0 = Test-Connection $ipAddress.IPAddressToString -Quiet
If($result0 -eq $true)
{
Try
{
$hostName = [System.Net.Dns]::GetHostEntry(“$ipAddress”).HostName
}
Catch [system.exception]
{
$hostName = “no host name”
}
Write-Host “The IP Address $ipAddress ($hostName) is responding”
}
ElseIf($result0 -eq $false)
{
Write-Host “The IP Address $ipAddress is not responding”
}
$customIPRange3 = $customIPRange3 + 1
$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange3 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $customIPRange2 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange2 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $counterOctet2
$customIPRange1 = $customIPRange1 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange1 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $counterOctet2
$customIPRange1 = $counterOctet1
$customIPRange0 = $customIPRange0 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange0 -lt 255)
}
Else
{
}
}
Else
{
}
}
Else
{
}
}
ElseIf($resultOctet1 -ne 0)
{
If($resultOctet2 -ne 0)
{
If($resultOctet3 -ne 0)
{
Do
{
Do
{
Do
{
$result1 = Test-Connection $ipAddress.IPAddressToString -Quiet
If($result1 -eq $true)
{
Try
{
$hostName = [System.Net.Dns]::GetHostEntry(“$ipAddress”).HostName
}
Catch [system.exception]
{
$hostName = “no host name”
}
Write-Host “The IP Address $ipAddress ($hostName) is responding”
}
ElseIf($result1 -eq $false)
{
Write-Host “The IP Address $ipAddress is not responding”
}
$customIPRange3 = $customIPRange3 + 1
$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange3 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $customIPRange2 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange2 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $counterOctet2
$customIPRange1 = $customIPRange1 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange1 -lt 255)
}
Else
{
}
}
Else
{
}
}
ElseIf($resultOctet2 -ne 0)
{
If($resultOctet3 -ne 0)
{
Do
{
Do
{
$result2 = Test-Connection $ipAddress.IPAddressToString -Quiet
If($result2 -eq $true)
{
Try
{
$hostName = [System.Net.Dns]::GetHostEntry(“$ipAddress”).HostName
}
Catch [system.exception]
{
$hostName = “no host name”
}
Write-Host “The IP Address $ipAddress ($hostName) is responding”
}
ElseIf($result2 -eq $false)
{
Write-Host “The IP Address $ipAddress is not responding”
}
$customIPRange3 = $customIPRange3 + 1
$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange3 -lt 255)

$customIPRange3 = $counterOctet3
$customIPRange2 = $customIPRange2 + 1
[System.Net.IPAddress]$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange2 -lt 255)
}
Else
{
}
}
ElseIf($resultOctet3 -ne 0)
{
Do
{
$result3 = Test-Connection $ipAddress.IPAddressToString -Quiet
If($result3 -eq $true)
{
Try
{
$hostName = [System.Net.Dns]::GetHostEntry(“$ipAddress”).HostName
}
Catch [system.exception]
{
$hostName = “no host name”
}
Write-Host “The IP Address $ipAddress ($hostName) is responding”
}
ElseIf($result3 -eq $false)
{
Write-Host “The IP Address $ipAddress is not responding”
}
$customIPRange3 = $customIPRange3 + 1
$ipAddress = “$customIPRange0.$customIPRange1.$customIPRange2.$customIPRange3”
}
While ($customIPRange3 -lt 255)
}

PowerShell: Retrieve all “live” (pingable) server names, manufacturers, models & serial number

This script searches AD for any server running Windows Server, strips the names out to make a list, pings the list to avoid wasting time and either gathers some WMI data or reports that the server is offline. It then collates the data for individual servers into one line which it writes to a CSV.

My next script is basically the same thing, but it filters out Dell servers at the start.
=======================================
Remove-Item .\allServers_Name_ST_Model.csv #deletes the old export file
[string]$serverList #this will contain the details of any device running Windows Server in AD
[string]$serverNames
[string]$serverArray #this will contain the name, manufacturer, model and serial number in an array
[int]$xAxis #keeeps track of the vertical array elements
[int]$yAxis #keeps track of the horizontal array elements
$serverList = Get-ADComputer -LDAPFilter "(&(ObjectCategory=Computer)(OperatingSystem=*server*))" | Select-Object Name | Sort-Object Name #Pulls any Windows Servers out of AD
$serverNames = $serverList.Name #Extracts just server names out of $serverList
$serverArray = New-Object 'object[,]' $serverList.Count,4 #creates the array with the same number of lines as there are servers in $serverList, and 4 columns-
#name, manufacturer, model, serial number.
$xAxis = 0 #arrays start at 0!
$yAxis = 0 #arrays start at 0!
ForEach ($server in $serverNames) #starts the loop, cycles through each server in turn
{
$isAlive = Test-Connection $Server -Count 1 -Quiet #creates a variable that will return true/ false depending on wther the server responds
 If($isAlive -eq $true) #if the server responds... pull WMI data from different classes, -ExpandProperty makes the output a bit prettier
 {
 Write-Host "Server $server is fine" #this isn't really necessary, it's handy for manual testing
 $serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_OperatingSystem -ComputerName $server | Select-Object CSName -ExpandProperty CSName
 $yAxis++ #increments $yAxis fro 0 > 1 to access next array element
 $serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Manufacturer -ExpandProperty Manufacturer
 $yAxis++ #increments $yAxis fro 1 > 2 to access next array element
 $serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_ComputerSystem -ComputerName $server | Select-Object Model -ExpandProperty Model
 $yAxis++ #increments $yAxis fro 2 > 3 to access next array element (remember 3 is the last column in a 4-column array)
 $serverArray[$xAxis,$yAxis] = Get-WMIObject -Class Win32_SystemEnclosure -ComputerName $server | Select-Object SerialNumber -ExpandProperty SerialNumber
 }
 ElseIf($isAlive -eq $false) #if the server doesn't respond, write the server name with "is not responding" to the array
 {
 $serverArray[$xAxis,$yAxis] = $server
 $yAxis++
 $serverArray[$xAxis,$yAxis] = "is not responding"
 }
 $yAxis=0 #resets the $yAxis so it begins at 0 on the next line
 $xAxis++ #increments $xAxis, this never gets reset to 0 as you just want it to cycle through each server until the end
}

#The $serverArray variable is fully populated by now, so we need to make the data suitable for output
$yAxis=0
$xAxis=0
ForEach($item in $serverArray) #loops through each cell of the array in order to put the collections into comma-separated lines of text
{
 $gatherServerArrayContent = $csName = $serverArray[$xAxis,$yAxis]
 $gatherServerArrayContent += ","
 $gatherServerArrayContent += $manufacturer = $serverArray[$xAxis,($yAxis+1)]
 $gatherServerArrayContent += ","
 $gatherServerArrayContent += $model = $serverArray[$xAxis,($yAxis+2)]
 $gatherServerArrayContent += ","
 $gatherServerArrayContent += $serialNumber = $serverArray[$xAxis,($yAxis+3)]
$gatherServerArrayContent | Out-File .\allServers_Name_ST_Model.csv -Append #each server has it's own line in this file containing the 4 attributes
$yAxis = 0 #same again- reset the $yAxis for the next line
 $xAxis++ #same again- $xAxis never gets reset as it just has to cycle through the whole array
}