A little background;
I migrated our Exchange On Prem to Office 365 last year and had to learn powershell to administer it.
Since then I’ve gotten into using it to perform numerous tasks and somewhat understand it, however more advanced things like creating an array, or understanding piping, etc., leave me a bit baffled.
Ultimately what I’m trying to do is fully automate our VIRTUAL server patching and rebooting, along with verifying services set to ‘auto’ are actually started, and if not, start them from a single console.
Down the road, I want this to be a scheduled task that does the following:
Starting at 6pm the night before the scheduled reboots, tell each server to install the patches that are pushed from SCCM. Preferably this would be staggered, so that not all of the servers are hitting the SCCM server for their patch at the same time, but I have no idea how to do that.
I have all of the servers in a .csv file and would prefer to keep it this way so going forward, when adding or removing a server, there is very little maintenance to do to make the script continue to work.
Then, to wait until exactly 6am, and have it start rebooting servers, in a particular order (which could be achieved by the order they are listed in the CSV file), staggering the reboot initiation by 30 seconds between servers, so they’re not all hitting the VMware hosts at the exact same time.
Once the reboots are completed, I’d like to have a way to go through each of the servers that were bounced, and verify that any service set to auto is started, and if not, have it remotely started, with a report written.
Here’s the truth, most of what I have working so far (patching is one script, reboots are another, and I’m just running them manually for testing purposes), is stuff someone else wrote, so I’d like to learn how to do this stuff, but finding time is always a challenge.
Here’s what I have so far:
Patching:
# Determine script location $ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path $log = "$ScriptDir\InstallUpdates.log" $date = Get-Date -Format "dd-MM-yyyy hh:mm:ss" # Get list of clients from notepad "--------------------- Script executed on $date (DD-MM-YYYY hh:mm:ss) ---------------------" + "`r`n" | Out-File $log -append #ForEach ($system in Get-Content $ScriptDir"\Chrisclients.txt") ForEach ($system in Import-CSV "H:\PathToCSVFile\ServersToReboot.csv") { $wmicheck=$null $wmicheck =Get-WmiObject -ComputerName $system -namespace root\cimv2 -Class Win32_BIOS -ErrorAction SilentlyContinue if ($wmicheck) { # Get list of all instances of CCM_SoftwareUpdate from root\CCM\ClientSDK for missing updates https://msdn.microsoft.com/en-us/library/jj155450.aspx?f=255&MSPPError=-2147217396 $TargetedUpdates= Get-WmiObject -ComputerName $system -Namespace root\CCM\ClientSDK -Class CCM_SoftwareUpdate -Filter ComplianceState=0 $approvedUpdates= ($TargetedUpdates |Measure-Object).count $pendingpatches=($TargetedUpdates |Where-Object {$TargetedUpdates.EvaluationState -ne 8} |Measure-Object).count $rebootpending=($TargetedUpdates |Where-Object {$TargetedUpdates.EvaluationState -eq 8} |Measure-Object).count if ($pendingpatches -gt 0) { try { $MissingUpdatesReformatted = @($TargetedUpdates | ForEach-Object {if($_.ComplianceState -eq 0){[WMI]$_.__PATH}}) # The following is the invoke of the CCM_SoftwareUpdatesManager.InstallUpdates with our found updates $InstallReturn = Invoke-WmiMethod -ComputerName $system -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$MissingUpdatesReformatted) -Namespace root\ccm\clientsdk "$system,Targeted Patches :$approvedUpdates,Pending patches:$pendingpatches,Reboot Pending patches :$rebootpending,initiated $pendingpatches patches for install" | Out-File $log -append } catch {"$System,pending patches - $pendingpatches but unable to install them ,please check Further" | Out-File $log -append } } else {"$system,Targeted Patches :$approvedUpdates,Pending patches:$pendingpatches,Reboot Pending patches :$rebootpending,Compliant" | Out-File $log -append } } else {"$system,Unable to connect to remote system ,please check further" | Out-File $log -append } }Rebooting:
$header = "server" $servers = import-csv "H:\PathToCSVFile\ServersToReboot.csv" -header $headerforeach($i in $servers) {
Write-Host “Attempting to reboot:” $i.server “…”$serverObj = gwmi Win32_operatingsystem -computer $i.server
$status = $serverObj.reboot()
if ($status.ReturnValue = “0”) {
Write-Host “Reboot successful.”
Write-Host “Waiting 15 seconds”
Start-Sleep -s 15
Write-Host “Starting Next Reboot”
} else {
Write-Host “Reboot failed. Check permissions.”
}
}
The reboot script works, for the most part, but once the last server is finished, it does make me wait 15 seconds before terminating, but it does work as expected.
I have scoured the web, and ended up here by my searches on a powershell to check on services on those servers, and to restart them if needed, but the discussion seems to fall off, or I got lost and didn’t understand.
Aside from reading a powershell book or taking another class, does anybody have any recommendations on how to accomplish this?