0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Windows PowerShell環境活用 ライフハックスクリプト

0
Posted at

曖昧な「ストレージが重い・空きがない」という事象は、原因の特定が難航しやすい障害の一つです。巨大ログの突発的増殖、ロックされたファイルによる削除不能、NTFSメタデータの増大など、原因を定量的に特定せずに場当たり的なファイル削除を行っても根本解決には至りません。

Windows / PowerShell環境において、単なるエクスプローラーでの容量確認を超えた「ファイル操作・容量診断レシピ」と、一括で一次切り分けを行う自動化スクリプト『disk-doctor.ps1』を提案します。


1. 階層的容量測定による「闇容量」の可視化

標準の Get-ChildItem に -Recurse を指定して巨大ディレクトリを走査すると、パイプラインのオーバーヘッドにより処理が極めて鈍化します。高速な診断には .NET 列挙 API(EnumerateFiles)をダイレクトに呼び出すか、CIM インスタンスを活用したセグメント解析が必要です。

高速なディレクトリ別容量ランキングの算出

# .NET System.IO APIを利用した高速深層走査とトップ10ディレクトリの抽出
[CmdletBinding()]
param([string]$Path = "C:\")

[System.IO.Directory]::EnumerateDirectories($Path) | ForEach-Object {
    $dir = $_
    try {
        $size = [System.IO.Directory]::EnumerateFiles($dir, "*", [System.IO.SearchOption]::AllDirectories) | 
            ForEach-Object { (New-Object System.IO.FileInfo($_)).Length } | 
            Measure-Object -Sum | Select-Object -ExpandProperty Sum

        [PSCustomObject]@{
            Directory = $dir
            SizeGB    = [math]::Round($size / 1GB, 2)
        }
    } catch {
        # アクセス権限拒否(UnauthorizedAccessException)等をハンドリング
        [PSCustomObject]@{ Directory = $dir; SizeGB = -1 }
    }
} | Sort-Object SizeGB -Descending | Select-Object -First 10 | Format-Table -AutoSize

出力例と判定基準

Directory                 SizeGB
---------                 ------
C:\ProgramData             42.15
C:\Users                   28.40
C:\Windows                 24.10
C:\System Volume Information -1.00

  • SizeGB = -1.00:アクセス拒否(管理者権限での再実行、または System Volume Information などの保護領域)。
  • 特定のアプリケーションデータ配下の不自然な増大:ローテーションが破綻したアプリケーションログや、一時ファイルの残留を疑う決定的な根拠となります。

2. I/Oボトルネックとロック状態の特定

容量不足だけでなく「ファイルが削除できない」「特定ディレクトリへの書き込みでI/O待ちが発生する」現象は、プロセスによるファイルロックやNTFSフラグメンテーションが起因します。

ハンドルロックの特定とNTFSメタデータの状態調査

# 1. オープン中のファイルとプロセスの紐付け(OpenFilesまたはGet-Processのコンテキスト利用)
# ※ OpenFiles を有効化(要再起動)している環境での直接照会
openfiles /query /fo csv | ConvertFrom-Csv | Select-Object -First 5

# 2. ボリュームの断片化およびUSNジャーナル(変更履歴)の検査
fsutil usn queryjournal C:

取得パラメータ / コマンド 意味と診断時の判定基準
Usn Journal 情報 LowestValidUsn と NextUsn の差分が極端に大きい場合、激しいファイル生成・削除がバックグラウンドで行われている。
openfiles 特定のログファイルがどの PID(プロセスID)に掴まれているかを特定。強制削除ではなくプロセス側の安全な停止手順へ導く。
Get-Volume (AllocationUnitSize) クラスタサイズ(通常4KB)。数バイトの微小ファイルが数百万個生成される環境では、ディスク上のサイズ(Allocated Size)が肥大化する「セクタロス」が発生。

3. 障害時にワンショットで一次切り分けを行う「自動化PowerShellスクリプト」

緊急時にストレージの全体像(パーティション状態、巨大ファイル上位20件、一時フォルダ肥大化)を網羅的に取得し、ログファイルへ保存する統合診断レシピです。

ワンステップ診断スクリプト:disk-doctor.ps1

<#
.SYNOPSIS
    Windows/PowerShell用 ディスク・ファイルシステム一次診断スクリプト
#>
[CmdletBinding()]
param (
    [string]$TargetDrive = "C:",
    [string]$LogPath = "$env:TEMP\disk_diag_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
)

# 出力のリダイレクト設定
Start-Transcript -Path $LogPath -Append | Out-Null

Write-Host "==========================================" -ForegroundColor Cyan
Write-Host " Storage Diagnostic Report - $(Get-Date)" -ForegroundColor Cyan
Write-Host " Host: $env:COMPUTERNAME ($((Get-CimInstance Win32_OperatingSystem).Caption))" -ForegroundColor Cyan
Write-Host " Target Drive: $TargetDrive" -ForegroundColor Cyan
Write-Host "==========================================" -ForegroundColor Cyan

Write-Host "`n[1. Volume & Partition Status]" -ForegroundColor Yellow
Get-Volume -DriveLetter $TargetDrive.TrimEnd(':') | Format-Table DriveLetter, FileSystemLabel, FileSystem, SizeRemainingGB, SizeGB, HealthStatus

Write-Host "`n[2. Top 15 Largest Files in $TargetDrive\]" -ForegroundColor Yellow
try {
    Get-ChildItem -Path "$TargetDrive\" -Recurse -File -ErrorAction SilentlyContinue |
        Sort-Object Length -Descending |
        Select-Object -First 15 |
        Select-Object @{N="FullName";E={$_.FullName}}, @{N="SizeMB";E={[math]::Round($_.Length / 1MB, 2)}}, LastWriteTime |
        Format-Table -AutoSize
} catch {
    Write-Warning "Failed to scan files completely due to access restrictions."
}

Write-Host "`n[3. System Temp Directories Size Summary]" -ForegroundColor Yellow
$tempPaths = @($env:TEMP, "C:\Windows\Temp", "C:\Windows\Prefetch")
foreach ($path in $tempPaths) {
    if (Test-Path $path) {
        $measure = Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
        $sizeMB = [math]::Round(($measure.Sum / 1MB), 2)
        [PSCustomObject]@{
            TempPath  = $path
            FileCount = $measure.Count
            TotalMB   = $sizeMB
        } | Format-Table -AutoSize
    }
}

Write-Host "`n[4. NTFS/File System Error Logs (System EventLog)]" -ForegroundColor Yellow
Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Ntfs','Disk'; StartTime=(Get-Date).AddDays(-1)} -ErrorAction SilentlyContinue |
    Select-Object TimeCreated, Id, LevelDisplayName, Message -First 5 |
    Format-Table -AutoSize

Write-Host "==========================================" -ForegroundColor Cyan
Write-Host "Diagnostic complete. Saved to: $LogPath" -ForegroundColor Cyan

Stop-Transcript | Out-Null

実行方法

# 実行ポリシーを一時許可して診断を実行
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process -Force
.\disk-doctor.ps1 -TargetDrive "C:"


決定論的アプローチによるストレージ管理

「容量が足りないから適当にログを消す」という対処療法は、根本原因(ロギング設計の破綻、ハンドルリーク、特定プロセスによるI/O占有)の隠蔽につながります。

  • L1(物理・ボリューム層): Get-Volume によるファイルシステム整合性(HealthStatus)とアロケーション単位の検証
  • L2(ファイルツリー構造層): .NET 列挙 API によるミリ秒単位の巨大ディレクトリ特定
  • L3(カーネル・プロセス層): fsutil および Get-WinEvent によるI/Oエラー・変更履歴ログの解析

PowerShellの持つ強力な.NET相互運用性とOS管理API(CIM/WMI)を組み合わせることで、直感に頼らない再現可能な障害解析が可能になります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?