PowerShellを使っていると、こんな場面に遭遇することがあります:
「コマンドの結果をメール本文に含めたいけど、うまく表示されない」
「オブジェクトの内容をログファイルに綺麗に保存したい」
「GUIアプリケーションでPowerShellの結果を表示したい」
「文字列として扱いたいのに、オブジェクトのままで困っている」
これらの問題を解決するのがOut-Stringコマンドレットです。
この記事では、PowerShellにおけるオブジェクトと文字列の違いから、Out-Stringの基本的な使い方、実践的な活用法まで詳しく解説します。
PowerShellのオブジェクトと文字列の基本概念

PowerShellはオブジェクト指向
PowerShellの特徴は、コマンドの出力がテキストではなくオブジェクトであることです。
これにより、データの構造や型情報が保持され、強力なデータ処理が可能になります。
# Get-Processの出力はプロセスオブジェクトの配列
$processes = Get-Process
$processes[0].GetType() # System.Diagnostics.Process
# コマンドの結果をパイプで次のコマンドに渡す
Get-Process | Where-Object { $_.CPU -gt 100 }
オブジェクトと文字列の違い
# オブジェクトとして扱う場合
$service = Get-Service -Name "Spooler"
$service.Status # プロパティにアクセス可能
$service.Stop() # メソッドを呼び出し可能
# 文字列として扱う場合
$serviceString = Get-Service -Name "Spooler" | Out-String
$serviceString.Length # 文字列の長さを取得
$serviceString -split "`n" # 行単位で分割
Out-Stringとは?

基本概念
Out-String
は、PowerShellオブジェクトを文字列表現に変換するコマンドレットです。
PowerShellが画面に表示する形式そのままの文字列を生成します。
基本構文
<InputObject> | Out-String
[-Width <Int32>]
[-NoNewline]
[<CommonParameters>]
最もシンプルな使用例:
Get-Process | Out-String
主要なパラメーター
パラメーター | 説明 | 例 |
---|---|---|
-Stream | 各行を個別の文字列として出力 | Out-String -Stream |
-Width | 出力の幅を指定 | Out-String -Width 120 |
基本的な使い方

