Disable Auto Windows Updates - 夜莺博客

Disable Auto Windows Updates

原文:Disable Auto Windows Updates — theDXT (Daniel Keer)

Auto Windows updates are annoying especially when left untamed as it will automatically reboot the device be it a workstation or a server. I’ve written a script that can mass disable Windows updates across all devices even if they aren’t domain joined.

Technically you could go in and disabled the Windows Update service but that stops all Windows updates. I don’t think that’s a good idea.

Another way would be to bring up Group Policy Editor and go to Computer Configuration > Administrative Templates > Windows Components > Windows Updates > Configure Automatic Updates and set that to be disabled.

However that option will work for domain joined devices but what about the non domain joined devices. It doesn’t make much sense to go to each device and manually edit the setting via the Local Group Policy Editor. To solve this issue I’ve written a script that could be ran across all devices including domain joined device and would leave other Windows updates settings in place.

When you bring Group Policy Editor and go to Computer Configuration > Administrative Templates > Windows Components > Windows Updates > Configure Automatic Updates and set that to be disabled.

Image 1

What ends up happening is the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU is added and the DWORD NoAutoUpdate is created with the value of 1

You could run a PowerShell command to force that registry key and value into the registry but that creates an issue on systems that have other Windows updates settings as they are saved in the same key.

To avoid that issue I’ve written a PowerShell script that will check if the registry key exists and if the key exists it will only alter NoAutoUpdate if the key doesn’t exist it will make the key and create the DWORD.

Here is all the code for the script

$RegKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU'
$KeyName = 'NoAutoUpdate'
$KeyValue = '1'

if(-not (Test-Path $RegKey)){

    New-Item -Path $RegKey -Force

    New-ItemProperty -Path $RegKey -Name $KeyName -Value $KeyValue -PropertyType DWORD -Force
}else {
Set-ItemProperty -Path $RegKey -Name $KeyName -Value $KeyValue
}

Code language:PowerShell(powershell)
I’ve posted the script on my GitHub here is a link to the specific script https://github.com/thedxt/Powershell/blob/main/Single-Task/DisableAutoUpdates.ps1

What the Registry Setting Actually Does

The option in the Group Policy Editor is a front end for a single value: NoAutoUpdate under the AU policy key. Setting it to 1 tells the Windows Update client to stop scheduling automatic downloads and installs. It does not stop the Windows Update service, delete the scheduled tasks, or prevent an administrator from running updates by hand — and that is the whole point of this approach. Manual patching and WSUS-driven installs keep working; only the unsupervised, reboot-when-you-least-expect-it behaviour is removed.

Two details matter when you script this instead of clicking it. First, the policy key is a machine scope path, so the change applies to every user on the box and survives fast user switching. Second, the AU key frequently contains sibling values such as AUOptions, ScheduledInstallDay and UseWUServer that were placed there by another policy or by a WSUS configuration. Overwriting the key to force one value in is how people accidentally re-point a machine at Windows Update after it was deliberately managed by WSUS — which is exactly why the script below only touches the one value it owns.

The Script, Line by Line

Read the script as three decisions rather than four lines of registry work:

  • Test-Path $RegKey answers "does the policy key already exist on this machine?" That question decides the branch, not the value we are about to set.
  • In the first branch, New-Item -Path $RegKey -Force creates the whole key path, including the intermediate keys that do not exist yet on a machine that has never had a policy applied. -Force makes the command idempotent, so re-running it on a key that already exists does not error.
  • New-ItemProperty ... -PropertyType DWORD -Force then creates NoAutoUpdate as a 32-bit DWORD with the value 1. The type matters: Windows Update reads a DWORD here, and a REG_SZ string that happens to contain "1" is not the same thing to the client.
  • In the second branch, Set-ItemProperty changes only the existing value, leaving AUOptions, UseWUServer and anything else under the key untouched.

That is the entire difference between this script and a one-line reg add: it never recreates a key that already holds someone else's settings.

Choosing Between GPO, Local Policy and the Script

All three routes write the same registry value, so the choice is about coverage and repeatability rather than the end state. A domain GPO is the right answer when every machine is joined and you own the OU structure: one object, centrally reported, and it survives a rebuild. Local Group Policy is fine for a single standalone machine but does not scale — and it is easy to prove a local policy exists yet hard to prove it was not overwritten later. The script covers the awkward middle: workgroup machines, lab hardware, a jump host that is intentionally not joined, and any device where you need the change applied now instead of at the next refresh interval.

