Skip to content

Instantly share code, notes, and snippets.

@imshaiknasir
Created February 12, 2025 14:32
Show Gist options
  • Save imshaiknasir/248846775998add5cfb7f5e933fee121 to your computer and use it in GitHub Desktop.
Save imshaiknasir/248846775998add5cfb7f5e933fee121 to your computer and use it in GitHub Desktop.
# Requires -RunAsAdministrator
# This script checks for Windows Updates and installs them automatically
# Create a log file path
$logPath = "$env:USERPROFILE\Desktop\WindowsUpdateCheck.log"
$date = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
# Function to write to both console and log file
function Write-Log {
param($Message)
Write-Host $Message
Add-Content -Path $logPath -Value $Message
}
# Function to release COM objects
function Release-ComObject {
param($ComObject)
if ($ComObject) {
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($ComObject) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
}
Write-Log "Starting Windows Update check at $date"
Write-Log "----------------------------------------"
try {
# Create Microsoft.Update.Session COM object
$UpdateSession = New-Object -ComObject Microsoft.Update.Session
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
$UpdateDownloader = $UpdateSession.CreateUpdateDownloader()
$UpdateInstaller = $UpdateSession.CreateUpdateInstaller()
Write-Log "Searching for updates..."
# Search for all available updates
$SearchResult = $UpdateSearcher.Search("IsInstalled=0")
# Get count of updates
$Updates = $SearchResult.Updates
$UpdateCount = $Updates.Count
if ($UpdateCount -eq 0) {
Write-Log "No updates found. Your system is up to date."
}
else {
Write-Log "Found $UpdateCount update(s):"
Write-Log ""
# Collection for updates to be installed
$UpdatesToInstall = New-Object -ComObject Microsoft.Update.UpdateColl
# List all updates and add them to installation collection
foreach ($Update in $Updates) {
$UpdateInfo = "Title: $($Update.Title)"
if ($Update.MsrcSeverity) {
$UpdateInfo += "`nSeverity: $($Update.MsrcSeverity)"
}
$UpdateInfo += "`nDescription: $($Update.Description)"
$UpdateInfo += "`nIs Security Update: $($Update.IsMandatory)"
$UpdateInfo += "`n----------------------------------------"
Write-Log $UpdateInfo
if ($Update.EulaAccepted -eq $false) {
$Update.AcceptEula()
}
# Add update to collection
$UpdatesToInstall.Add($Update) | Out-Null
}
if ($UpdatesToInstall.Count -gt 0) {
Write-Log "`nDownloading updates..."
$UpdateDownloader.Updates = $UpdatesToInstall
$DownloadResult = $UpdateDownloader.Download()
Write-Log "Download completed."
Write-Log "Installing updates..."
# Install updates
$UpdateInstaller.Updates = $UpdatesToInstall
$InstallResult = $UpdateInstaller.Install()
Write-Log "`nInstallation Results:"
Write-Log "Successful: $($InstallResult.ResultCode -eq 2)"
Write-Log "Reboot Required: $($InstallResult.RebootRequired)"
if ($InstallResult.RebootRequired) {
Write-Log "`nIMPORTANT: A system restart is required to complete the installation of updates."
# Uncomment the following line if you want automatic restart
# Restart-Computer -Force
}
}
}
}
catch {
Write-Log "Error occurred while processing updates:"
Write-Log $_.Exception.Message
}
finally {
Write-Log "`nUpdate process completed at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Log "========================================`n"
# Clean up COM objects
if ($Updates) { Release-ComObject $Updates }
if ($UpdatesToInstall) { Release-ComObject $UpdatesToInstall }
if ($SearchResult) { Release-ComObject $SearchResult }
if ($UpdateSearcher) { Release-ComObject $UpdateSearcher }
if ($UpdateDownloader) { Release-ComObject $UpdateDownloader }
if ($UpdateInstaller) { Release-ComObject $UpdateInstaller }
if ($UpdateSession) { Release-ComObject $UpdateSession }
# Force immediate exit
exit
}

Automatically install the updates when found. Here's the modified script:

# Requires -RunAsAdministrator
# This script checks for Windows Updates and installs them automatically

# Create a log file path
$logPath = "$env:USERPROFILE\Desktop\WindowsUpdateCheck.log"
$date = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

# Function to write to both console and log file
function Write-Log {
    param($Message)
    Write-Host $Message
    Add-Content -Path $logPath -Value $Message
}

# Function to release COM objects
function Release-ComObject {
    param($ComObject)
    if ($ComObject) {
        [System.Runtime.InteropServices.Marshal]::ReleaseComObject($ComObject) | Out-Null
        [System.GC]::Collect()
        [System.GC]::WaitForPendingFinalizers()
    }
}

Write-Log "Starting Windows Update check at $date"
Write-Log "----------------------------------------"

try {
    # Create Microsoft.Update.Session COM object
    $UpdateSession = New-Object -ComObject Microsoft.Update.Session
    $UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
    $UpdateDownloader = $UpdateSession.CreateUpdateDownloader()
    $UpdateInstaller = $UpdateSession.CreateUpdateInstaller()

    Write-Log "Searching for updates..."
    
    # Search for all available updates
    $SearchResult = $UpdateSearcher.Search("IsInstalled=0")
    
    # Get count of updates
    $Updates = $SearchResult.Updates
    $UpdateCount = $Updates.Count

    if ($UpdateCount -eq 0) {
        Write-Log "No updates found. Your system is up to date."
    }
    else {
        Write-Log "Found $UpdateCount update(s):"
        Write-Log ""
        
        # Collection for updates to be installed
        $UpdatesToInstall = New-Object -ComObject Microsoft.Update.UpdateColl

        # List all updates and add them to installation collection
        foreach ($Update in $Updates) {
            $UpdateInfo = "Title: $($Update.Title)"
            if ($Update.MsrcSeverity) {
                $UpdateInfo += "`nSeverity: $($Update.MsrcSeverity)"
            }
            $UpdateInfo += "`nDescription: $($Update.Description)"
            $UpdateInfo += "`nIs Security Update: $($Update.IsMandatory)"
            $UpdateInfo += "`n----------------------------------------"
            
            Write-Log $UpdateInfo

            if ($Update.EulaAccepted -eq $false) {
                $Update.AcceptEula()
            }
            
            # Add update to collection
            $UpdatesToInstall.Add($Update) | Out-Null
        }

        if ($UpdatesToInstall.Count -gt 0) {
            Write-Log "`nDownloading updates..."
            $UpdateDownloader.Updates = $UpdatesToInstall
            $DownloadResult = $UpdateDownloader.Download()

            Write-Log "Download completed."
            Write-Log "Installing updates..."

            # Install updates
            $UpdateInstaller.Updates = $UpdatesToInstall
            $InstallResult = $UpdateInstaller.Install()

            Write-Log "`nInstallation Results:"
            Write-Log "Successful: $($InstallResult.ResultCode -eq 2)"
            Write-Log "Reboot Required: $($InstallResult.RebootRequired)"
            
            if ($InstallResult.RebootRequired) {
                Write-Log "`nIMPORTANT: A system restart is required to complete the installation of updates."
                # Uncomment the following line if you want automatic restart
                # Restart-Computer -Force
            }
        }
    }
}
catch {
    Write-Log "Error occurred while processing updates:"
    Write-Log $_.Exception.Message
}
finally {
    Write-Log "`nUpdate process completed at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
    Write-Log "========================================`n"
    
    # Clean up COM objects
    if ($Updates) { Release-ComObject $Updates }
    if ($UpdatesToInstall) { Release-ComObject $UpdatesToInstall }
    if ($SearchResult) { Release-ComObject $SearchResult }
    if ($UpdateSearcher) { Release-ComObject $UpdateSearcher }
    if ($UpdateDownloader) { Release-ComObject $UpdateDownloader }
    if ($UpdateInstaller) { Release-ComObject $UpdateInstaller }
    if ($UpdateSession) { Release-ComObject $UpdateSession }
    
    # Force immediate exit
    exit
}

Key changes and features in this version:

  1. Auto-Installation: The script will now automatically:

    • Search for updates
    • Accept EULAs if needed
    • Download updates
    • Install updates
  2. Restart Handling:

    • The script will tell you if a restart is required
    • There's a commented line # Restart-Computer -Force that you can uncomment if you want automatic restarts
  3. Detailed Logging:

    • Shows download progress
    • Shows installation results
    • Indicates if a restart is needed

To use this script:

  1. Save it as Check-And-Install-WindowsUpdates.ps1
  2. Run PowerShell as Administrator
  3. Navigate to the script location
  4. Run: .\Check-And-Install-WindowsUpdates.ps1

Important notes:

  1. The script requires administrator privileges
  2. By default, it won't automatically restart your computer (you can enable this by uncommenting the restart line)
  3. All actions are logged to both the console and a log file on your desktop
@imshaiknasir
Copy link
Author

Encountering a PowerShell execution policy error????

This is a security feature in PowerShell that prevents unauthorized scripts from running. Let's resolve this issue.

To fix this, you have several options:

  1. Temporary Solution (Safest, affects only current PowerShell session):
    Open PowerShell as Administrator and run:
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

Then run your script again:

.\Check-WindowsUpdates.ps1
  1. Permanent Solution (More convenient but slightly less secure):
    Open PowerShell as Administrator and run:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

or

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine

To check your current execution policy:

Get-ExecutionPolicy

Here's what each execution policy means:

  • Restricted: Default policy, doesn't allow scripts to run
  • RemoteSigned: Allows local scripts and requires downloaded scripts to be signed
  • AllSigned: All scripts must be digitally signed
  • Bypass: No restrictions (not recommended for security reasons)
  • Undefined: No execution policy set
  • Unrestricted: Loads all scripts and configuration files

Recommended approach:

  1. Open PowerShell as Administrator (Right-click PowerShell → Run as Administrator)
  2. Set the execution policy to RemoteSigned for your user:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
  1. Type "Y" to confirm the change
  2. Try running your script again:
.\Check-WindowsUpdates.ps1

If you want to revert the changes later for security reasons:

Set-ExecutionPolicy -ExecutionPolicy Restricted -Scope CurrentUser

Note: If you're in a corporate environment, you might need to contact your system administrator as execution policies might be controlled by group policies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment