Automating ShutdownWithUpdates with Scripts and Task Scheduler
Automating ShutdownWithUpdates lets you install pending Windows updates and power off machines without manual intervention — useful for maintenance windows, lab machines, and overnight updates. This guide shows a reproducible approach using PowerShell scripts and Task Scheduler to run ShutdownWithUpdates reliably and safely.
What “ShutdownWithUpdates” does
- Closes running apps, installs pending quality and feature updates, and then powers off the PC.
- Ensures updates apply without leaving the system in a partially-updated state that needs a manual restart.
Overview of the solution
- Create a PowerShell script that:
- Checks for pending updates.
- Warns or notifies logged-on users (optional).
- Initiates an update-and-shutdown operation.
- Create a Scheduled Task to run the script at desired times with appropriate privileges.
- Optionally add safeguards (user deferral window, logging, retry).
PowerShell script (automated update + shutdown)
Save this as C:\Scripts\ShutdownWithUpdates.ps1. Adjust paths and options as needed.
powershell
# Requires running as Administrator \(logFile</span><span> = </span><span class="token" style="color: rgb(163, 21, 21);">'C:\Scripts\ShutdownWithUpdates.log'</span><span> </span><span></span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value ”===== \(</span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(57, 58, 52);">Get-Date</span><span class="token" style="color: rgb(57, 58, 52);"> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span class="token" style="color: rgb(57, 58, 52);">Format o</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span class="token" style="color: rgb(163, 21, 21);"> Starting ShutdownWithUpdates check ====="</span><span> </span> <span></span><span class="token" style="color: rgb(0, 0, 255);">try</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span></span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;"># 1) Detect if updates are pending using Windows Update COM API</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)updateSession = New-Object -ComObject Microsoft.Update.Session \(updateSearcher</span><span> = </span><span class="token" style="color: rgb(54, 172, 170);">\)updateSession.CreateUpdateSearcher() \(searchResult</span><span> = </span><span class="token" style="color: rgb(54, 172, 170);">\)updateSearcher.Search(“IsInstalled=0 and Type=‘Software’ and IsHidden=0”) \(pendingCount</span><span> = </span><span class="token" style="color: rgb(54, 172, 170);">\)searchResult.Updates.Count Add-Content -Path \(logFile</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Value </span><span class="token" style="color: rgb(163, 21, 21);">"Found </span><span class="token" style="color: rgb(54, 172, 170);">\)pendingCount pending updates.” if (\(pendingCount</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-eq</span><span> 0</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value “No pending updates. Exiting.” exit 0 } # 2) Optional: notify interactive user(s) via a 5-minute toast/message \(notifyMinutes</span><span> = 5 </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">try</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;"># If an interactive session exists, create a popup via msg.exe</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)sessions = quser 2>\(null</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">if</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(54, 172, 170);">\)sessions) { # Send simple message to all sessions msg “System will install updates and shut down in \(notifyMinutes</span><span class="token" style="color: rgb(163, 21, 21);"> minutes. Save your work."</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span><span class="token" style="color: rgb(0, 0, 255);">catch</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span> <span> </span><span class="token" style="color: rgb(57, 58, 52);">Start-Sleep</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Seconds </span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(54, 172, 170);">\)notifyMinutes 60) # 3) Download and install updates \(updatesToInstall</span><span> = </span><span class="token" style="color: rgb(57, 58, 52);">New-Object</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>ComObject Microsoft</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>Update</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>UpdateColl </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">foreach</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(54, 172, 170);">\)update in \(searchResult</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>Updates</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)updatesToInstall.Add(\(update</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">|</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Out-Null</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span> <span> </span><span class="token" style="color: rgb(54, 172, 170);">\)downloader = \(updateSession</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>CreateUpdateDownloader</span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)downloader.Updates = \(updatesToInstall</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value “Downloading updates…” \(downloadResult</span><span> = </span><span class="token" style="color: rgb(54, 172, 170);">\)downloader.Download() Add-Content -Path \(logFile</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Value </span><span class="token" style="color: rgb(163, 21, 21);">"Download result: </span><span class="token" style="color: rgb(57, 58, 52);">\)(\(downloadResult</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span class="token" style="color: rgb(57, 58, 52);">ResultCode</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span> </span> <span> </span><span class="token" style="color: rgb(54, 172, 170);">\)installer = \(updateSession</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>CreateUpdateInstaller</span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span> </span><span class="token" style="color: rgb(54, 172, 170);">\)installer.Updates = \(updatesToInstall</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value “Installing updates…” \(installResult</span><span> = </span><span class="token" style="color: rgb(54, 172, 170);">\)installer.Install() Add-Content -Path \(logFile</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Value </span><span class="token" style="color: rgb(163, 21, 21);">"Install result: </span><span class="token" style="color: rgb(57, 58, 52);">\)(\(installResult</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span class="token" style="color: rgb(57, 58, 52);">ResultCode</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span class="token" style="color: rgb(163, 21, 21);">; RebootRequired=</span><span class="token" style="color: rgb(57, 58, 52);">\)(\(installResult</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span class="token" style="color: rgb(57, 58, 52);">RebootRequired</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span class="token" style="color: rgb(163, 21, 21);">"</span><span> </span> <span> </span><span class="token" style="color: rgb(0, 128, 0); font-style: italic;"># 4) If install succeeded (or reboot required), initiate shutdown with applied updates</span><span> </span><span> </span><span class="token" style="color: rgb(0, 0, 255);">if</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">(</span><span class="token" style="color: rgb(54, 172, 170);">\)installResult.ResultCode -eq 2 -or \(installResult</span><span class="token" style="color: rgb(57, 58, 52);">.</span><span>RebootRequired</span><span class="token" style="color: rgb(57, 58, 52);">)</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value “Initiating shutdown to complete updates…” # Force apps closed after a 60-second warning; change /t to adjust delay shutdown.exe /s /t 60 /f /d p:2:17 /c “Installing updates — system will shut down to finish installation.” } else { Add-Content -Path \(logFile</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Value </span><span class="token" style="color: rgb(163, 21, 21);">"Install did not require reboot or failed. No shutdown."</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span><span></span><span class="token" style="color: rgb(57, 58, 52);">}</span><span> </span><span class="token" style="color: rgb(0, 0, 255);">catch</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">{</span><span> </span><span> </span><span class="token" style="color: rgb(57, 58, 52);">Add-Content</span><span> </span><span class="token" style="color: rgb(57, 58, 52);">-</span><span>Path </span><span class="token" style="color: rgb(54, 172, 170);">\)logFile -Value “ERROR: $_” exit 1 }
Notes:
- The script uses the Microsoft.Update.Session COM API (Windows Update Agent). It requires Administrator privileges.
- ResultCode values: 2 typically means succeeded. Adjust checks for your environment.
- The script logs basic progress to C:\Scripts\ShutdownWithUpdates.log.
Create a Scheduled Task
Use Task Scheduler to run the script with highest privileges.
- Open Task Scheduler > Create Task.
- General:
- Name: ShutdownWithUpdates
- Run whether user is logged on or not
- Check “Run with highest privileges”
- Configure for: Windows ⁄11 (or your OS)
- Triggers:
- New… choose schedule (e.g., Weekly at 2:00 AM on Sundays).
- Actions:
- New…
- Action: Start a program
- Program/script: powershell.exe
- Add arguments: -ExecutionPolicy Bypass -NoProfile -File “C:\Scripts\ShutdownWithUpdates.ps1”
- Conditions:
- (Optional) Start only if the computer is idle for… or only if on AC power.
- Settings:
- Allow task to be run on demand
- If the task fails, restart every X minutes (optional)
- Save and supply admin credentials if prompted.
Safeguards and best practices
- Test manually before scheduling. Run the script in a test VM.
- User deferral: Increase notify time or implement an interactive dismissal mechanism.
- Logging & alerts: Centralize logs or send email on failure.
- Scope: For many machines, use Group Policy, SCCM, or Windows Update for Business for scale.
- Backup critical systems before automating updates.
Troubleshooting quick tips
- Task fails to run: ensure “Run with highest privileges” and correct credentials.
- COM object errors: ensure Windows Update Agent is present and script runs as admin.
- No shutdown: check installResult.RebootRequired and ResultCode values in the log.
Example: quick one-liner Scheduled Task action
Program: powershell.exe Arguments: -ExecutionPolicy Bypass -NoProfile -Command “Start-Process -FilePath ‘C:\Scripts\ShutdownWithUpdates.ps1’ -Verb RunAs”
This setup automates installing updates and powering off systems safely during maintenance windows. Adjust notification, timing, and logging to match your environment.
Leave a Reply