オブジェクトを文字列に変換
# プロセス情報を文字列として取得
$processString = Get-Process | Out-String
Write-Host "データ型: $($processString.GetType().Name)" # String
# サービス情報を文字列として取得
$serviceString = Get-Service | Select-Object -First 5 | Out-String
-Streamパラメーターの使用
# Stream無し:全体が一つの文字列
$allInOne = Get-Process | Select-Object -First 3 | Out-String
Write-Host "行数: $(($allInOne -split "`n").Count)"
# Stream有り:各行が個別の文字列
$lineByLine = Get-Process | Select-Object -First 3 | Out-String -Stream
Write-Host "要素数: $($lineByLine.Count)"
3. 幅の制御
# デフォルトの幅で出力
Get-Process | Select-Object Name, CPU, WorkingSet | Out-String
# 幅を120文字に制限
Get-Process | Select-Object Name, CPU, WorkingSet | Out-String -Width 120
# 幅を無制限に設定
Get-Process | Select-Object Name, CPU, WorkingSet | Out-String -Width 4096
実践的な使用例

メール送信での活用
# システム情報をメールで送信
function Send-SystemReport {
param(
[string]$To,
[string]$From,
[string]$SmtpServer
)
# システム情報を文字列として取得
$computerInfo = Get-ComputerInfo | Select-Object WindowsProductName, TotalPhysicalMemory, CsProcessors | Out-String
$diskInfo = Get-WmiObject -Class Win32_LogicalDisk | Select-Object DeviceID, Size, FreeSpace | Out-String
$serviceInfo = Get-Service | Where-Object { $_.Status -eq "Stopped" } | Select-Object -First 10 | Out-String
# メール本文を構成
$body = @"
=== システムレポート ===
生成日時: $(Get-Date)
=== コンピューター情報 ===
$computerInfo
=== ディスク情報 ===
$diskInfo
=== 停止中のサービス(上位10件) ===
$serviceInfo
"@
# メール送信
Send-MailMessage -To $To -From $From -Subject "システムレポート" -Body $body -SmtpServer $SmtpServer
}
# 使用例
Send-SystemReport -To "admin@company.com" -From "server@company.com" -SmtpServer "smtp.company.com"
ログファイルへの出力
# システム監視ログの作成
function Write-SystemLog {
param([string]$LogPath = "C:\logs\system_monitor.log")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
# 各種情報を文字列として取得
$cpuInfo = Get-Counter "\Processor(_Total)\% Processor Time" | Out-String
$memoryInfo = Get-Counter "\Memory\Available MBytes" | Out-String
$diskInfo = Get-Counter "\PhysicalDisk(_Total)\% Disk Time" | Out-String
# ログエントリの作成
$logEntry = @"
=== $timestamp ===
CPU使用率:
$cpuInfo
メモリ情報:
$memoryInfo
ディスク使用率:
$diskInfo
================================
"@
# ログファイルに追記
Add-Content -Path $LogPath -Value $logEntry
}
# 定期実行の設定例
# Register-ScheduledTask などと組み合わせて使用
GUIアプリケーションでの表示
# Windows Formsを使用したシステム情報表示
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
function Show-SystemInfo {
# システム情報を文字列として取得
$systemInfo = @"
=== システム情報 ===
$(Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, TotalPhysicalMemory | Out-String)
=== プロセス情報(CPU使用率上位10件) ===
$(Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU, WorkingSet | Out-String)
=== サービス情報(停止中のサービス) ===
$(Get-Service | Where-Object { $_.Status -eq "Stopped" } | Select-Object -First 10 Name, Status | Out-String)
"@
# フォームの作成
$form = New-Object System.Windows.Forms.Form
$form.Text = "システム情報"
$form.Size = New-Object System.Drawing.Size(800, 600)
$form.StartPosition = "CenterScreen"
# テキストボックスの作成
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Multiline = $true
$textBox.ScrollBars = "Vertical"
$textBox.Font = New-Object System.Drawing.Font("Consolas", 9)
$textBox.Dock = "Fill"
$textBox.Text = $systemInfo
$textBox.ReadOnly = $true
# フォームにコントロールを追加
$form.Controls.Add($textBox)
# フォームを表示
$form.ShowDialog()
}
# 使用例
Show-SystemInfo
レポート生成
# 月次レポートの生成
function Generate-MonthlyReport {
param(
[string]$OutputPath = "C:\reports\monthly_$(Get-Date -Format 'yyyyMM').txt"
)
# レポートヘッダー
$header = @"
===============================
月次システムレポート
生成日時: $(Get-Date)
===============================
"@
# セキュリティイベントの集計
$securityEvents = Get-WinEvent -FilterHashtable @{LogName='Security'; StartTime=(Get-Date).AddDays(-30)} |
Group-Object Id |
Sort-Object Count -Descending |
Select-Object -First 10 Name, Count |
Out-String
# システムエラーの集計
$systemErrors = Get-WinEvent -FilterHashtable @{LogName='System'; Level=2; StartTime=(Get-Date).AddDays(-30)} |
Group-Object Id |
Sort-Object Count -Descending |
Select-Object -First 10 Name, Count |
Out-String
# アプリケーションエラーの集計
$appErrors = Get-WinEvent -FilterHashtable @{LogName='Application'; Level=2; StartTime=(Get-Date).AddDays(-30)} |
Group-Object Id |
Sort-Object Count -Descending |
Select-Object -First 10 Name, Count |
Out-String
# レポート本文の構成
$report = @"
$header
=== セキュリティイベント集計(過去30日間) ===
$securityEvents
=== システムエラー集計(過去30日間) ===
$systemErrors
=== アプリケーションエラー集計(過去30日間) ===
$appErrors
=== システム構成情報 ===
$(Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, TotalPhysicalMemory, CsProcessors | Out-String)
レポート終了
"@
# ファイルに出力
$report | Out-File -FilePath $OutputPath -Encoding UTF8
Write-Host "レポートを生成しました: $OutputPath"
}
高度な使用例

カスタム書式設定との組み合わせ
# カスタム書式でプロセス情報を整形
function Format-ProcessInfo {
param([int]$Top = 10)
$processes = Get-Process |
Sort-Object WorkingSet -Descending |
Select-Object -First $Top |
Format-Table @{
Label = "プロセス名"
Expression = { $_.ProcessName }
Width = 20
}, @{
Label = "PID"
Expression = { $_.Id }
Width = 8
Alignment = "Right"
}, @{
Label = "メモリ使用量(MB)"
Expression = { [math]::Round($_.WorkingSet / 1MB, 2) }
Width = 15
Alignment = "Right"
}, @{
Label = "CPU時間"
Expression = { $_.CPU }
Width = 10
Alignment = "Right"
} | Out-String
return $processes
}
# 使用例
$formattedProcesses = Format-ProcessInfo -Top 5
Write-Host $formattedProcesses
複数のオブジェクト型を統合したレポート
# 統合システムレポートの生成
function Get-ComprehensiveSystemReport {
$report = @()
# セクション1: システム基本情報
$report += "=== システム基本情報 ==="
$report += Get-ComputerInfo |
Select-Object WindowsProductName, WindowsVersion, TotalPhysicalMemory |
Format-List | Out-String
# セクション2: ディスク使用量
$report += "=== ディスク使用量 ==="
$report += Get-WmiObject -Class Win32_LogicalDisk |
Where-Object { $_.DriveType -eq 3 } |
Select-Object @{
Name = "ドライブ"
Expression = { $_.DeviceID }
}, @{
Name = "総容量(GB)"
Expression = { [math]::Round($_.Size / 1GB, 2) }
}, @{
Name = "使用済み(GB)"
Expression = { [math]::Round(($_.Size - $_.FreeSpace) / 1GB, 2) }
}, @{
Name = "空き容量(GB)"
Expression = { [math]::Round($_.FreeSpace / 1GB, 2) }
}, @{
Name = "使用率(%)"
Expression = { [math]::Round((($_.Size - $_.FreeSpace) / $_.Size) * 100, 1) }
} |
Format-Table -AutoSize | Out-String
# セクション3: ネットワークアダプター
$report += "=== ネットワークアダプター ==="
$report += Get-NetAdapter |
Where-Object { $_.Status -eq "Up" } |
Select-Object Name, InterfaceDescription, LinkSpeed |
Format-Table -AutoSize | Out-String
# セクション4: 実行中のサービス
$report += "=== 重要なサービス状態 ==="
$importantServices = @("Spooler", "BITS", "Workstation", "Server", "Themes", "UxSms")
$report += Get-Service -Name $importantServices -ErrorAction SilentlyContinue |
Select-Object Name, Status, StartType |
Format-Table -AutoSize | Out-String
return $report -join "`n"
}
# 使用例
$systemReport = Get-ComprehensiveSystemReport
$systemReport | Out-File -FilePath "C:\reports\system_report.txt" -Encoding UTF8
エラーハンドリング付きの安全な文字列変換
# 安全なOut-String関数
function ConvertTo-SafeString {
param(
[Parameter(ValueFromPipeline)]
$InputObject,
[int]$Width = 120,
[switch]$Stream,
[int]$MaxLength = 10000
)
begin {
$allObjects = @()
}
process {
$allObjects += $InputObject
}
end {
try {
$stringResult = if ($Stream) {
$allObjects | Out-String -Stream -Width $Width
} else {
$allObjects | Out-String -Width $Width
}
# 文字列長制限の適用
if (-not $Stream -and $stringResult.Length -gt $MaxLength) {
$truncated = $stringResult.Substring(0, $MaxLength)
$truncated += "`n... (truncated, original length: $($stringResult.Length) chars)"
return $truncated
}
return $stringResult
}
catch {
Write-Warning "Out-String conversion failed: $($_.Exception.Message)"
return $InputObject.ToString()
}
}
}
# 使用例
Get-Process | ConvertTo-SafeString -MaxLength 5000
他のコマンドレットとの比較・使い分け

