ブルースクリーンで病む前に

あなたが Windows の管理者なら、ブルースクリーンが発生した後、上司または取引先からこう言われるでしょう。「原因は？」

ブルースクリーンの原因は様々ですが、少なくともメモリダンプが出力されていなければ、返答は「しるか！」になります。

上司または取引先から詰められて精神的に病む前に、ブルースクリーンが発生した際にメモリダンプが出力できる準備をしておきましょう。

ブルースクリーンについて知りたい方はこちらを一読ください。

https://qiita.com/shj9rk/items/8e4f70ec5f81b83b009f

## 環境
Windows OS 全般

## 完全メモリダンプの出力設定
完全メモリダンプの出力設定は、GUI で可能ですが、今回は、PowerShell スクリプトでやってみます。

紹介する PowerShell スクリプトでは、物理メモリのサイズに基づいてページファイルのサイズを設定し、完全メモリダンプの設定を行った後、システムを再起動してこれらの設定を反映しています。完全メモリダンプの出力は、ページファイルを使用して行われるため、ページファイルのサイズも変更が必要です。

### PowerShell スクリプト
```powershell:BeforeBlueScreen.ps1
# 1. 物理メモリのサイズを取得
$totalMemory = (Get-CimInstance -ClassName Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum).Sum

# 2. ページファイルのサイズを計算
$totalMemoryMB = [math]::round($totalMemory / 1MB)
$pagefileSizeMB = $totalMemoryMB + 400

# 3. ページファイル設定
$regPathPagingFiles = "HKLM:\System\CurrentControlSet\Control\Session Manager\Memory Management"
$pagingFilesValue = "c:\pagefile.sys $pagefileSizeMB $pagefileSizeMB"
Set-ItemProperty -Path $regPathPagingFiles -Name PagingFiles -Value $pagingFilesValue

# 4. 完全メモリダンプ設定
$regPathCrashControl = "HKLM:\System\CurrentControlSet\Control\CrashControl"
Set-ItemProperty -Path $regPathCrashControl -Name FilterPages -Value 0 -Type DWord
Set-ItemProperty -Path $regPathCrashControl -Name CrashDumpEnabled -Value 1 -Type DWord
Set-ItemProperty -Path $regPathCrashControl -Name AlwaysKeepMemoryDump -Value 1 -Type DWord

# 5. OS を再起動して設定を反映
Restart-Computer -Force
```
### スクリプトの流れ
#### 1. 物理メモリのサイズを取得
```powershell
$totalMemory = (Get-CimInstance -ClassName Win32_PhysicalMemory | Measure-Object -Property Capacity -Sum).Sum
```
`Get-CimInstance -ClassName Win32_PhysicalMemory` を使ってシステムに搭載されている物理メモリの容量を取得し、`Measure-Object` を使い、すべてのメモリモジュールの `Capacity` プロパティを合計して、物理メモリの総容量を `$totalMemory` に代入しています。

Win32_PhysicalMemory class - Win32 apps | Microsoft Learn
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-physicalmemory

#### 2. ページファイルのサイズを計算
```powershell
$totalMemoryMB = [math]::round($totalMemory / 1MB)
$pagefileSizeMB = $totalMemoryMB + 400
```
`totalMemory` の値を MB 単位に変換、四捨五入して `$totalMemoryMB` にし、400 を加算し、ページファイルサイズとして `$pagefileSizeMB` に代入しています。ページファイルの設定は MB 単位で設定する必要があるので、この処理が必要になります。

#### 3. ページファイル設定
```powershell
$regPathPagingFiles = "HKLM:\System\CurrentControlSet\Control\Session Manager\Memory Management"
$pagingFilesValue = "c:\pagefile.sys $pagefileSizeMB $pagefileSizeMB"
Set-ItemProperty -Path $regPathPagingFiles -Name PagingFiles -Value $pagingFilesValue
```
ページファイルの設定を行います。レジストリの `PagingFiles` 値に、先ほど計算したページファイルサイズを反映した文字列を保存します。`Set-ItemProperty` コマンドで、`PagingFiles` の設定を更新しています。

#### 4. 完全メモリダンプの設定
```powershell
$regPathCrashControl = "HKLM:\System\CurrentControlSet\Control\CrashControl"
Set-ItemProperty -Path $regPathCrashControl -Name FilterPages -Value 0 -Type DWord
Set-ItemProperty -Path $regPathCrashControl -Name CrashDumpEnabled -Value 1 -Type DWord
Set-ItemProperty -Path $regPathCrashControl -Name AlwaysKeepMemoryDump -Value 1 -Type DWord
```
メモリダンプの設定を行います。具体的には、以下のレジストリ値を設定しています。
- `FilterPages` を `0`（フィルターを無効化）
- `CrashDumpEnabled` を `1`（完全メモリダンプ）
- `AlwaysKeepMemoryDump` を `1`（常にメモリダンプファイルを保持）

#### 5. システムの再起動
```powershell
Restart-Computer -Force
```
システムを再起動して、設定が反映されるようにします。`-Force` オプションを使用して強制的に再起動します。

### 使用例
この PowerShell スクリプトは管理者としての実行が必要です。
```powershell
# スクリプトの実行を許可
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process

# スクリプト実行
.\BeforeBlueScreen.ps1
```

## さいごに
FilterPages の設定を１に設定すると、完全メモリダンプではなく、アクティブメモリダンプを出力できます。
```powershell
Set-ItemProperty -Path $regPathCrashControl -Name FilterPages -Value 1 -Type DWord
```
メモリダンプは、デフォルト設定だと、%SystemRoot%\MEMORY.DMP に出力されますので、出力先のドライブ容量が不足している場合は、アクティブメモリダンプにしたほうがいいかもしれません。

GUI で設定を変更したい場合は、以下の Web サイトにスクリーンショット付きで書いておいたので確認してみてください。

完全メモリ ダンプの出力設定 | Microsoft Japan Windows Technology Support Blog
https://jpwinsup.github.io/blog/2021/02/15/Performance/Hang_BSOD/MemoryDump/