trying to find out what servers need a reboot by looking at remote registry

Hello! I need to find out what servers in our environment are requiring a reboot.

This code works interactively:

PS> $remoteMachine = "DC1"
$updatehive = reg query "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
if ($updateHive -match "RebootRequired") {write-host "$remoteMachine needs a reboot."} else {write-host "$remoteMachine is OK."}
$remoteMachine = "DC2"
$updatehive = reg query "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
if ($updateHive -match "RebootRequired") {write-host "$remoteMachine needs a reboot."} else {write-host "$remoteMachine is OK."}

DC1 needs a reboot.
DC2 is OK.

The same code does not work in a foreach loop:

PS> $machineList = "\\fp1\install\scripts\servers.txt"
Foreach ($remoteMachine in $machineList)
{   $updatehive = reg query "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    if ($updateHive -match "RebootRequired") {write-output "$remoteMachine needs a reboot."}
}
reg : ERROR: Invalid key name.
At line:3 char:19
+ {   $updatehive = reg query "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Micros ...
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (ERROR: Invalid key name.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
 
OK, maybe I need to build the string first:

PS> $machineList = "\\fp1\install\scripts\servers.txt"
Foreach ($remoteMachine in $machineList)
{   $hivePath = "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    $updatehive = reg query "$hivePath"
    if ($updateHive -match "RebootRequired") {write-output "$remoteMachine needs a reboot."}
}
reg : ERROR: Invalid key name.
At line:4 char:19
+     $updatehive = reg query "$hivePath"
+                   ~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (ERROR: Invalid key name.:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

OK, maybe I need to use native Powershell:

PS> $remoteMachine = "DC1"
PS> $remoteHKLM = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$remoteMachine)
PS> $updateteHive = $remoteHKLM.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update")
PS> if ($updateHive -contains "RebootRequired") {write-output "$remoteMachine needs a reboot."}

nothing. I also tried the following code variants, with the same response - nothing:

PS> $remoteHKLM = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine",$remoteMachine)
PS> $updateteHive = $remoteHKLM.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
PS> if ($updateHive -like "RebootRequired") {write-output "$remoteMachine needs a reboot."}
PS> if ($updateHive -match "RebootRequired") {write-output "$remoteMachine needs a reboot."}

I am stumped. Hopefully there is some substitution rule I don't know about, being a relative newbie.

What I would really like is for the list of servers needing a reboot to be emailed or texted to me if any were found.

Any advice or guidance would be greatly appreciated!

Rob

May 25th, 2015 9:50am

Registry remoting needs firewall open and you need to have correct permissions.  Remote registry service must be running.

You cannot read a file by just using its name:

$machineList = Get-Content \\fp1\install\scripts\servers.txt
Foreach ($remoteMachine in $machineList){ ...

Free Windows Admin Tool Kit Click here and download it now
May 25th, 2015 10:57am

Oh wow, was that stupid - that's what I get for staying up into the wee hours, when I turn into a pumpkin at 2200.

Here's the finished code, nice and tidy:

$rebootList = ""
$serverList = get-content "\\fp1\install\scripts\server.list"
Foreach ($server in $serverList)
{   $updatehive = reg query "\\$server\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    if ($updateHive -match "RebootRequired") {$rebootList = $rebootList + " " + $server}                   }
if ($rebootList -ne "")
{   $smtp = new-object Net.Mail.SmtpClient("mail.miat.edu", 25)
    $smtp.Send(administrator@company.com,"rob@company.com","server pending reboot list: ",$rebootList)    }

This is the first step. My eventual goal is to build a cheap way to monitor critical system stuff, like automatic non-running processes, critical event log entries, disk space, memory, CPU, and email me stuff that's in the red.

If anyone has something like this already, it sure beats reinventing the wheel!

thanks again,

Rob

May 25th, 2015 1:14pm

Here is a much easier way to check for a reboot.  It is extremely fast.

workflow RebootStatus {
	parallel{
		inlinescript {
			$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $PSComputerName)
			$key = $reg.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update')
			if ($key.OpenSubKey('RebootRequired')) {
				[PSCustomObject]@{ $computer = $PSComputerName; RebootRequired = $true }
			} else {
				[PSCustomObject]@{ ComputerName = $PSComputerName; RebootRequired = $false }
			}
		}
	}
	
}

rebootstatus -PSComputerName omega, devws2, w8test



The calls are run in parallel.  No throttling is necessary as PowerShell will tune appropriately.

YOU cannot test inside ot a WF.  Th WF test the connectivity for you.

Free Windows Admin Tool Kit Click here and download it now
May 25th, 2015 2:38pm

jrv,

Thank you for the replies! My script is working for now, I will turbocharge later.  :^)

Right now, I need to solve another issue. I have added to the 'looking for reboot' script to also list for me all servers that have automatic services not running. Here is the code now:

$rebootList = $autolist = ""
$serverList = get-content "\\fp1\install\scripts\server.list"
Foreach ($server in $serverList)
{   $updatehive = reg query "\\$server\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    if ($updateHive -match "RebootRequired") {$rebootList = $rebootList + " " + $server}
    $autostop = Get-WmiObject win32_service -Filter "startmode = 'auto' AND state != 'running'" -ComputerName $server | select $server, name, startname, exitcode | ft -AutoSize
    if ($autostop -ne  "") {$autolist = $autolist + $autostop}   }
if ($rebootList -ne "")
{   $smtp = new-object Net.Mail.SmtpClient("mail.miat.edu", 25)
    $smtp.Send(administrator@company.com,"rob@company.com","server health check: ","reboot: " + $rebootList + "`r`n`n" + $autolist)    }

Kind of crude but it works. My problem is adding the service lists to a cumulative service list. The individual $autostop output looks like this: (and I really like the fact that I can add a variable to the table header!)

FP1 name                           startname                   exitcode
--- ----                           ---------                   --------
    clr_optimization_v4.0.30319_32 LocalSystem                        0
    SysmonLog                      NT Authority\NetworkService        0

I was hoping to concatenate all output to a single file with the server name in the first column.

Instead, the $autolist output looks like this:

 Microsoft.PowerShell.Commands.Internal.Format.FormatStartData Microsoft.PowerShell.Commands.Internal.Format.GroupStartData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Micro
soft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData Microsoft.PowerShell.Commands.Internal.Format.GroupEndData Microsoft.Pow
erShell.Commands.Internal.Format.FormatEndDataMicrosoft.PowerShell.Commands.Internal.Format.FormatStartData Microsoft.PowerShell.Commands.Internal.Format.GroupStartData Microsoft.PowerShell.C

Obviously I'm formatting this wrong, but I can't figure out how - something to do with outputting this to a string?Rob

May 25th, 2015 3:38pm

hint:

$autolist = $autolist |Out-String

Start by learning how to format code so it is readable.  I don't think any of us want to try to decode you confusing typing with no spaces.

Free Windows Admin Tool Kit Click here and download it now
May 25th, 2015 3:55pm

"Start by learning how to format code so it is readable. "

Do you mean "learn how to use the 'insert code' feature of the forum", or do you mean "learn how to write code that is readable"?

"I don't think any of us want to try to decode you confusing typing with no spaces."

Do you mean the last example I gave of $autolist output? Do you mean I am confusing typing with spaces? Should "you" be "your"?

In any event, I as a newbie am confused. I understand that $autostop is an object and $autolist is a string, and I need it as a string not an object, and when I add $autostop to $autolist I get about 30 lines of gibberish in $autolist that is basically "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" repeated hundreds of times. I don't understand how when I add the readable command $autostop to $autolist, the result is unreadable.

I want $autolist to be a readable text list of non-running automatic services for every server:

WRTERM32 name                           startname                   exitcode
-------- ----                           ---------                   --------
         clr_optimization_v4.0.30319_32 LocalSystem                        0
         SysmonLog                      NT Authority\NetworkService        0


LYNC name                           startname                   exitcode
-------- ----                           ---------                   --------
         clr_optimization_v4.0.30319_32 LocalSystem                        0
         SysmonLog                      NT Authority\NetworkService        0

I tried your 'hint' but get the same results:

$autolist = $autolist | Out-String
Out-String -InputObject $autolist

Please advise.

Rob

May 25th, 2015 11:35pm

Part d'un:

"Start by learning how to format code so it is readable. "

Do you mean "learn how to use the 'insert code' feature of the forum", or do you mean "learn how to write code that is readable"?

No!  I mean learn how to format you code so it is readable. That means learn how to indent and structure you code.

Example - this is more readable:

$machineList=Get-Content \\fp1\install\scripts\servers.txt
foreach($remoteMachine in $machineList){
   $updatehive = reg query "\\$remoteMachine\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
   if ($updateHive -match "RebootRequired"){
       "$remoteMachine needs a reboot."
   }
}

Free Windows Admin Tool Kit Click here and download it now
May 26th, 2015 12:20am

"Start by learning how to format code so it is readable. "

Do you mean "learn how to use the 'insert code' feature of the forum", or do you mean "learn how to write code that is readable"?

"I don't think any of us want to try to decode you confusing typing with no spaces."

Do you mean the last example I gave of $autolist output? Do you mean I am confusing typing with spaces? Should "you" be "your"?

In any event, I as a newbie am confused. I understand that $autostop is an object and $autolist is a string, and I need it as a string not an object, and when I add $autostop to $autolist I get about 30 lines of gibberish in $autolist that is basically "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" repeated hundreds of times. I don't understand how when I add the readable command $autostop to $autolist, the result is unreadable.

I want $autolist to be a readable text list of non-running automatic services for every server:

WRTERM32 name                           startname                   exitcode
-------- ----                           ---------                   --------
         clr_optimization_v4.0.30319_32 LocalSystem                        0
         SysmonLog                      NT Authority\NetworkService        0


LYNC name                           startname                   exitcode
-------- ----                           ---------                   --------
         clr_optimization_v4.0.30319_32 LocalSystem                        0
         SysmonLog                      NT Authority\NetworkService        0

I tried your 'hint' but get the same results:

$autolist = $autolist | Out-String
Out-String -InputObject $autolist

Please advise.

Rob

My point is that you ramble on about a lot of things but you are not asking a question.  Slow down and clear your head. Ask a specific question.  Make your code examples illustrate the issue of your question.  We cannot easily decode a long ramble. 

Start by stating a clear question.  Add simple examples to illustrate.  Most of us wil understand as we have decadesof experience.  If we don't understand we will ask questions to help you clarify.

Don't try to solve "world hunger" in one post.

May 26th, 2015 12:27am

I want $autolist to be a readable text list of non-running automatic services for every server:

$autolist = $autolist | Out-String

The output of Format commands is a collection of formatter objects. To remove them you need to do your own formatting. This is standard and documented for Power

Free Windows Admin Tool Kit Click here and download it now
May 26th, 2015 12:31am

 Get-WmiObject win32_service `
    -Filter "startmode = 'auto' AND state != 'running'"  `
    -ComputerName $server `
    | select-object $server, name, startname, exitcode `
    | ft -auto -wrap >> test2.out
PS C:\> $test2 = get-content "test2.out"
PS C:\> $test2
canexch1 name           startname                   exitcode
-------- ----           ---------                   --------
         DiagTrack      LocalSystem                        0
         RemoteRegistry NT AUTHORITY\LocalService          0
         sppsvc         NT AUTHORITY\NetworkService        0
         wsbexchange    LocalSystem                        0
$smtp.Send(admin@a.com,"rob@b.com","server health check: ",$test2)

In the email I receive:

 canexch1 name           startname                   exitcode -------- ----           ---------                   --------          DiagTrack      LocalSystem                        0          RemoteRegistry NT AUTHORITY\LocalService          0          sppsvc         NT AUTHORITY\NetworkService        0          wsbexchange    LocalSystem                        0 

So, my one simple question: how do I email the output of this get-WmiObject command to myself as readable text, so it looks the same as it did from the command line?

May 27th, 2015 12:12am

I just posted the answer to that above.  Did you even try it?

Use Send-MailMessage as it is easier to use and works better.

You do not need to output to a file and you should not output to a file.

I recommend actually learning how to use PoowerShell instaed of guessing at everything.  It will beeasier for you to understand when someone gives you an answer.

Start here: https://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx?f=255&MSPPError=-2147217396

Free Windows Admin Tool Kit Click here and download it now
May 27th, 2015 12:18am

YOu make a lot of very nasic mistakes caused by not having learned the basics.

Try this;

$myreport= Get-WmiObject win32_service     -Filter "startmode = 'auto' AND state != 'running'"     -ComputerName $server | 
    select-object $server, name, startname, exitcode | 
    Format-Table -auto |
    Out-String



Learn to experiment a little bit at a time until you understand what is happening.  This is the nature of technology and learning how to use computer based system. Use the hel to learn how a CmdLet works and to see the exa

May 27th, 2015 12:30am

Finished product.

$rebootList = $autolist = $diskList = $logList = ""
$yesterday  = (get-date).AddDays(-1)
$serverList = get-content "\\fp1\install\scripts\server.list"
$filterList = "startmode = 'auto' AND state != 'running' AND exitcode !=0"
$crlf       = "`r`n`n"
Foreach ($server in $serverList)
    # servers requiring a reboot
{   $updatehive = reg query "\\$server\HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    if ($updateHive -match "RebootRequired") {$rebootList = $rebootList + " " + $server}
    # servers with autostart processes not running with exitcode not zero
    $autostop = Get-WmiObject win32_service -Filter $filterList -ComputerName $server `
              | select $server, name, startname, exitcode | ft | Out-String
    if ($autostop -ne  "") {$autolist = $autolist + $autostop}
    # servers with System and Application log errors over the last 24 hours (last 20 events only)
    $errLog = Get-Winevent -ComputerName $server `
             -FilterHashtable @{LogName="System","Application"; Level=1,2,3; startTime=$yesterday} -MaxEvents 20 `
            | select $server, ProviderName, ID, LevelDisplayName, Message | ft | out-string
    $logList = $logList + $errLog
    # servers with disks over 75% full
    $serverdisks = Get-WmiObject win32_logicaldisk -Filter "DriveType=3" -ComputerName $server
    foreach ($disk in $serverDisks)
       {   $TotalFree   = [Math]::round($disk.freespace/1GB)
           $TotalSize   = [Math]::round($disk.size/1GB)
           $PercentFree = [Math]::round(($disk.freespace/$disk.size) * 100)
           $Drive = $disk.DeviceID
           $diskTight = "$server - $Drive - $totalSize Gb total, $totalFree Gb / $PercentFree% free" | Out-String
           if ($PercentFree -le 25) {$diskList = $diskList + $diskTight}
       } 
}
$mailbody = "reboot: "                         + $rebootList +$crlf+ `
            "disks over 75%:"              +$crlf+ $diskList +$crlf+ `
            "stopped autostart processes:" +$crlf+ $autolist +$crlf+ `
            "error log events:"            +$crlf+ $logList
Send-MailMessage -from servercheck@a.com -to rob@b.com -subject "server health check: " `
 -body "$mailbody" -smtpServer mail.a.com

The only other thing I would like is for the output to line up in the email like it does interactively, but I would need it to arrive with a non-proportional font, and anyway, it's for IT, not management. It doesn't have to be pretty.

I'm a busy IT consultant who gets paid to manage big picture stuff, and wish I had the luxury to deep dive into anything - I learn just enough to get the job done, or usually hire someone to get the job done, or find others who know more than I do (which is not hard to do...) to tell me how to get it done  :^)

Ah, the life of a jack of all trades, and by default, master of none! Sigh.

Free Windows Admin Tool Kit Click here and download it now
May 29th, 2015 10:12am

You would do yourself a favor by actually learning something yourself rather that relying on others too do it for you.  You would have had this done in less than 5 minutes.  It is sort of a beginners script after all.

Don't you think that 5+ days is a long time for a 5 minute script.

You can also remove about half of the lines and have a much cleaner script.  Also learn how to format a scrip so that it is readable.  It makes it easier too debug.

May 29th, 2015 10:26am

No - I am not picking on you. I am trying to get you to look at what you are doing and realize that you can do a good job.  You do not need to rely on others to do your work for you.

Here is an example of how to approach this.  It stall has a few pretty bad methods for accumulating data but it demonstrates how to structure code for flexibility and readability.

The other plus here is that it can be very easily converted to use HTML and produce a professional looking report.

$mailprops=@{
    From='servercheck@a.com'
    To='rob@b.com'
    Subject='server health check:'
    SmtpServer='mail.a.com'
}

$mailbody = @'
    Reboot: {0}
    Disks over 75%: {1}
    Stopped autostart processes: {2}
    Error log events: {3}
'@

$filterList = "startmode = 'auto' AND state != 'running' AND exitcode !=0"
$filterHash=@{LogName ='System','Application';Level=1,2,3;StartTime=[DateTime]::Today.AddDays(-1)}

$serverList = get-content \\fp1\install\scripts\server.list
Foreach ($server in $serverList){
    
    $updatehive = reg query "\\$server\HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
    if($updateHive -match 'RebootRequired'){
        [array]$rebootList+=$server 
    }
    
    # servers with autostart processes not running with exitcode not zero
    if($autostop = Get-WmiObject win32_service -Filter $filterList -ComputerName $server | 
        select $server, name, startname, exitcode | ft | Out-String){
        $autolist = $autolist + $autostop 
    }
    
    # servers with System and Application log errors over the last 24 hours (last 20 events only)
    $errLog = Get-Winevent -ComputerName $server -FilterHashtable $filterHash -MaxEvents 20 |
        select $server, ProviderName, ID, LevelDisplayName, Message | ft | out-string
    $logList+=$errLog
    
    # servers with disks over 75% full
    $serverdisks = Get-WmiObject win32_logicaldisk -Filter "DriveType=3" -ComputerName $server
    foreach ($disk in $serverDisks) {
        $TotalFree = [Math]::round($disk.freespace/1GB)
        $TotalSize = [Math]::round($disk.size/1GB)
        $PercentFree = [Math]::round(($disk.freespace/$disk.size) * 100)
        $Drive = $disk.DeviceID
        $diskTight = "$server - $Drive - $totalSize Gb total, $totalFree Gb / $PercentFree% free" | Out-String
        if ($PercentFree -le 25) { $diskList = $diskList + $diskTight }
    }
}

$body=$mailbody -f ($rebootlist -join ' '),($disktight),$autolist,$loglist
Send-MailMessage @mailprops -Body $body
You would need to redo the disk and eventlog sections as they will not work as you expect and take too much code to produce a result.

Your script is a valiant attempt at producing a report but would have been much easier if you spent some time learning how to write PowerShell code.  It would save you a lot of time. 

I have spent many years working with Admins.  Most start out like you; arrogant and independent -  "I will figure it out by myself". In the end the successful ones learn how to study the technology they use.

You cannot advance in this technology without learning how to learn effectively. Most experienced Admins read the equivalent of a book a week and constantly practice and experiment with new technologies until they are comfortable with how they work.  It is a skill that is absolutely necessary.

Use the script here and refine it.  Learn how to use code effectively. Read articles on how to format code and how to comment code.  Look at how others have formatted complex reports to send by email.

Here are some articles on how to do fancy mail reports: http://tech-comments.blogspot.com/2012/07/powershell-dynamically-color-posh.html

Free Windows Admin Tool Kit Click here and download it now
May 29th, 2015 11:57am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics