今更ならがらWindows10へのアップグレード広告を切るスクリプト

# はじめに
このスクリプトは自己責任で実行し、いかなる責任も当方は負わないことを宣言します。

# MSの広告戦略とアップグレード
Windows7sp1とWindows8.1update1を使っている方には昨年よりWindows10へのアップグレードを案内する広告が表示されていることはご存知だと思われます。その少々強引すぎる手法により一時話題にもなりました。
またアップグレード期間が７月末ということでいままで表示されていなかったWindows7(spなし)やWindows8にも全画面広告が表示されることになりました。
裁判を経ていわゆる『強制』アップグレードの案内は収まりつつありますが、ここで広告を表示しているGWX及び関連したWindowsUpdateをアンインストールするスクリプトを公開したいと思います。

すでに同様の機能は各種フリーソフトとして配布されて何番煎じになっているか分からないのですが。。。

# スクリプト
基本はバッチファイルで、一部にPowershellを使っています。管理者権限を要求しますので管理者としてログインして実行してください。

```bash:DisableGWX.cmd
@echo off && setlocal
set "cache=%temp%\%~nx0"

CLS
IF NOT EXIST "%cache%" (
ECHO.
ECHO ***********************************
ECHO Caching scripts
ECHO ***********************************
copy "%~0" "%cache%"
) ELSE GOTO :is_cache

:is_cache
IF NOT "%~0"=="%cache%" (
ECHO.
ECHO ***********************************
ECHO Run script form cache
ECHO ***********************************
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process %cache%"
exit /b
) ELSE goto :is_admin

:is_admin
date %date% >nul 2>&1
IF NOT '%errorlevel%' == '0' (
ECHO.
ECHO ***********************************
ECHO Invoking UAC to escalate privilege
ECHO ***********************************
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process %cache% -Verb runas"
exit /b
) ELSE goto :main 

:main
CLS
ECHO.
ECHO ***********************************
ECHO MAIN SCRIPT START.
ECHO ***********************************
cd /d %temp%

ECHO.
ECHO ***********************************
ECHO Stop Windowns Update
ECHO ***********************************
net stop wuauserv
net stop cryptSvc
net stop bits
net stop msiserver

ECHO.
ECHO ***********************************
ECHO Killing GWX.exe and GWXUX.exe
ECHO ***********************************
taskkill /f /t /im gwx.exe
taskkill /f /t /im gwxux.exe

ECHO.
ECHO ***********************************
ECHO Disabling GWX and OSUpgrade
ECHO ***********************************
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Gwx" /v "DisableGwx" /t REG_DWORD /d 00000001 /f
reg add "HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate" /v "DisableOSUpgrade" /t REG_DWORD /d 00000001 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\OSUpgrade" /v "AllowOSUpgrade" /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\OSUpgrade" /v "ReservationsAllowed" /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\GWX.exe" /v "Debugger" /t REG_SZ /d "rundll32.exe" /f

ECHO.
ECHO ***********************************
ECHO Removing GWX Downloading cache
ECHO ***********************************
start /wait takeown /F C:\$Windows.~BT\* /R /A /D Y
start /wait icacls C:\$Windows.~BT\*.* /T /grant administrators:F
rmdir /S /Q C:\$Windows.~BT\

start /wait takeown /F C:\$Windows.~WS\* /R /A /D Y
start /wait icacls C:\$Windows.~WS\*.* /T /grant administrators:F
rmdir /S /Q C:\$Windows.~WS\

ECHO.
ECHO ***********************************
ECHO Restart Windowns Update
ECHO ***********************************
start /wait net start wuauserv

ECHO.
ECHO ***********************************
ECHO Uninstall and Hide KBs
ECHO ***********************************
@powershell "$s=[scriptblock]::create((gc \"%~f0\"|?{$_.readcount -gt 93})-join\"`n\");&$s" %*
exit /b

REM POWERSHELL SCRIPT BLOCK
$KBNumbers = 2876229,2952664,2976978,2977759,2990214,3021917,3022345,3035583,3044374,3068708,3075249,3080149,3123862,3150513,3173040

[Boolean]$ErrFound = $false
$ComputerName = $env:COMPUTERNAME
# Uninstall
$hotfixes = Get-WmiObject -ComputerName $ComputerName -Class Win32_QuickFixEngineering | select hotfixid
Foreach ($KBNumber in $KBNumbers) {
  Write-Host "Checking whether update $KBNumber needs to be uninstalled"
  $KBID = "KB"+$KBNumber
  if($hotfixes -match $KBID) {
      Write-host "Found update $KBNumber. Uninstalling."
      $UninstallString = "cmd.exe /c wusa.exe /uninstall /KB:$KBNumber /quiet /norestart"
      Write-Host "Executing '($UninstallString)'"
      ([WMICLASS]"\\$ComputerName\ROOT\CIMV2:win32_process").Create($UninstallString) | out-null            
      while (@(Get-Process wusa -computername $ComputerName -ErrorAction SilentlyContinue).Count -ne 0) {
          Start-Sleep 3
          Write-Host "Waiting for update removal to finish ..."
      }
    Write-Host "Completed the uninstallation of update $KBNumber"
  }
  else {            
    Write-Host "Update $KBNumber not installed so no uninstall needed"
  }            
  Write-Host "-----------"
} # Foreach $KBNumber
# Hide (block) the update
try {
  Write-Host "Listing Windows Update List..."
  $UpdateSession = New-Object -ComObject Microsoft.Update.Session
  $UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
  $UpdateSearcher.IncludePotentiallySupersededUpdates = $true
  $SearchResult = $UpdateSearcher.Search("IsInstalled=0")
  Foreach ($KBNumber in $KBNumbers) {
    Write-Host "Checking whether update $KBNumber needs to be hidden"
    [Boolean]$KBListed = $false
    Foreach ($Update in $SearchResult.updates) {
      Foreach ($KBArticleID in $Update.KBArticleIDs) {
        # Next line is for debugging
        # Write-Host "$KBArticleID, $($Update.IsHidden), $($Update.title)"
        if ($KBArticleID -eq $KBNumber) {
          $KBListed = $true
          if ($Update.IsHidden -eq $false) {
            Write-Host "Hiding update $KBNumber (UpdateID $($Update.Identity.UpdateID), deployed $($Update.LastDeploymentChangeTime.ToString('MM/dd/yyyy')))"
             $Update.IsHidden = $true     
          } else {
            Write-Host "Update $KBNumber (UpdateID $($Update.Identity.UpdateID), deployed $($Update.LastDeploymentChangeTime.ToString('MM/dd/yyyy'))) is already hidden"
          } # if $Update.IsHidden
        } # if $KBArticleID -eq $KBNumber
      } # Foreach $KBArticleID
    } # Foreach $Update
 
    if ($KBListed -eq $false) {
      Write-Host "Update $KBNumber was not found searching Windows Update"
    }
    Write-Host "-----------"
  } # Foreach $KBNumber
 
  Write-Host ""
  $objAutoUpdateSettings = (New-Object -ComObject "Microsoft.Update.AutoUpdate").Settings
  $objSysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
  if ($objSysInfo.RebootRequired) {
    Write-Host "A reboot is required to complete the process"
  } else {
    Write-Host "No reboot is required"
  }
 
  Write-Host ""
  Write-Host "Script execution succeeded"
  $ExitCode = 0
}
catch {
  Write-Host ""
  $error[0]
  Write-Host ""
  Write-Host "Hiding update(s) failed"
  $ExitCode = 1001
}

Write-Host "Finished pathing..."
```