Use PowerShell to Find Servers that Need a Reboot

Use PowerShell to Find Servers that Need a Reboot

  • Comments 9
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to find servers that need to be rebooted.

Hey, Scripting Guy! Question  Hey, Scripting Guy! My boss is a Falstaff sort of character, but every once in a while he does actually have a good idea. When he recently logged on to a server console (don’t ask me why my boss was actually logging on to the console of a server), a message popped up that stated the server needed to reboot to complete installing updates.

No one knows how long the server was in that state. So he “challenged” me (a euphuism for telling me to do it) to write a script that would detect any server on the network that needed to be rebooted following installation of hotfixes. I have looked around at several WMI classes, and searched the Hey, Scripting Guy! Blog, but to no avail. I am hoping you can come up with something that does not entail logging on to 1,000 servers and looking for reboot messages that may pop up (that was Falstaff’s idea—“hey, you can use RDP and not have to physically go to the box,” he said).

—YD

Hey, Scripting Guy! Answer Hello YD,

Microsoft Scripting Guy, Ed Wilson, is here. Well, tomorrow February 21, 2013, at 9:30 PM Eastern Standard Time, I will be on the PowerScripting Podcast with Hal and Jon. It will be awesome, and it is a lot of fun. I have been looking forward to this event for weeks now; ever since the Scripting Wife asked me to be on the show (she does all their scheduling). I am not certain about the wisdom of turning on auto update for 1,000 servers. (I would think you would want to do testing, and the like, prior to pushing out the updates and use System Center or WSUS.)

Find servers that need a reboot

To find all servers that need a reboot, I look for the presence of the following registry key:

HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations

The PendingFileRenameOperations key does not appear if there are no files to rename. The rename operation occurs when a file is replaced, and the replacement file is renamed to take the place of the original file. The registry key is shown in the image that follows.

Image of registry editor

Use the ActiveDirectory module to find all servers

An easy way to find all of the servers is to use the ActiveDirectory module and the Get-ADComputer cmdlet. I am feeling a bit lazy today, so I am just going to get all the computers, choose the OperatingSystem attribute, pipe the results to the Where-Object, and pick up anything that looks like server. Here is the code.

Import-Module ActiveDirectory

$servers = Get-ADComputer -Filter * -Properties operatingsystem |

    Where operatingsystem -match 'server'

Use Invoke-Command to find remote registry keys

Ok, now I need to see if the PendingFileRenameOperations registry key exists or not. There are myriad ways of doing this, but lately, I use the Invoke-Command and the Get-ItemProperty cmdlets to do this sort of thing.

Note   To use a local variable on a remote computer requires using $using in Windows PowerShell 3.0 to make the local variable available on the remote computer. Otherwise, the Invoke-Command cmdlet looks for a variable on the remote computer and you will get a path not found, if you are lucky. If you are unlucky, you will get the value of a variable on the remote computer that does not work and it can be difficult to troubleshoot.

The command shown here uses the Invoke-Command cmdlet to run the command in the ScriptBlock against every server stored in the $servers variable. I use the automatic foreach feature of Windows PowerShell 3.0 to get back the name of each server. I specify the ErrorAction (EA is the alias) of silentlycontinue (0 is the enumeration value), so that no errors arise on the console. Remember the ScriptBlock uses Get-ItemProperty to retrieve the registry key value, and if that registry key does not exist, an error arises. The $using:Path brings in the value of the local $path variable, as $using:name brings in the value of $name. The code is shown here.

Invoke-command -ComputerName $servers.name -Ea 0 -ScriptBlock {

Get-ItemProperty -Path $using:path -Name $using:name}

Now, I use the Select-Object to choose only the computer name and to display whether the registry key exists. Here is the code that does this work:

Select-Object pscomputername, @{

 LABEL='RebootRequired';

 EXPRESSION={if($_.PendingFileRenameOperations){$true}}}

When the script runs, it returns a list of computers needing a reboot. This is shown in the following image.

Image of command output

Because the script returns objects with the computer name in it, the results can be piped to the Restart-Computer cmdlet to perform the restarts.

YD, that is all there is to using Windows PowerShell to find all servers that need a reboot. Join me tomorrow when I will talk about more way cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • If you use a corporate WSUS, you can find out which PCs are pending reboots from that. I wrote this script that will run on a schedule, in the middle of the night, and reboot any that are pending. It has various traps in it so if I run it during the day, interactively, it won't do anything. You get the idea...

    # Script to find computers pending a WSUS reboot (coz someone is still logged-on to it... grrr)

    # and reboot them. OBVIOUSLY, do NOT run this during the day !!!!!

    $interactive = [Environment]::UserInteractive;

    # The above will detect if this is run interactively (as opposed to scheduled task)

    # if interactive, it will NOT reboot anything

    # if non-interactive, eg scheduled task, it will simply report

    [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null

    if (!$wsus) {

           $wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();

    }

    $computerScope = new-object Microsoft.UpdateServices.Administration.ComputerTargetScope;

    $computerScope.IncludedInstallationStates = [Microsoft.UpdateServices.Administration.UpdateInstallationStates]::InstalledPendingReboot;

    $computers = $wsus.GetComputerTargets($computerScope);

    $theTime = Get-Date;

    $computers | foreach-object {

    if ($interactive) {

    write-host $_.FullDomainName;

    } else {

    # bit un-necessary... this can only run in the wee small hours if non-interactive (ie, schtask)

    If($theTime.Hour -lt 7) {

    Restart-Computer $_.FullDomainName -WhatIf; # remove the -Whatif when ready for production

    }

    }

    }

  • Great article Ed!  This topic is near and dear to my heart...  Last year I was asked to determine pending reboot status on a lot of systems in our environment.  As you know, there are several keys that reference a reboot, so I compiled them in to a cool little PowerShell function called Get-PendingReboot, I have it uploaded on the script center:

    gallery.technet.microsoft.com/.../Get-PendingReboot-Query-bdb79542

  • @Andreww you are right, using a corporate WSUS server or System Center is the best way to manage updates for a large (or even for a medium or small) network. I love your script. Thank you for sharing.

  • @Brian Wilhite I am glad you like the article -- and thanks for sharing your way cool function via the Script Repository.

  • This is killing me. This works...for the most part, but only returns our AD server as needing to be rebooted. I can login to several other servers and see the registry key, but those servers don't show up. Why would this only be returning our AD server?

  • @TrevorHall Hmm, just a guess mind you, but do your other servers have WinRM and have you enabled PowerShell Remoting? What is the version of PowerShell, WinRM on those machines. What is the version of PowerShell / Windows you are using to remove from? Rights, Permissions to access the registry key? Unfortunately, there are dozens of potential things that can go wrong.

  • Powershell and WinRM are both 2.0 on the servers. 3.0 on my Win8 machine(running the cmdlet/script from). I have rights to access the registry keys on all servers.

    Powershell remoting - Yes to enabled on the servers. I didn't have this turned on on my machine. Turned on, ran again, and it comes back with the same thing. Just the primary AD server.  Ah......crap. Could this be because this is a Win 2012 server running Powershell and WinRM 3.0 and the rest of our servers are 2008 with 2.0?

  • @TrevorHall No, that should not be it. You can remote from v2 to v3 and vice versa. take a look about remote troubleshooting topic go.microsoft.com/fwlink to see if that will help. You might be running into a 32 bit / 64 bit thing ...

  • Thanks Ed. Looking into this.