Out-String vs Format-* コマンドレット
# Format-Tableは表形式のオブジェクトを返す
$formatted = Get-Process | Select-Object -First 5 | Format-Table
$formatted.GetType() # Microsoft.PowerShell.Commands.Internal.Format.*
# Out-Stringは文字列を返す
$stringified = Get-Process | Select-Object -First 5 | Format-Table | Out-String
$stringified.GetType() # System.String
# 直接的な使い分け例
# ファイル出力の場合
Get-Process | Format-Table | Out-File "processes.txt" # 推奨
Get-Process | Format-Table | Out-String | Out-File "processes.txt" # 冗長
Out-String vs ConvertTo-* コマンドレット
# データ変換の目的による使い分け
# 1. 人間が読むための表示用 → Out-String
$displayText = Get-Service | Select-Object -First 5 | Out-String
# 2. 構造化データとしての変換 → ConvertTo-*
$csvData = Get-Service | Select-Object -First 5 | ConvertTo-Csv
$jsonData = Get-Service | Select-Object -First 5 | ConvertTo-Json
$xmlData = Get-Service | Select-Object -First 5 | ConvertTo-Xml
# 3. 用途別の選択指針
# - メール本文、ログ表示 → Out-String
# - データ交換、API連携 → ConvertTo-Json
# - Excel取り込み → ConvertTo-Csv
# - システム間連携 → ConvertTo-Xml
Out-String vs ToString()メソッド
# 単一オブジェクトの場合
$process = Get-Process | Select-Object -First 1
# ToString()メソッド:オブジェクトの基本文字列表現
$toStringResult = $process.ToString()
Write-Host "ToString(): $toStringResult"
# Out-String:PowerShellの表示書式を適用
$outStringResult = $process | Out-String
Write-Host "Out-String:`n$outStringResult"
# 配列の場合の違い
$processes = Get-Process | Select-Object -First 3
# ToString():配列全体の型情報
$processes.ToString() # "System.Object[]"
# Out-String:各要素を整形して表示
$processes | Out-String # 詳細な表形式
パフォーマンスとメモリの考慮事項

大量データでのメモリ使用量
# メモリ効率的な処理の比較
function Compare-StringConversionMethods {
$testSize = 10000
# 方法1: Out-String(一括変換)
$time1 = Measure-Command {
$result1 = 1..$testSize | ForEach-Object { Get-Random } | Out-String
}
# 方法2: Out-String -Stream(ストリーミング)
$time2 = Measure-Command {
$result2 = 1..$testSize | ForEach-Object { Get-Random } | Out-String -Stream
}
# 方法3: ToString()の直接使用
$time3 = Measure-Command {
$result3 = 1..$testSize | ForEach-Object { (Get-Random).ToString() }
}
[PSCustomObject]@{
Method = @("Out-String", "Out-String -Stream", "ToString()")
Time = @($time1.TotalMilliseconds, $time2.TotalMilliseconds, $time3.TotalMilliseconds)
}
}
# パフォーマンステスト実行
$performanceResults = Compare-StringConversionMethods
$performanceResults | Format-Table -AutoSize
大容量データの効率的な処理
# 大容量ログファイルの処理例
function Process-LargeLogData {
param(
[string]$LogPath,
[string]$OutputPath,
[int]$BatchSize = 1000
)
$processedCount = 0
$batchContent = @()
# ストリーミング処理でメモリ効率を改善
Get-Content $LogPath | ForEach-Object {
$batchContent += $_
$processedCount++
# バッチサイズに達したら文字列化して出力
if ($processedCount % $BatchSize -eq 0) {
$stringOutput = $batchContent | Out-String
Add-Content -Path $OutputPath -Value $stringOutput
$batchContent = @()
Write-Progress -Activity "Processing" -PercentComplete (($processedCount / 100000) * 100)
}
}
# 残りのデータを処理
if ($batchContent.Count -gt 0) {
$stringOutput = $batchContent | Out-String
Add-Content -Path $OutputPath -Value $stringOutput
}
Write-Progress -Activity "Processing" -Completed
Write-Host "処理完了: $processedCount 行を処理しました"
}
トラブルシューティング(よくある問題と解決策)

出力が途中で切れる問題
# 問題:出力幅が制限されて情報が失われる
Get-Process | Out-String
# 解決策:幅を十分に大きく設定
Get-Process | Out-String -Width 200
# または幅制限を無効化
Get-Process | Out-String -Width ([int]::MaxValue)
改行コードの問題
# 問題:異なる環境での改行コードの違い
$output = Get-Process | Out-String
# 解決策:改行コードを統一
$output = $output -replace "`r`n", "`n" # Unix形式に統一
$output = $output -replace "`n", "`r`n" # Windows形式に統一
特殊文字やエンコーディングの問題
# 問題:特殊文字が含まれる場合の文字化け
$processInfo = Get-Process | Out-String
# 解決策:適切なエンコーディングでファイル出力
$processInfo | Out-File -FilePath "processes.txt" -Encoding UTF8
メモリ不足の問題
# 問題:大量データで OutOfMemoryException
$hugeOutput = Get-WmiObject Win32_Process | Out-String
# 解決策1: ストリーミング処理
Get-WmiObject Win32_Process | Out-String -Stream | ForEach-Object {
# 1行ずつ処理
}
# 解決策2: 分割処理
Get-WmiObject Win32_Process | Select-Object -First 100 | Out-String
実際の業務での活用例

