One of the first things I do when provsioning a new server is:
- configure the network card, assign an IP address
- define a proxy
- configure Windows Update settings
- Download and install all security udpates
Every IT-pro has his own list. The Microsoft PowerShell MVP Jeffery Hicks says for example on this page: Windows Server 2012: First Five Fixes
I assume you will do the following tasks by default when setting up a new Windows Server 2012 system:
* Configure computer name
* Configure networking
* Install features and roles
* Run Windows Update
I’m not going to cover those as I think they are pretty self-evident in the Server Manager GUI, but I do have 5 additional “fixes” that I’ve been using.
He’s right for a GUI environment but it isn’t very straight forward for the Core Edition or when you’ve to automate it.
I’ve already presented how to get and set a proxy server using powershell on this page: https://p0w3rsh3ll.wordpress.com/2012/10/07/getsetclear-proxy/
Recently the Microsoft MVP Jan Egil Ring presented on the Hey Scripting guy’s blog how to Use PowerShell to Configure the NIC on Windows Server 2012
For listing and configuring Windows updates settings, currently I only know the excellent work done by Boe Prox for corporate environments. Here are some links to the great resources Boe shared and still maintains:
- Learn how to use the WSUS Update Scope with Windows PowerShell to get update status information for client computers
- The Get-ClientWSUSSetting script that:
allows you to query a system or systems to find the wsus client settings. This performs a registry lookup for both the Environment and Configuration keys and allows you to specify if you prefer to view one of the other.
- The Set-ClientWSUSSetting script that
allows you to configure one or more system’s automatic updates client by manipulating the registry settings assoicated with each setting.
- PoshWSUS,
a module designed to help fill in a gap where a System Administrator can perform WSUS commands against the server via the command line vs working using the GUI.
- On the Hey Scripting guy’s blog he shows how to use Windows PowerShell to install WSUS and configure clients for updates.
- He also recently demonstrated the Client and patch management using the UpdateServices module on a PowershellMagazine blog post.
- PoshPAIG (PowerShell Patch Audit/Installation GUI)
allows you to easily audit and install patches on your servers in the network by providing a graphical interface to select which servers to audit/install and to generate reports for the systems.
But this isn’t exactly what I was looking for, espcially for Non–Active Directory environments. I also wanted a console output where I don’t need to know that AUoptions represents the behavior of Automatic udpates notifications and that a value of 4 means that it should “install updates automatically”.
I didn’t want a script for Managing Windows Update with PowerShell that doesn’t take into account group policy (GPO) settings.
Even the module written by Michal Gajda and presented by Ed Wilson in the following Hey scripting guy’s blog post didn’t propose a solution to read the Windows update settings.
So I’ve been using the following resources to write my own function.
-
Configure Automatic Updates in a Non–Active Directory Environment
http://technet.microsoft.com/en-us/library/cc708449%28WS.10%29.aspx - How to configure automatic updates by using Group Policy or registry settings
http://support.microsoft.com/kb/328010
I also wanted the function to work on a freshly installed computer where Windows Updates settings haven’t been configured yet.
Function Get-WUSettings { [cmdletbinding()] Param( [switch]$viaRegistry=$false ) Begin { # Get the Operating system $OSVersion = [environment]::OSVersion.Version # Initialize object $WshShell = New-Object -ComObject Wscript.Shell $polkey = 'HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' $stdkey = 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' } Process { if ($viaRegistry) { try { $AUEnabled = $WshShell.RegRead("$polkey\NoAutoUpdate") } catch { # if this value is absent, it means it's turned on $AUEnabled = 0 } Switch ($AUEnabled) { 1 {$AUEnabled = $false} 0 {$AUEnabled = $true } } try { $AUOptions = $WshShell.RegRead("$polkey\AUOptions") } catch { try { $AUOptions = $WshShell.RegRead("$stdkey\AUOptions") } catch { $AUOptions = 0 } } Switch ($AUOptions) { 0 {$AUNotificationLevel = 'Not Configured'} 1 {$AUNotificationLevel = 'Never check for updates'} 2 {$AUNotificationLevel = 'Notify Before Download'} 3 {$AUNotificationLevel = 'Notify Before Installation'} 4 {$AUNotificationLevel = 'Install updates automatically'} } try { $IncludeRecommendedUpdates = $WshShell.RegRead("$polkey\IncludeRecommendedUpdates") } catch { # if the value is absent we get it from $IncludeRecommendedUpdates = $WshShell.RegRead("$stdkey\IncludeRecommendedUpdates") } Switch ($IncludeRecommendedUpdates) { 0 {$GetRecommendedUpdates = $false} 1 {$GetRecommendedUpdates = $true} } try { $UseWUServerVal = $WshShell.RegRead("$polkey\UseWUServer") } catch { # if the value doesn't exist, it means that we don't use a WSUS server $UseWUServerVal = 0 } Switch ($UseWUServerVal) { 1 {$UseWUServer = $true} 0 {$UseWUServer = $false } } # Create a default object with a subset of properties $obj = New-Object -TypeName psobject -Property @{ 'Is Automatic Update Enabled' = $AUEnabled 'Use a WSUS Server' = $UseWUServer 'Automatic Updates Notification' = $AUNotificationLevel; 'Receive recommended udpates' = $GetRecommendedUpdates; } if ($OSVersion -lt [version]'6.2') { try { $ScheduledInstallDay = $WshShell.RegRead("$polkey\ScheduledInstallDay") $ScheduledInstallTime = $WshShell.RegRead("$polkey\ScheduledInstallTime") } catch { try { $ScheduledInstallDay = $WshShell.RegRead("$stdkey\ScheduledInstallDay") $ScheduledInstallTime = $WshShell.RegRead("$stdkey\ScheduledInstallTime") } catch { # Absent = Every Day @3 AM but I prefer to leave it blank in the returned object } } Switch ($ScheduledInstallDay) { 0 {$InstallDay = 'Every Day'} 1 {$InstallDay = 'Every Sunday'} 2 {$InstallDay = 'Every Monday'} 3 {$InstallDay = 'Every Tuesday'} 4 {$InstallDay = 'Every Wednesday'} 5 {$InstallDay = 'Every Thursday'} 6 {$InstallDay = 'Every Friday'} 7 {$InstallDay = 'Every Saturday'} } if ($ScheduledInstallTime) { $InstallTime = New-TimeSpan -Hours $ScheduledInstallTime } $obj | Add-Member -MemberType NoteProperty -Name 'Install Frequency' -Value $InstallDay $obj | Add-Member -MemberType NoteProperty -Name 'Install Time' -Value $InstallTime } else { # These properties don't exist anymore on Windows 8 } # Add extra properties if ($UseWUServer) { try { $WUServer = $WshShell.RegRead('HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\WUServer') $WUStatusServer = $WshShell.RegRead('HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\WUStatusServer') } catch { # we silently fail } $obj | Add-Member -MemberType NoteProperty -Name 'WSUS Server' -Value $WUServer $obj | Add-Member -MemberType NoteProperty -Name 'WSUS Status URL' -Value $WUStatusServer } try { $OptinGUID = $WshShell.RegRead('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\DefaultService') } catch { # Fail silently } if ($OptinGUID -eq '7971f918-a847-4430-9279-4a52d1efe18d') { $obj | Add-Member -MemberType NoteProperty -Name "Opted-in Microsoft Update" -Value $true } else { $obj | Add-Member -MemberType NoteProperty -Name "Opted-in Microsoft Update" -Value $false } # Return our object $obj } else { # We use Com Object $COMWUSettings = (New-Object -ComObject Microsoft.Update.AutoUpdate).Settings # Settings might be controlled by GPO if ($COMWUSettings.ReadOnly) { # Use the registry Get-WUSettings -viaRegistry:$true break } else { $UseWUServer = $false } Switch ($COMWUSettings.NotificationLevel) { 0 {$AUNotificationLevel = 'Not Configured'} 1 {$AUNotificationLevel = 'Never check for updates'} 2 {$AUNotificationLevel = 'Notify Before Download'} 3 {$AUNotificationLevel = 'Notify Before Installation'} 4 {$AUNotificationLevel = 'Install updates automatically'} } $isAUenabled = (New-Object -ComObject Microsoft.Update.AutoUpdate).serviceEnabled $obj = New-Object -TypeName psobject -Property @{ 'Is Automatic Update Enabled' = $isAUenabled 'Automatic Updates Notification' = $AUNotificationLevel; 'Use a WSUS Server' = $UseWUServer 'Receive recommended udpates' = $COMWUSettings.IncludeRecommendedUpdates; } if ($OSVersion -lt [version]'6.2') { Switch ($COMWUSettings.ScheduledInstallationDay) { 0 {$InstallDay = 'Every Day'} 1 {$InstallDay = 'Every Sunday'} 2 {$InstallDay = 'Every Monday'} 3 {$InstallDay = 'Every Tuesday'} 4 {$InstallDay = 'Every Wednesday'} 5 {$InstallDay = 'Every Thursday'} 6 {$InstallDay = 'Every Friday'} 7 {$InstallDay = 'Every Saturday'} } if ($COMWUSettings.ScheduledInstallationTime) { $InstallTime = New-TimeSpan -Hours $COMWUSettings.ScheduledInstallationTime } $obj | Add-Member -MemberType NoteProperty -Name 'Install Frequency' -Value $InstallDay $obj | Add-Member -MemberType NoteProperty -Name 'Install Time' -Value $InstallTime } else { # not available on W8 } (New-Object -ComObject Microsoft.Update.ServiceManager).services | ForEach-Object { if ($_.IsDefaultAUService) { $OptinGUID = $_.ServiceID } } if ($OptinGUID -eq '7971f918-a847-4430-9279-4a52d1efe18d') { $obj | Add-Member -MemberType NoteProperty -Name "Opted-in Microsoft Update" -Value $true } else { $obj | Add-Member -MemberType NoteProperty -Name "Opted-in Microsoft Update" -Value $false } # return $obj } } End {} }
Here’s what I get on the Windows 7 computer I use at home:
Here’s what I get on the Windows 8 computer I use at home:
Hi There – Is tehre anyway to get this to accept pipelined input? This fills a big need we have perfectly – except for that one small part…I need this run against groups of servers… Thanks in advance!
Yes, there is but for what parameter? For a ComputerName parameter to target a remote computer?
Actually, there’s a more simple way to achieve this w/o modifying the code.
Copy/paste the code into a .ps1 file, get rid of the function statement by removing the first and last line of the code.
Thats perfect – Worked great, Thanks! I had tried that but had forgot to take out the function line!
Will this only work for machines that are not on a domain and not governed by GPO’s?
It will work on both computers whether joined to a domain or not. And it will report the correct settings either set by GPO or not.
Hi,
you can help me with the following…?
When run the function or the script among server groups the output not show something values.
Remote Servers Groups by: Invoke-Command -ComputerName $Servers -FilePath .\Get-WUSettings.ps1
Receive recommended udpates :
Is Automatic Update Enabled :
Automatic Updates Notification :
Use a WSUS Server : False
Opted-in Microsoft Update : False
PSComputerName : SRVDC01
RunspaceId : 1dffc724-fa5b-4451-be4d-755d68ca136a
Receive recommended udpates :
Is Automatic Update Enabled :
Automatic Updates Notification :
Use a WSUS Server : False
Opted-in Microsoft Update : False
PSComputerName : SRVFILE01
RunspaceId : bced6e95-a1a2-43a3-84fe-17e838a93df6
Locally on server SRVDC01: Get-WUSettings
Receive recommended udpates : True
Is Automatic Update Enabled : True
Automatic Updates Notification : Notify Before Installation
Use a WSUS Server : False
Opted-in Microsoft Update : False
Thanks!!
Hi,
Yes, I can help 🙂
I was able to reproduce the behavior you mentioned.
Running the comObject through remoting doesn’t work very well.
To override this shortcoming, you can create a file Get-WUSettings.ps1, copy/paste the above function and add the following line after the function:
And then you use the file the way you did with the invoke-command cmdlet.
Hello,
I know it has been a few years, since you published this, however, I would appreciate some help. I’m trying to ruin the script but I get nothing in return, the prompt comes back expecting another command.
O’m executing the script as depicted in the examples in the images.
Hi,
Yes, I may help.
On what version on Windows do you run the script ? Is it Windows 10 or Server 2016 ?
Currently there’s a hardcoded value that limits it because I wrote the script when these OS weren’t released yet.
Hello,
I’m running the script on Windows 7
Ok,
Can you try the following?
I got nothing, below is a snipet of the results
PS C:\utils\scripts> .\Get-WUSettings.ps1 -viaregistry:$true
PS C:\utils\scripts>
Oh, I see you copy/pasted the above function into a file Get-WUSettings.ps1.
If, yes, try the following:
Does this make a difference?
It worked, thank you.
hi, how do i run the script to remote multiple servers and will be output as .csv or .txt
Thank you
Hi,
Copy/paste the code into a .ps1 file, get rid of the function statement by removing the first and last line of the code and do:
I’m not sure I will have any luck but I’ll ask anyway :). I am not able to use invoke-command to run this against multiple remote servers. The environment doesn’t allow it. Is there some way I can just get the Windows Update Settings which is all I’m looking for on remote systems without invoke-command? I usually have to run wmi calls. There are other scripts out there that can pull back information but yours is more readable to my manager who is requesting this information.
Invoke-Command uses Powershell remoting. If it doesn’t work, it means remoting is not enabled on the targeted endpoint/server/node/workstation. If you’re in a domain environment, remoting uses by default kerberos for authentication and any data carried by PSRemoting over the network is encrypted. While WMI works fine, it’s now considered legacy (it uses DCOM) while PS remoting is considered as a modern and a more secure remote management method.
It’s possible to rewrite the part of the function that reads the registry and make it do it using wmi calls. It would be feasible but ugly.
You may deliver more value and have (all future) management tasks done faster, easier and in a more secure way, if you first have PSRemoting enabled everywhere and configured correctly (btw, “enabled” doesn’t mean it has to accept any incoming connection). Address first this major management issue and convince your boss that this should be a top priority for both of you.
Ok thank you and I fully agree and have made the argument. Time I try again. BTW, this is pretty awesome tyvm for the work and response.
You might try running it in this fashion. Edit the script to send email results or drop a result file to a domain file share. Use a GPO to push the script file out to all your remote machines, along with a scheduled task to run the now-local .ps1 script.
Im wondering if you can help me, im trying to run this on Windows Server 2016, it tells me that Windows Updates is set to Automatic, but when I run sconfig, sconfig tells me it is set to manual?
Yes, I can probably help you. Does the function w/o parameter and with the viaRegistry parameter have the same output?
I’ll have a look at a sconfig on a Windows 2016 server and will report back what sconfig does.
Here’s the vbscript function in sconfig.vbs that checks for the value displayed in the menu next to the entry about “Windows Update Settings”

If the value NoAutoUpdate is present under”HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU”, it will display “Manual”
If the value NoAutoUpdate is not present, it will start looking at the AUOptions under HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU