Windows 11でWindows Updateによる更新を手動で停める (前編)

ストップ!
©いらすとや.

Windows 10でもWindows 11でもWindows Updateは非常に邪魔。裏で勝手に更新の有無をチェックして更新作業を始めるのもユーザーが気付かない程度におとなしくやってくれるなら正直全然構わないのだが、Windowsのはとにかくユーザー側の操作が邪魔されるくらいリソース激減でディスクアクセスも派手に行われる。特に貧弱なスペックのPCほどその「圧倒的邪魔」っぷりを実感しやすいかと。

以前はさらに更新作業の過程でほぼ強制的に再起動がかかったりで進行中のユーザーの仕事がメチャクチャにされたこともあったが、それはさすがに非難轟々だったので再起動の先送りができるようになった(みたい)。
幕の途中で舞台の見えるところで美術さんが次の舞台セットの用意を始めたり、役者がまだセリフを喋っているのに時間だからと幕を降ろし始める舞台さん、役者が隅の方に追いやられ舞台スタッフが中央でカーテンコールに応える、そんな舞台イヤだよね。でも、それがWindows。全く裏方としてのOSの分をわきまえていない。

ということで、「Windows Updateを停めたい」というのがこの記事。
ただし、OSを最新状態に保つことは重要なので、決して「Windowsで金輪際更新しないようにしましょう」というものではないので念の為。
あくまでもユーザーが望まないときの勝手な更新をさせないというもの。つまり自身で積極的に更新を行う人向け。
この記事ではWindows 11でやってるけどここ最近のWindows 10も同じ筈。

Windows Updateを停める 1
なんかPCが異常に重くてまともに使えないってなって、確認すると勝手に更新チェックとかダウンロードとか始まってるのフザケンナ。

Windows Updateサービスの停止

Windows Updateを停める 2
スタートボタンを左クリックしてスタートメニュー上部の検索テキストボックスに入力。おそらく文字を入力しようとすると次の画面に切り替わる。

Windows Updateを停める 3
英語で service 、または日本語で サービス と入力する。
すぐに下に検索結果が出るので、「サービス」アプリを選択して「開く」をクリック。ここでは特に「管理者として実行」である必要はない。

Windowsベテランの人は上のようなまどろっこしいのではなく[Win]+[R]から「services.msc」でどうぞ

Windows Updateを停める 4
「サービス」が起動したら縦スクロールして「Windows Update」の行を見つける。おそらく「実行中」になっている筈。実行中とはいっても今何か処理中ということではなく「起動済み」とか「常駐中」とかそんな感じ。

Windows Updateを停める 5
「Windows Update」の行で右クリックして「停止」を選択。

Windows Updateを停める 6
Windows Updateの行の「状態」が「実行中」が消えて空白に変わる。つまり「停止」になった。

Windows Updateを停める 7
再び「Windows Update」の行で右クリックして今度は「プロパティ」を選択。

Windows Updateを停める 8
プロパティ窓の左上の「全般」タブの選択状態(最初から選択されて筈)で、「スタートアップの種類」のドロップダウンメニューから「無効」を選択。
右下の「適用」ボタンと「OK」をクリック。

Windows Updateを停める 9
Windows Updateの行のスタートアップの種類が「無効」になった。

Windows Updateを停める 7
さらにもう一度「Windows Update」の行で右クリックして再び「プロパティ」を選択。

Windows Updateを停める 10
プロパティ窓上部の「回復」タブを選択。
「最初のエラー」が初期値では「サービスを再起動する」になっている筈なので「何もしない」に変更する。
右下の「適用」ボタンと「OK」をクリック。

基本的には、これでWindows Updateサービスが停まって「無効化」されたので勝手に更新しないようになった筈だが、実際にはいつのまにかWindows Updateサービスが有効化され勝手に実行中の状態になる。それは関連サービスや関連バッチによるもの。つまりそれらを停めなければ再びWindows Updateが動き出すことになるということ。(以下)

Windows Update Medic Serviceサービスの停止

先ずは停めるべきはここまでで操作してきたWindows Updateサービスのすぐ下にあった「Windows Update Medic Service」。これはWindows Updateの正常な状態を保つためのサービス。
ところが、この「Windows Update Medic Service」はWindows Updateサービスのように生易しくない。

Windows Updateを停める 11
「Windows Update Medic Service」をWindows Updateや他のサービスと同様にコントロールしようとしても「アクセスが拒否されました」になってしまう。これは管理者権限でコマンドでサービスコントロールを行おうとしても、普通に使える最高権限のシステムアカウントであっても全て拒否されるので操作できないサービスらしい。
そこで・・・(以下)

Windows Updateを停める 12
この記事の最初の方の手順と同じスタートボタンからアプリケーションを検索する方法で「レジストリ」でレジストリエディタを開くか、または[Win]+[R]で「ファイル名を指定して実行」の小窓に「regedit」を入力して[OK]でレジストリエディタを開く。

Windows Updateを停める 13
レジストリエディタの左列でツリー構造の「HKEY_LOCAL_MACHINE」→「SYSTEM」→「CurrentControlSet」→「Services」→「WaaSMedicSvc」を辿る。
「WaaSMedicSvc」を左クリックすると右列にそのサービスに関連するレジストリがいくつか表示される。
コンピュータ\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WaaSMedicSvc であることをしっかり確認する。
「Start」の行を見つける。StartのDWORDは初期値が3の筈。 (上の画像では既に4になっているが)
「Start」を左ダブルクリックする。

Windows Updateを停める 14
DWORD編集画面になるので値を3から4に変更する。
「OK」ボタンをクリック。

Windows Updateを停める 15
再び、「サービス」を表示すると例の「Windows Update Medic Service」の「スタートアップの種類」が無効になっている。

レジストリエディタを操作するのがイヤならレジストリファイルをダウンロードしてダブルクリックで実行する方法があります。この記事の内容は「WaaSMedicSvcサービスを無効化する」です。

基本的には1度無効にしたら何か重大な不具合でもない限り無効のままで問題無いと思いますが、どうしても元に戻したい場合だけ上の「有効化(手動)」のレジストリファイルをダウンロードして実行してください。)
無効化・有効化のレジストリファイルでは「スタートアップの種類」だけを変更し、その他の値は触らないようになっています。

上の2つのリンクを右クリックして「リンクのファイルの保存」を行う。
エクスプローラーなどのファイラーで保存したファイルをダブルクリックで実行できる。
レジストリファイルをを実行しようとすると2,3回ほど確認を求められるが全て実行する方向で。

Orchestrator Serviceの更新サービスの停止

Windows Updateを停める 16
もう一つ、「Orchestrator Serviceの更新」サービスを停止する。
「Orchestrator Serviceの更新」サービスを右クリックするかサービスをダブルクリックするかして「Orchestrator Serviceの更新」サービスのプロパティーを表示。

Windows Updateを停める 17
サービスの状態が「実行中」の場合は「停止」ボタンをクリックして、右下の「適用」。
「スタートアップの種類」で「無効」を選択して、右下の「適用」。

Windows Updateを停める 18
「Orchestrator Serviceの更新」サービスが「無効」になったことを確認する。

Windows Updateを停める 19
「Orchestrator Serviceの更新」サービスが「無効」になっているとWindowsの設定の「Windows Update」を表示すると「問題が発生しました」になって更新できない状態になっている。(これでOK)
Windowsの更新を行いたい場合は「Windows Update」サービスと「Orchestrator Serviceの更新」サービスの2つのサービスのスタートアップの種類を「手動」に変更すると正常に更新できる(筈)。

既に知っている人なら当たり前、そうでなくても勘が良い人ならもうここで気付いたかもしれないが、サービスの制御ってほとんどレジストリエディタの\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servicesで操作できるのよね。

毎回更新の度に「Windows Update」サービスと「Orchestrator Serviceの更新」サービスの有効化(手動化)と「無効化」を操作するのは面倒なのでレジストリファイルをクリックするだけで切り替わるようにする。

上の2つのリンクを右クリックして「リンクのファイルの保存」を行う。
エクスプローラーなどのファイラーで保存したファイルをダブルクリックで実行できる。
レジストリファイルをを実行しようとすると2,3回ほど確認を求められるが全て実行する方向で。

他に、Background Intelligent Transfer ServiceやDelivery Optimizationサービスを停止する方が良いという情報もあるようですが、Windows Update以外に影響する可能性があるのでこの記事ではこれらは停めないことにしました。

長くなりすぎるので関連タスクの停止は次記事で。

2021年10月30日変更: コピペミスで「Orchestrator Serviceの更新サービスの停止」が抜けていたので追加。
レジストリエディタを操作するのが怖い人・面倒な人向けにレジストリファイルを追加。

この記事の内容はWindowsのシステムを再起動するとしれっと元に戻されることが多いのでご注意ください。システム再起動後もWindows Updateを停めておく設定はまた別に用意する予定です。

2022年12月25日: 記事の題名が誤解を生む可能性があったので修正(前編・後編 共に)

関連記事:

ESP32マイコンボードとMAX7219 LEDディスプレイ4連x2でNTPクロックを作ってみた

NTPクロックを作ってみた。

電波時計が自動的に時刻合わせをしてくれないので正確な時刻を表示する時計が欲しくなったというのは前の記事で書いた。
で、Arduino互換のマイコンカードと8x8のLEDマトリクスディスプレイが4つ繋がったものを2つ買ってそれを接続して表示できるようになったというのも書いた。マイコンボードでNTP時刻合わせをするというのも書いた。
今回は、NTPで正しい時刻を取得してその時刻をLDEディスプレイに表示する。つまり元々の目的のものを作る。

普通に日付と時刻を表示しようとしたらディスプレイの表示範囲を超過してしまった
MAX7219 LEDディスプレイモジュールは4連を2個。元々の予定では4連を2つ重ね(2行)にするつもりでいたが、時刻表示(HH:MM:SS)を4連1枚に表示するのは難しいことがわかったので 4連を並べて8連(1行)にした。4連にHH:MM:SSを表示しようと思ったらかなり細いフォントを使うか縮小フォントを使うかになるけど1モジュールが8x8のLEDディスプレイなので細い字にするのも限界がある。読みやすさを犠牲にするのはイヤなので。
ちなみに、工夫なしに普通に日付と時刻を表示しようとしたら表示範囲に収まりきらずに秒の表示が切れてしまった。

何をどのように表示するかを考えた。

  • 時刻は秒まで表示する。HH:MM:SS形式で、これは絶対。
  • 時刻は常時表示にしたい。
  • 日付も表示したい。
  • 曜日も表示したい。
  • 西暦の年も表示したい。できたら4桁で。
  • 他の情報は要らない。

以上から、時刻(HH:MM:SS)を常時表示するエリアと日付のゾーン(エリア)に2分割する。
時刻のゾーンは固定表示。
「年」、「月/日」、「曜日(英字3文字)」を縦スクロールで上下移動して表示。そして、月/日の表示回数が多くてかつ表示時間を長めにする。
年 → 月/日 → 曜日 → 月/日 → 年 のような繰り返し。

ゾーン分割とアニメーションの表示方法についてはMD_Parolaライブラリに付属のスケッチ例からParola_Zone_TimeMsgを参考にした。

モジュール並びとゾーン分け
2021年10月18日: モジュールの並びとゾーン分けについて、↓の2段落分の説明がヘタクソで書いた本人もなんかよく判らんかったのでこの画像を追加

LEDモジュールは8x8の単体タイプを並べようが4連タイプを並べようが、右から左に制御するモジュール番号が付く。つまり7 6 5 4 3 2 1 0のようになる。
ゾーンを分割すると右からゾーン0、その左にゾーン1・・・のように並ぶ。つまり、モジュールもゾーンも右から左に並ぶ。英数字は左から右に書くので感覚としては逆並び。

時刻表示部分は、HH:MM:SSの8文字、日付側は年表示がYYYYで4文字、月日表示はMM/DDの5文字、曜日は英語の短縮形3文字とする。つまり時刻表示の方が文字数が多いので日付表示と時刻表示の表示範囲を1:1ではなく3:5で分割して表示することにした。4連モジュール2個を使うので4連を上下に並べる(4列x2行)表示はこの時点でムリということになった。
3:5と書いたが、モジュールとゾーンは右から左に0から数字が付くのでモジュール 7, 6, 5 がゾーン1でモジュール4 3, 2, 1, 0 がゾーン0になる。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <NTPClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include "GF4x8p.h"  // 4x8 font

//Wi-Fi
#define SSID "Wi-Fi-SSID"
#define WIFIKEY "WI-FI-PASSWORD"

//NTP client
#define ntpServer "NTP Server" //Host name or IP Address
#define tzOffset 32400     // JST = 3600 * 9

//MAX7219
#define MAX_DEVICES 8 // eight modules
#define CLK_PIN   27
#define DATA_PIN  12
#define CS_PIN    14

#define SPEED_TIME  25  //Small numbers are faster. Zero is the fastest.
#define PAUSE_TIME_L  1200 //1200ms for month/day long pause
#define PAUSE_TIME_S  300 //300ms for month/day short pause

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
// Hardware SPI connection
//MD_Parola P = MD_Parola(CS_PIN, MAX_DEVICES);
MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, ntpServer, tzOffset, 3540000); //59 minutes : 59(min) x 60(sec) x 1000(ms) = 3540000


void setup() {
  WiFi.begin(SSID, WIFIKEY);

  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 );
  }

  timeClient.begin();

  P.begin(2); // 2 zones
  P.setZone(0, 0, 4);  //00011111 <- Zone 0  for Time display
  P.setZone(1, 5, 7);  //11100000 <- Zone 1  for Date display
  P.setFont(0,GF4x8p);
  P.setFont(1,GF4x8p);
  P.setIntensity(0);  //Darkest
}

void loop() {

  time_t epTime = timeClient.getEpochTime();
  static uint8_t  dsw = 0;
  struct tm  ts;
  char bufD[15], bufT[9]; // "yyyy mm/dd aaa" + 1 = 15,  "hh:mm:ss" + 1 = 9   
  char *parr[15];
  ts = *localtime(&epTime);

  timeClient.update();

  P.displayAnimate();

  //Zone 1 Date
  if (P.getZoneStatus(1)) {
    strftime(bufD, sizeof(bufD), "%Y %m/%d %a", &ts);
    parr[0] = strtok(bufD, " "); // year
    parr[1] = strtok(NULL, " "); // month/day
    parr[2] = strtok(NULL, " "); // day of the week

    switch (dsw) {
      case 0: // month/day down
        P.displayZoneText(1, parr[1], PA_CENTER, SPEED_TIME, 0, PA_NO_EFFECT, PA_SCROLL_DOWN);
        dsw++;
        break;
      case 1: // year down
        P.displayZoneText(1, parr[0], PA_CENTER, SPEED_TIME, 0, PA_SCROLL_DOWN, PA_NO_EFFECT);
        P.setPause(1, PAUSE_TIME_S);
        dsw++;
        break;
      case 2: // year up
        P.displayZoneText(1, parr[0], PA_CENTER, SPEED_TIME, 0, PA_NO_EFFECT, PA_SCROLL_UP);
        dsw++;
        break;
      case 3: // month/day up
        P.displayZoneText(1, parr[1], PA_CENTER, SPEED_TIME, 0, PA_SCROLL_UP, PA_NO_EFFECT);
        P.setPause(1, PAUSE_TIME_L);
        dsw++;
        break;
      case 4: // month/day up
        P.displayZoneText(1, parr[1], PA_CENTER, SPEED_TIME, 0, PA_NO_EFFECT, PA_SCROLL_UP);
        dsw++;
        break;
      case 5: // day of the week up
        P.displayZoneText(1, parr[2], PA_CENTER, SPEED_TIME, 0, PA_SCROLL_UP, PA_NO_EFFECT);
        P.setPause(1, PAUSE_TIME_S);
        dsw++;
        break;
      case 6: // day of the week down
        P.displayZoneText(1, parr[2], PA_CENTER, SPEED_TIME, 0, PA_NO_EFFECT, PA_SCROLL_DOWN);
        dsw++;
        break;
      case 7: // month/day  up
        P.displayZoneText(1, parr[1], PA_CENTER, SPEED_TIME, 0, PA_SCROLL_DOWN, PA_NO_EFFECT);
        P.setPause(1, PAUSE_TIME_L);
        dsw = 0;
        break;
      default:
        break;
    }
    P.displayReset(1);
  }

  //Zone 0 Time
  if (P.getZoneStatus(0)) {
    strftime(bufT, sizeof(bufT), "%T", &ts); // %T: hh:mm:ss
    P.displayZoneText(0, bufT, PA_CENTER, SPEED_TIME, 0, PA_PRINT, PA_NO_EFFECT);
    P.displayReset(0);
  }

  delay(50); //Don't remove this delay, and don't make it too small
}

void loop(){} の中はひたすらループ処理が行われるが、P.getZoneStatus(#Zone)が1でなければそのゾーンのアニメーションの制御はループに邪魔されず(実際は多少邪魔される)に進行する。逆に言えばアニメーションの動作が完了してP.getZoneStatus(#Zone)が1になるまでアニメーションの処理に邪魔されず(実際は多少邪魔される)にループが進行するのでアタマがこんがらかるような余計なことを考えなくて済むのでとてもラク。
void loop(){}の最後にディレイを入れているが、値(ミリ秒)が小さすぎるとループ処理が速く行われすぎて動作異常になると思われる。ただし大きすぎても今度は動作が遅くなったり処理開始のタイミングが狂うかもしれないので適度な大きさの数値にする。50msより少し小さい程度?

今回は狭い表示範囲に文字を詰め込むため専用にフォントを作成した。時計の表示は時・分・秒が変わる度に表示位置がガタガタ変わるのはイヤなので数字は4ドットの固定幅(英字も)で数字は4x8の大きめにし、記号は幅を最小限に1〜3ドット(列)の可変幅というハイブリッド型プロポーショナルフォントにした。
ゼロはアルファベットのOと区別がしやすいよう斜線付きタイプにしたが敢えて超少数派の逆斜線にしてみた。(Øと斜線の向きが逆)
一応、フォントのリンクを貼っておくのでダウンロードできます。

GF4x8p.h

まぁ素敵なフォントを作ってやろうという意欲はあるんだけど、残念ながらデザインセンスと実力がからっきし無いので字の見た目が残念かもしれない。もっと良いのが欲しいという人は自分で作っていただければ。 で、ダウンロードしたフォントのファイルをスケッチと同じディレクトリに置く。上の例ではファイル名が GF4x8p.h でフォント名が GF4x8p 。つまり、スケッチの最初の方で#include "GF4x8p.h" と指定してやればそのフォントがインクルードされ、P.setFont(0,GF4x8p);のように指定することで0番ゾーンでそのフォントが使われる(P.setFont(1,GF4x8p);なら1番ゾーン)。なのでゾーン単位でフォントを使い分けることができる。

予定通りに日付と時刻がきれいに表示されるようになった
日付、時刻ともにそれぞれのゾーンの中で中央寄せ。日付表示は8x8 LEDディスプレイ3モジュール分のゾーンなので5文字表示の「月/日」ではカツカツだが、時刻ゾーンは左右の端に余裕がある感じ。

最初にWi-Fiで接続するだけしか処理が入っていないのでWi-Fiの通信が途切れるとそのあと再接続しない筈。そうすると画面表示が異常に遅くなるかも。特に日付スクロールが壊れたように遅くなる。電源を入れ直すしか対応がない。Wi-Fiの接続の監視/再接続する処理が要るかも。

2022年11月5日:
Wi-Fi自動再接続の処理について記事にしました。この記事のコードに僅かの修正で使えます。

関連記事:
Up