監査ログの作成
# システム監査ログ生成スクリプト
function New-AuditLog {
param(
[string]$AuditPath = "C:\audit\system_audit_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
)
$auditStart = Get-Date
$auditData = @()
# 監査ヘッダー
$auditData += "=========================================="
$auditData += "システム監査ログ"
$auditData += "開始時刻: $auditStart"
$auditData += "=========================================="
$auditData += ""
# ユーザーアカウント監査
$auditData += "=== ローカルユーザーアカウント ==="
$auditData += Get-LocalUser | Select-Object Name, Enabled, LastLogon | Out-String
# グループメンバーシップ監査
$auditData += "=== 管理者グループメンバー ==="
$auditData += Get-LocalGroupMember -Group "Administrators" | Select-Object Name, ObjectClass | Out-String
# インストール済みソフトウェア監査
$auditData += "=== インストール済みソフトウェア(最新10件) ==="
$auditData += Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Where-Object { $_.DisplayName } |
Sort-Object InstallDate -Descending |
Select-Object -First 10 DisplayName, DisplayVersion, InstallDate |
Out-String
# ネットワーク設定監査
$auditData += "=== ネットワーク設定 ==="
$auditData += Get-NetIPAddress -AddressFamily IPv4 |
Where-Object { $_.IPAddress -ne "127.0.0.1" } |
Select-Object InterfaceAlias, IPAddress, PrefixLength |
Out-String
# 監査終了
$auditEnd = Get-Date
$auditData += "=========================================="
$auditData += "監査終了時刻: $auditEnd"
$auditData += "所要時間: $($auditEnd - $auditStart)"
$auditData += "=========================================="
# ファイル出力
$auditData | Out-File -FilePath $AuditPath -Encoding UTF8
Write-Host "監査ログを作成しました: $AuditPath"
}
定期レポートの自動生成
# 週次サーバーレポート生成
function New-WeeklyServerReport {
param(
[string]$ReportPath = "C:\reports\weekly_$(Get-Date -Format 'yyyyMMdd').html"
)
# HTMLテンプレート
$htmlTemplate = @"
<!DOCTYPE html>
<html>
<head>
<title>週次サーバーレポート</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.section { margin-bottom: 30px; }
.data { background-color: #f5f5f5; padding: 10px; font-family: monospace; white-space: pre-wrap; }
h2 { color: #333; border-bottom: 2px solid #ccc; }
</style>
</head>
<body>
<h1>週次サーバーレポート</h1>
<p>生成日時: $(Get-Date)</p>
<div class="section">
<h2>システム情報</h2>
<div class="data">$(Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, TotalPhysicalMemory | Out-String)</div>
</div>
<div class="section">
<h2>リソース使用状況</h2>
<div class="data">$(Get-Counter "\Processor(_Total)\% Processor Time", "\Memory\Available MBytes" | Out-String)</div>
</div>
<div class="section">
<h2>ディスク使用量</h2>
<div class="data">$(Get-WmiObject -Class Win32_LogicalDisk | Select-Object DeviceID, @{Name="サイズ(GB)";Expression={[math]::Round($_.Size/1GB,2)}}, @{Name="空き容量(GB)";Expression={[math]::Round($_.FreeSpace/1GB,2)}} | Out-String)</div>
</div>
<div class="section">
<h2>エラーイベント(過去7日間)</h2>
<div class="data">$(Get-WinEvent -FilterHashtable @{LogName='System'; Level=2; StartTime=(Get-Date).AddDays(-7)} | Select-Object -First 10 TimeCreated, Id, LevelDisplayName, Message | Out-String)</div>
</div>
</body>
</html>
"@
# HTMLファイル生成
$htmlTemplate | Out-File -FilePath $ReportPath -Encoding UTF8
Write-Host "週次レポートを生成しました: $ReportPath"
# ブラウザで開く
Start-Process $ReportPath
}
まとめ
PowerShellのOut-String
コマンドレットは、オブジェクト指向の世界と文字列ベースの処理を橋渡しする重要なツールです。
基本機能:
- PowerShellオブジェクトを文字列に変換
- 表示書式を保持した文字列化
- ストリーミング処理による効率的な変換
- 出力幅の制御
実践的な活用:
- メール本文への情報埋め込み
- ログファイルへの構造化データ保存
- GUIアプリケーションでの情報表示
- レポート生成とドキュメント作成
重要なポイント:
- メモリ使用量の最適化
- 大容量データの効率的な処理
- エンコーディングと文字化け対策
- 適切な出力幅の設定
コメント