In practice most environments want two of the three. Publish the setting as a GPO for the domain, and keep the script for the machines the GPO cannot reach, with the same registry logic so that the two never disagree about what "disabled" means.

Running the Script Across Many Machines

The point of writing this as a script instead of a policy is reach — including machines that are not domain joined and therefore never see a Group Policy Object. For a handful of hosts, PowerShell remoting is enough:

Invoke-Command -ComputerName pc01,pc02,pc03 -FilePath .\DisableAutoUpdates.ps1

For a fleet, keep the list in a file and let the script run in parallel batches:

$Computers = Get-Content .\computers.txt
Invoke-Command -ComputerName $Computers -FilePath .\DisableAutoUpdates.ps1 `
    -ThrottleLimit 32 -ErrorAction Continue

Workgroup machines need two prerequisites before any of this works. First, enable remoting on each target:

Enable-PSRemoting -Force

Second, when the client is not in the same domain or forest, add the targets to the client's trusted hosts list, because Kerberos authentication is unavailable and you will fall back to NTLM:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.*"
Test-WSMan -ComputerName 192.168.1.50

If a login script or a management tool is the better fit for your environment, the same script can be dropped into a GPO computer startup script, an SCCM/Intune remediation script, or an Ansible task — the registry logic does not change, only the transport. Record the result per machine either way; a silent Invoke-Command against forty hosts where six are offline tells you nothing useful unless you redirect the errors to a log.

Verifying the Setting Took Effect

Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name NoAutoUpdate
gpresult /h C:\Temp\gpresult.html

On a local machine the first command should print 1. Through remoting, wrap it so a missing key is reported as a failure instead of an exception:

Invoke-Command -ComputerName $Computers -ScriptBlock {
    $p = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU'
    if (Test-Path $p) { (Get-ItemProperty $p).NoAutoUpdate } else { 'KEY MISSING' }
}

On a client OS you should also see "Some settings are managed by your organization" in the Windows Update page of Settings, and gpresult will confirm whether the change came from local registry policy or an applied GPO. Server 2016 and later behave the same way; what differs is the UI wording, not the registry path.

Rolling Back: Re-enabling Windows Updates

Reversals are as important as the deployment, especially for machines that were patched manually and now need to fall back under normal servicing:

# Return the machine to automatic updates
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name NoAutoUpdate -Value 0

# Or remove the value entirely, leaving other AU settings intact
Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -Name NoAutoUpdate

On domain-joined machines a GPO that sets the same value will simply reapply at the next policy refresh, so change the policy rather than the registry if that is where the original setting came from — gpupdate /force after the edit, then verify with gpresult. Removing the value altogether is the cleaner rollback: it leaves any WSUS or scheduling settings that share the key exactly as they were.

Safer Alternatives: Control the Reboot, Not the Update

Disabling automatic updates completely solves the reboot problem and creates a patching problem, so before you deploy this to a fleet consider whether a narrower setting achieves the same result. The same GPO branch offers a graduated set of choices in Configure Automatic Updates: option 2 downloads and notifies before installing, option 3 downloads and notifies before restarting, and option 4 installs on a schedule you define — typically outside working hours.

Two additional settings close most of the remaining gap. Active hours tells the client when it may not restart, and No auto-restart with logged on users (NoAutoRebootWithLoggedOnUsers) postpones a pending restart as long as somebody is signed in — which is precisely the complaint that makes people reach for the registry in the first place. Where updates must be deferred rather than disabled, Windows Update for Business deadlines, WSUS approval windows or an Intune ring give you reporting and a hard limit on how long a deferral can last.

What Still Updates After You Disable It

  • Manual updates - an administrator clicking "Check for updates" still gets results.
  • WSUS-managed installs driven by a deadline will still apply, because the server-side schedule is unaffected by the local policy value.
  • Microsoft Defender definition updates and other security-only content have their own cadence and can be governed separately.
  • Store applications, Office Click-to-Run and driver packages follow their own update paths and are not covered by NoAutoUpdate.

Treat the setting as "no unsupervised reboots" rather than "this machine is frozen", and document which of those paths remains active in your environment so the next audit does not discover it for you.

Related Guides on This Site

For a fuller PowerShell treatment of the same problem see Windows updates PowerShell script, and if the machines must stay on an older build, read enabling Windows 10 Extended Security Updates so security fixes continue after mainstream servicing ends. On non-persistent VDI, remember that registry changes to a golden image behave differently — see deploying applications on non-persistent VDI for how image and per-user state diverge.