WSUSなしでWindows 10の広告をWindows Updateから非表示にする

先月頃から、Windows 7の通知領域に「Windows 10を入手する」とか「無料アップグレードを予約」とかいう邪魔なMicrosoftの広告が入るようになってきた。 社内SEとしてはユーザに勝手にOSをアップグレードされるわけにはいかないので、消し去りたい。

ネットを探してみると、やはり同様の悩みを持つ人は多いらしく、結論としては、

  1. GWX.exeとGWXUX.exeをタスクマネージャで強制終了する
  2. インストールされたWindows Updateの「KB3035583」をアンインストールする
  3. 再度Windows Updateがインストールさせようとしてくるので、KB3035583を右クリックして「非表示」にする

ということらしい。 → 参考サイト: 「Windows10を入手する」の通知が消えない\(^o^)/

さて、1人社内SEとしては以上の手順をユーザの全PCに行うのは無理なので、なんとか自動化したい。 1と2についてはコマンドプロンプトで可能なので、あっさり情報が見つかり、

Taskkill /IM GWX.exe /F
Taskkill /IM GWXUX.exe /F
wusa.exe /uninstall /kb:3035583 /quiet /norestart

と書いたバッチファイルをログオンスクリプトに仕込むことで可能だった。

問題は3の何度アンインストールしても再インストールさせようとしてくる点。 根本的な解決策はもちろんWSUSサーバを立てて、KB3035583を承認しなければ良い。

だが、私の会社にはWSUSサーバはない。 レジストリをいじったりして特定のWindows Updateを非表示にする方法がないか、と調べてみたら、 Windows Update Agent APIというのがあることを発見。

英語の情報しかなかったが、サンプルを参考に目的の「KB3035583」を非表示にするスクリプト(今回はJavaScript)を書いてみた。

/**********************************************************************
 WSUSを使用せずに不必要なWindowsUpdateを非表示
 
 Copyright 2015-2016 330k
 使用は自己責任でお願いします
**********************************************************************/
try{
  // インストールしないWindowsUpdateのKB番号
  var disabledKBs = [
    2876229,
    2952664,
    2976978,
    2977759,
    3021917,
    3022345,
    3035583,
    3068708,
    3075249,
    3080149,
    3123862,
    3150513,
    2990214,// Win 7
    3050265,
    3065987,
    3075851,
    3083324,
    3083710,
    3102810,
    3112343,
    3135445,
    3138612,
    3161608,
    3044374,// Win 8.1
    3050267,
    3065988,
    3075853,
    3083325,
    3083711,
    3102812,
    3112336,
    3135449,
    3138615,
    3161606
  ].sort().reverse();
  
  var disabledKBregexp = new RegExp('(' + disabledKBs.join(')|(') + ')');
  var updateSession, updateSearcher, searchResult, update;
  var objShell = WScript.CreateObject("WScript.Shell");
  //var fso = new ActiveXObject("Scripting.FileSystemObject");
  var i, j;
  
  // WUA生成
  updateSession = WScript.CreateObject("Microsoft.Update.Session");
  updateSession.ClientApplicationID = "info.330k.disable_wupdate.20160626";
  
  // 既にインストールされているかもしれないので、まずアンインストールする
  for(i = 0; i < disabledKBs.length; i++){
    log("uninstall: " + disabledKBs[i]);
    objShell.Run("wusa.exe /uninstall /kb:" + disabledKBs[i] + " /quiet /norestart", 0, true);
  }
  
  // 未インストールの場合は非表示にする
  log("search updates which are not installed yet");
  updateSearcher = updateSession.CreateUpdateSearcher();
  searchResult = updateSearcher.Search("IsInstalled=0 and IsHidden=0");
  log("updates found: " + searchResult.Updates.Count);
  for(i = 0; i < searchResult.Updates.Count; i++){
    update = searchResult.Updates.Item(i);
    for(j = 0; j < update.KBArticleIDs.Count; j++){
      log("found:\t" + update.KBArticleIDs.Item(j));
      if(disabledKBregexp.test(update.KBArticleIDs.Item(j))){
        log("hide:\t" + update.KBArticleIDs.Item(j));
        update.IsHidden = true;
        break;
      }
    }
  }
  log("finish");
  WScript.Quit(0);
  
}catch(e){
  log(e.message);
  WScript.Quit(1);
}

// CScriptで実行された場合のみログを表示する
function log(message){
  if(/cscript\.exe$/i.test(WScript.FullName)){
    WScript.Echo((new Date()).toLocaleString() + "\t" + message);
  }
}

今後KB3035583以外にも非表示にしたいアップデートが出るかもしれない(多分出る)ので、 追加しやすいよう工夫してみた。

これも同様にログオンスクリプトに仕込んでおけば、ユーザがまだインストールしていなければ非表示にすることができる。

自己責任の下で良ければ使ってください。 ※動作確認したのはWindows 7のみです。Windows 8で動作しなかったらすみません。


Feb. 6 2016 追記

ついにWindows 10が「推奨されるアップデート」になってしまった。

KB3035583以外にもWindows 10がらみのものを削除するよう訂正し、 またすでにインストールされてしまった場合は削除するようにした。


Mar. 27 2016 追記

KB番号を間違えていたので修正(誤2974978 → 正2976978)。

紹介と訂正の記事ありがとうございます(【Win】 特定のKBを非表示にするスクリプト)。 最近は非表示にしていてもいつのまにかインストールされてしまいますが・・・。


Jun. 26 2016 追記

KB番号を追加。CScriptで実行するとログを表示するように改良。

あまりにもWindows 10へのアップグレードがうるさいので、 私の会社ではタスクスケジューラに登録して、3時間に一度実行するように設定した。


Jul. 29 2016 追記

私の会社では無事1台も被害者を出さずに乗り切った。

今後は上記のスクリプトをタスクスケジューラから解除してしばらく様子見。