【初心者向け】Windows PowerShellのパイプライン入門|効率的なコマンド連携の使い方を完全解説!

Windows

PowerShellを使っていると、1つのコマンドで完結しないケースによく出会います。

「ファイル一覧から特定の名前だけ取り出したい」
「サービス一覧を条件でフィルタしたい」
「プロセスを並び替えて表示したい」
…そんなときに便利なのがパイプライン(|)です。

UNIX系のシェルに慣れている人にも馴染み深いこの記号ですが、PowerShellのパイプは**「文字列」ではなく「オブジェクト」を渡す**のが最大の特徴です。

この記事では、PowerShellパイプラインの基本構文・実例・応用テクニックまで、初心者にもわかりやすく丁寧に解説します。

スポンサーリンク

PowerShellのパイプラインとは?

パイプライン(|)の基本概念

PowerShellでは、コマンドの出力(結果)を、次のコマンドの入力として渡すためにパイプ|を使います。

基本的な書き方:

コマンド1 | コマンド2 | コマンド3

例:

Get-Process | Where-Object { $_.CPU -gt 10 } | Sort-Object CPU

この例では、「プロセス一覧を取得」→「CPU使用率10以上でフィルタ」→「CPU使用率で並び替え」という処理が流れるように実行されます。

他のシェルとの最大の違い:オブジェクトを渡す

シェルパイプで渡すデータ特徴
bash/cmd文字列(テキスト)単純だが加工が必要
PowerShell.NETオブジェクト構造化されたデータをそのまま利用

具体例で理解しよう:

bashの場合(文字列処理):

ps aux | grep "firefox" | awk '{print $2}'

PowerShellの場合(オブジェクト処理):

Get-Process firefox | Select-Object Id

PowerShellでは、プロセスオブジェクトのIdプロパティに直接アクセスできるため、より直感的で確実な処理が可能です。

オブジェクトの構造を理解しよう

プロセスオブジェクトの例:

# プロセス情報を取得
$process = Get-Process notepad

# オブジェクトのプロパティを確認
$process | Get-Member

出力例:

Name          MemberType Definition
----          ---------- ----------
Id            Property   int Id {get;}
ProcessName   Property   string ProcessName {get;}
CPU           Property   double CPU {get;}
WorkingSet    Property   long WorkingSet {get;}
...

これらのプロパティに、パイプライン内で直接アクセスできるのがPowerShellの強みです。

ポイント: PowerShellのパイプラインは、構造化されたデータをそのまま受け渡しできるため、より強力で柔軟な処理が可能です。

基本的な使い方とパターン別実例

① Where-Object:条件でフィルタリング

基本構文:

コマンド | Where-Object { 条件式 }
# 短縮形
コマンド | ? { 条件式 }

実例1:CPU使用率でプロセスをフィルタ

Get-Process | Where-Object { $_.CPU -gt 10 }

実例2:実行中のサービスのみ表示

Get-Service | Where-Object { $_.Status -eq "Running" }

実例3:特定サイズ以上のファイルを検索

Get-ChildItem C:\Temp | Where-Object { $_.Length -gt 1MB }

実例4:複数条件でのフィルタ

Get-Process | Where-Object { $_.CPU -gt 5 -and $_.WorkingSet -gt 100MB }

② Sort-Object:並び替え

基本構文:

コマンド | Sort-Object プロパティ名
# 降順の場合
コマンド | Sort-Object プロパティ名 -Descending

実例1:CPU使用率で並び替え

Get-Process | Sort-Object CPU -Descending

実例2:ファイルサイズで並び替え

Get-ChildItem | Sort-Object Length -Descending

実例3:複数プロパティで並び替え

Get-Service | Sort-Object Status, Name

③ Select-Object:必要な情報だけ抽出

基本構文:

コマンド | Select-Object プロパティ1, プロパティ2
# 先頭n件のみ
コマンド | Select-Object -First n

実例1:プロセス名とCPU使用率のみ表示

Get-Process | Select-Object ProcessName, CPU

実例2:ファイル名とサイズのみ表示

Get-ChildItem | Select-Object Name, Length

実例3:上位5件のみ取得

Get-Process | Sort-Object CPU -Descending | Select-Object -First 5

④ 出力とエクスポート

ファイルに保存:

Get-Process | Where-Object { $_.CPU -gt 5 } | Out-File "highcpu.txt"

CSVファイルに出力:

Get-Service | Export-Csv "services.csv" -NoTypeInformation

グリッド表示(GUI):

Get-Process | Out-GridView

HTML形式で出力:

Get-Service | ConvertTo-Html | Out-File "services.html"

実用的な組み合わせ例

例1:大きなファイルを見つける

Get-ChildItem C:\ -Recurse | 
Where-Object { !$_.PSIsContainer -and $_.Length -gt 100MB } | 
Sort-Object Length -Descending | 
Select-Object FullName, @{Name="SizeMB";Expression={[math]::Round($_.Length/1MB,2)}} |
Format-Table -AutoSize

例2:停止中のサービスを確認

Get-Service | 
Where-Object { $_.Status -eq "Stopped" } | 
Sort-Object Name | 
Select-Object Name, Status |
Export-Csv "stopped_services.csv" -NoTypeInformation

ポイント: 基本的な組み合わせだけでも、フィルタ・抽出・並び替え・出力保存が自在に可能になります。

PowerShellパイプラインの応用テクニック

高度なフィルタリング

正規表現を使ったフィルタ:

Get-Process | Where-Object { $_.ProcessName -match "^s.*" }
# 「s」で始まるプロセス名のみ

配列に含まれるかのチェック:

$criticalServices = @("Spooler", "DHCP", "DNS")
Get-Service | Where-Object { $_.Name -in $criticalServices }

Null値のチェック:

Get-Process | Where-Object { $_.MainWindowTitle -ne "" }
# ウィンドウタイトルがあるプロセスのみ

ForEach-Object:カスタム処理

基本構文:

コマンド | ForEach-Object { カスタム処理 }
# 短縮形
コマンド | % { カスタム処理 }

実例1:各サービスの状態を整形表示

Get-Service | ForEach-Object {
    "Service: $($_.Name) is $($_.Status)"
}

実例2:ファイル拡張子を変更

Get-ChildItem *.txt | ForEach-Object {
    Rename-Item $_.FullName $_.FullName.Replace(".txt", ".bak")
}

実例3:計算処理を追加

Get-Process | ForEach-Object {
    [PSCustomObject]@{
        Name = $_.ProcessName
        "MemoryMB" = [math]::Round($_.WorkingSet / 1MB, 2)
        "CPUPercent" = [math]::Round($_.CPU, 2)
    }
}

Measure-Object:統計処理

基本的な統計:

Get-ChildItem | Measure-Object -Property Length -Sum -Average -Maximum

プロセスのメモリ使用量統計:

Get-Process | Measure-Object -Property WorkingSet -Sum -Average |
ForEach-Object {
    [PSCustomObject]@{
        "総メモリ使用量(GB)" = [math]::Round($_.Sum / 1GB, 2)
        "平均メモリ使用量(MB)" = [math]::Round($_.Average / 1MB, 2)
        "プロセス数" = $_.Count
    }
}

Group-Object:グループ化

サービスの状態別グループ化:

Get-Service | Group-Object Status

ファイルの拡張子別グループ化:

Get-ChildItem | Group-Object Extension | 
Sort-Object Count -Descending |
Select-Object Name, Count

プロセスの会社別グループ化:

Get-Process | Group-Object Company | 
Where-Object { $_.Name -ne "" } |
Sort-Object Count -Descending |
Select-Object Name, Count -First 10

複雑なチェーン処理の例

システム監視スクリプトの例:

Get-Process | 
Where-Object { $_.CPU -gt 5 -or $_.WorkingSet -gt 500MB } |
Sort-Object CPU -Descending |
Select-Object @{Name="プロセス名";Expression={$_.ProcessName}},
              @{Name="CPU使用率";Expression={[math]::Round($_.CPU,2)}},
              @{Name="メモリ(MB)";Expression={[math]::Round($_.WorkingSet/1MB,2)}},
              @{Name="開始時刻";Expression={$_.StartTime}} |
Format-Table -AutoSize |
Out-String |
Add-Content "system_monitor.log"

ディスク使用量レポートの例:

Get-ChildItem C:\ -Recurse -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
    $size = (Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue | 
             Measure-Object -Property Length -Sum).Sum
    [PSCustomObject]@{
        Folder = $_.FullName
        SizeGB = [math]::Round($size / 1GB, 2)
    }
} |
Where-Object { $_.SizeGB -gt 1 } |
Sort-Object SizeGB -Descending |
Export-Csv "disk_usage.csv" -NoTypeInformation

ポイント: Where-ObjectForEach-ObjectMeasure-Objectなどと組み合わせることで、複雑な処理も一行で記述できます。

パイプライン利用時の注意点とトラブル対策

よくある問題と対処法

問題① パイプ対象が空で何も起きない

# 存在しないプロセスを検索
Get-Process -Name "NotExistProcess" | Where-Object { $_.CPU -gt 5 }
# → エラーにならないが、何も表示されない

対策:存在確認を事前に行う

if (Get-Process -Name "notepad" -ErrorAction SilentlyContinue) {
    Get-Process -Name "notepad" | Where-Object { $_.CPU -gt 5 }
} else {
    Write-Host "指定されたプロセスが見つかりません"
}

問題② 出力が多すぎて画面に収まらない

対策1:ページャーを使用

Get-Process | More

対策2:GUI表示を使用

Get-Process | Out-GridView

対策3:件数を制限

Get-Process | Select-Object -First 10

問題③ エラーが発生して処理が止まる

対策:エラー処理を追加

Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.Length -gt 1GB }

$_(パイプライン変数)の理解

$_とは:

  • パイプラインで渡されるオブジェクト1つを表す特別な変数
  • Where-ObjectForEach-Object内で使用

正しい使用例:

Get-Service | Where-Object { $_.Status -eq "Running" }
#                           ↑ここの$_は各サービスオブジェクト

よくある間違い:

Get-Service | Where-Object { Status -eq "Running" }
# エラー:$_が抜けている

パフォーマンスの考慮

遅い処理の例:

# 大量のファイルを1つずつ処理
Get-ChildItem C:\ -Recurse | ForEach-Object { Test-Path $_.FullName }

改善された処理:

# 条件を先に絞り込む
Get-ChildItem C:\ -Recurse -File | Where-Object { $_.Length -gt 1MB }

デバッグのコツ

段階的にパイプラインを構築:

# ステップ1:基本データを確認
Get-Process

# ステップ2:フィルタを追加
Get-Process | Where-Object { $_.CPU -gt 5 }

# ステップ3:並び替えを追加
Get-Process | Where-Object { $_.CPU -gt 5 } | Sort-Object CPU

# ステップ4:出力形式を調整
Get-Process | Where-Object { $_.CPU -gt 5 } | Sort-Object CPU | Select-Object Name, CPU

中間結果の確認:

Get-Process | Tee-Object -Variable processes | Where-Object { $_.CPU -gt 5 }
# $processes変数で中間結果を確認可能

ポイント: パイプラインは便利ですが、無出力=バグではないことや$_の扱いに注意が必要です。

実用的なパイプラインスクリプト例

システム管理

メモリ使用量が多いプロセスの監視:

function Monitor-HighMemoryProcesses {
    Get-Process | 
    Where-Object { $_.WorkingSet -gt 100MB } |
    Sort-Object WorkingSet -Descending |
    Select-Object ProcessName, 
                  @{Name="MemoryMB";Expression={[math]::Round($_.WorkingSet/1MB,2)}},
                  Id, StartTime |
    Format-Table -AutoSize
}

サービスの健全性チェック:

function Check-CriticalServices {
    $criticalServices = @("Spooler", "Themes", "AudioSrv")
    
    $criticalServices | ForEach-Object {
        $service = Get-Service $_ -ErrorAction SilentlyContinue
        if ($service) {
            [PSCustomObject]@{
                ServiceName = $_
                Status = $service.Status
                StartType = $service.StartType
                IsRunning = ($service.Status -eq "Running")
            }
        }
    } | Format-Table -AutoSize
}

ファイル管理

重複ファイルの検出:

function Find-DuplicateFiles {
    param([string]$Path = ".")
    
    Get-ChildItem $Path -Recurse -File |
    Group-Object Length |
    Where-Object { $_.Count -gt 1 } |
    ForEach-Object {
        $_.Group | Group-Object { 
            (Get-FileHash $_.FullName).Hash 
        } |
        Where-Object { $_.Count -gt 1 } |
        ForEach-Object {
            Write-Host "重複ファイル発見:" -ForegroundColor Yellow
            $_.Group | Select-Object FullName, Length | Format-Table
        }
    }
}

古いファイルのクリーンアップ:

function Remove-OldFiles {
    param(
        [string]$Path,
        [int]$DaysOld = 30
    )
    
    $cutoffDate = (Get-Date).AddDays(-$DaysOld)
    
    Get-ChildItem $Path -Recurse -File |
    Where-Object { $_.LastWriteTime -lt $cutoffDate } |
    ForEach-Object {
        Write-Host "削除: $($_.FullName)" -ForegroundColor Red
        # Remove-Item $_.FullName -Force  # 実際に削除する場合はコメントアウト
    }
}

ログ解析

イベントログの分析:

function Analyze-EventLog {
    param([int]$Hours = 24)
    
    $startTime = (Get-Date).AddHours(-$Hours)
    
    Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=$startTime} -ErrorAction SilentlyContinue |
    Group-Object LevelDisplayName |
    Sort-Object Count -Descending |
    Select-Object @{Name="レベル";Expression={$_.Name}},
                  @{Name="件数";Expression={$_.Count}} |
    Format-Table -AutoSize
}

よくある質問と回答

Q: パイプラインはどこまで長くできますか?

A: 技術的制限はありませんが、可読性のため適度な長さに

# 読みやすい例(改行で整理)
Get-Process |
Where-Object { $_.CPU -gt 5 } |
Sort-Object CPU -Descending |
Select-Object Name, CPU |
Format-Table -AutoSize

Q: bashのパイプラインとの互換性は?

A: 基本的な構文は似ていますが、データの扱いが異なります

項目bashPowerShell
区切り文字改行・スペースオブジェクトのプロパティ
データ型文字列のみ型付きオブジェクト
フィルタgrepWhere-Object
並び替えsortSort-Object

Q: パフォーマンスを向上させるには?

A: 以下の点に注意してください

  1. 早い段階でフィルタ:Where-Objectを最初に配置
  2. 必要なプロパティのみ選択:Select-Objectで絞り込み
  3. エラー処理:-ErrorAction SilentlyContinueで継続
  4. バッチ処理:ForEach-Objectより配列操作を優先

Q: デバッグはどうすれば?

A: 段階的な構築とTee-Objectの活用

# 中間結果を変数に保存
Get-Process | Tee-Object -Variable allProcesses |
Where-Object { $_.CPU -gt 5 } | Tee-Object -Variable filteredProcesses |
Sort-Object CPU

# 後で中間結果を確認
$allProcesses.Count
$filteredProcesses.Count

まとめ:PowerShellのパイプラインで作業をスマートに効率化しよう!

今回学んだ重要なポイント:

  • 基本概念:オブジェクトを渡すPowerShell独自の仕組み
  • 基本操作:Where-Object、Sort-Object、Select-Objectの組み合わせ
  • 応用テクニック:ForEach-Object、Measure-Object、Group-Objectの活用
  • 実践的な使い方:システム管理、ファイル管理、ログ解析への応用

実際に使ってみよう:

  1. 基本的なフィルタリングから始める
  2. 段階的にパイプラインを構築する練習
  3. 実用的なスクリプトを作成してみる
  4. エラー処理とデバッグの方法を覚える

PowerShellのパイプラインは、オブジェクトを受け渡すことで複雑な処理をシンプルに表現できる強力な仕組みです。

  • フィルタWhere-Object
  • 並べ替えSort-Object
  • 抽出Select-Object
  • 出力Out-FileOut-GridViewExport-Csv

コメント

タイトルとURLをコピーしました