An annoyance for anyone when running a large scripted software release is when the deployment fails half way through because someone has left a logged-on Windows session with an Open file or Window. You may then need to invest large amounts of time identifying the cause, reverting changes that only deployed half-way and eventually re-run the release package…
In one of my earlier blog posts I explained how I would drop servers into maintenance mode when running a software deployment to prevent being spammed by Operations Manager Alerts… I targeted my specific environment in SCOM using a filter that would only add servers with a NetBIOS name starting with PROD or TEST.
I have quickly whipped up something similar to boot all users off of servers (log-off) prior to executing release package. The snippet below will grab all servers in the “Servers OU” on active directory and throw them into an array. It will then enumerate each server and use the Inbuilt “MSG” command (similar to NET SEND) to warn each user logged onto servers to save their work and log off (along with a countdown timer). Once the timer hits zero the Win32Shutdown() WMI method is run to Force log-off all users so the deployment can proceed
This script could easily be turned into a function that passed along a parameter for Prod/Test/Dev environments.
Enjoy…
#Load Active Directory Module Import-Module ActiveDirectory; [int]$timeleft = 5 #Countdown time until Logoff (Mins) [System.Reflection.Assembly]::LoadWithPartialName("System.Diagnostics") $countdowntimer = new-object system.diagnostics.stopwatch #Establish prodservers array + Enumerate all servers with a name starting with "PROD" and add to array [array] $prodservers= @() Get-AdComputer -filter 'Name -like "PROD*"' -SearchBase "OU=Servers,DC=resdevops,DC=com" -Properties "Name" | foreach-object { $prodservers += $_.Name } while($timeleft -gt 0) { $countdowntimer.start() foreach ($server in $prodservers) {msg * /SERVER:$server "A software deployment is scheduled for the PROD environment; Your remote session will be logged off automatically in $timeleft minutes, you should save your work."} while ($countdowntimer.elapsed.minutes -lt 1) {write-progress -activity "Elapsed Time" -status $countdowntimer.elapsed} $countdowntimer.reset() $timeleft-- } #Once countdown is complete - Run Win32Shutdown WMI method with the "4" value #to force loggof all users foreach ($server in $prodservers) { Write-Host "Logging all users off of $server" (gwmi win32_operatingsystem -ComputerName $server).Win32Shutdown(4) } Write-Host "`n`nSent Logoff command to $($prodservers.count) servers" -foregroundcolor Green;-Patrick
Apprecaited this!
Can you make the script search all servers under one OU for a spesific user and then log off that user only?
K.
Hi Ketil,
Yep, you can certainly search within an OU!
In order to log off a specific user you would need to do something more crafty. Because I’m using the Win32Shutdown(4) method it forcefully logs everyone off.
You could potentially get a users Session ID (SID) and log off that user using a similar WMI command?
-Patrick