Param(
[string]$Region = "ap-northeast-1",
[string]$OutputDir = "./iam-full-export",
[switch]$ExportPolicyDocuments = $false
)
# ---- 初期設定 ---------------------------------------------------
$policyDocsDir = Join-Path $OutputDir "policy-documents"
try {
New-Item -ItemType Directory -Path $OutputDir -ErrorAction SilentlyContinue | Out-Null
if ($ExportPolicyDocuments) {
New-Item -ItemType Directory -Path $policyDocsDir -ErrorAction SilentlyContinue | Out-Null
}
} catch {
Write-Error "出力ディレクトリ作成失敗: $($_.Exception.Message)"
exit 1
}
$logFile = Join-Path $OutputDir "iam-export-log-$(Get-Date -Format 'yyyyMMdd-HHmmss').txt"
Start-Transcript -Path $logFile -Append
Write-Host "=== IAM ユーザー情報収集開始 ===" -ForegroundColor Green
Write-Host "リージョン: $Region" -ForegroundColor Yellow
Write-Host "出力先: $OutputDir" -ForegroundColor Yellow
try {
# ---- IAM ユーザー一覧取得 ---------------------------------------------------
Write-Host "IAM ユーザー一覧取得中..." -ForegroundColor Cyan
$users = (aws iam list-users --region $Region --output json | ConvertFrom-Json).Users
if (!$users) { throw "IAM ユーザー一覧取得失敗" }
$totalUsers = $users.Count
Write-Host "対象ユーザー数: $totalUsers" -ForegroundColor Green
$results = @()
$count = 0
# ---- 各ユーザー処理 ---------------------------------------------------
foreach ($u in $users) {
$count++
$userName = $u.UserName
Write-Progress -Activity "IAM ユーザー処理中" -Status "$userName ($count/$totalUsers)" -PercentComplete (($count/$totalUsers)*100)
# 初期レコード生成
$info = [ordered]@{
UserName=""
UserId=""
Arn=""
CreateDate=""
ConsoleLoginEnabled="No"
ConsoleLoginStatus="無効"
PasswordLastUsed="Never"
MFAEnabled="No"
MFADeviceSerial=""
AccessKey1Id="" ; AccessKey1Status="" ; AccessKey1CreateDate="" ; AccessKey1LastUsed=""
AccessKey2Id="" ; AccessKey2Status="" ; AccessKey2CreateDate="" ; AccessKey2LastUsed=""
AccessKeysStatus="無効"
Groups=""
AttachedPolicies=""
InlinePolicies=""
LastActivityDate=""
AccountStatus="無効"
}
# 基本情報
$info.UserName = $userName
$info.UserId = $u.UserId
$info.Arn = $u.Arn
$info.CreateDate = $u.CreateDate.ToString("yyyy-MM-dd HH:mm:ss")
$consoleEnabled = $false
$activeKeys = 0
# ---- get-user(PasswordLastUsed) ----
try {
$g = aws iam get-user --user-name $userName --region $Region --output json | ConvertFrom-Json
if ($g.User.PasswordLastUsed) {
$info.PasswordLastUsed = $g.User.PasswordLastUsed.ToString("yyyy-MM-dd HH:mm:ss")
}
} catch {
Write-Warning "ユーザー $userName の詳細情報取得失敗: $($_.Exception.Message)"
}
# ---- Console Login ----
try {
$loginProfile = aws iam get-login-profile --user-name $userName --region $Region --output json | ConvertFrom-Json
if($loginProfile){
$consoleEnabled = $true
$info.ConsoleLoginEnabled = "Yes"
$info.ConsoleLoginStatus = "有効"
}
} catch {
Write-Warning "ユーザー $userName のログインプロファイル取得失敗: $($_.Exception.Message)"
}
# ---- MFA ----
try {
$mfa = aws iam list-mfa-devices --user-name $userName --region $Region --output json | ConvertFrom-Json
if ($mfa.MFADevices.Count) {
$info.MFAEnabled = "Yes"
$info.MFADeviceSerial = $mfa.MFADevices[0].SerialNumber
}
} catch {
Write-Warning "ユーザー $userName のMFAデバイス情報取得失敗: $($_.Exception.Message)"
}
# ---- Access Keys ----
try {
$keys = (aws iam list-access-keys --user-name $userName --region $Region --output json | ConvertFrom-Json).AccessKeyMetadata
for ($i=0; $i -lt $keys.Count; $i++) {
$kid = "AccessKey$($i+1)"
$info["${kid}Id"] = $keys[$i].AccessKeyId
$info["${kid}Status"] = $keys[$i].Status
$info["${kid}CreateDate"] = $keys[$i].CreateDate.ToString("yyyy-MM-dd HH:mm:ss")
if ($keys[$i].Status -eq "Active") {
$activeKeys++
}
try {
$lu = aws iam get-access-key-last-used --access-key-id $keys[$i].AccessKeyId --region $Region --output json | ConvertFrom-Json
if ($lu.AccessKeyLastUsed.LastUsedDate) {
$info["${kid}LastUsed"] = $lu.AccessKeyLastUsed.LastUsedDate.ToString("yyyy-MM-dd HH:mm:ss")
} else {
$info["${kid}LastUsed"] = "Never"
}
} catch {
$info["${kid}LastUsed"] = "Error"
Write-Warning "アクセスキー $($keys[$i].AccessKeyId) の使用状況取得失敗: $($_.Exception.Message)"
}
}
# アクセスキー全体の状態
$info.AccessKeysStatus = if ($activeKeys -gt 0) { "有効 ($activeKeys個)" } else { "無効" }
} catch {
Write-Warning "ユーザー $userName のアクセスキー情報取得失敗: $($_.Exception.Message)"
}
# ---- Groups ----
try {
$info.Groups = (
aws iam list-groups-for-user --user-name $userName --region $Region --output json |
ConvertFrom-Json | Select-Object -Expand Groups |
ForEach-Object { $_.GroupName }
) -join "|"
} catch {
Write-Warning "ユーザー $userName のグループ情報取得失敗: $($_.Exception.Message)"
}
# ---- Attached Policies ----
try {
$attach = (aws iam list-attached-user-policies --user-name $userName --region $Region --output json | ConvertFrom-Json).AttachedPolicies
$info.AttachedPolicies = ($attach | ForEach-Object { $_.PolicyName }) -join "|"
if ($ExportPolicyDocuments) {
foreach ($p in $attach) {
try {
$policy = aws iam get-policy --policy-arn $p.PolicyArn --region $Region --output json | ConvertFrom-Json
$ver = aws iam get-policy-version --policy-arn $p.PolicyArn --version-id $policy.Policy.DefaultVersionId --region $Region --output json | ConvertFrom-Json
($ver.PolicyVersion.Document | ConvertTo-Json -Depth 10) |
Out-File (Join-Path $policyDocsDir "$($userName)_$($p.PolicyName)_attached.json")
} catch {
Write-Warning "ポリシー $($p.PolicyName) のドキュメント取得失敗: $($_.Exception.Message)"
}
}
}
} catch {
Write-Warning "ユーザー $userName のアタッチ済みポリシー情報取得失敗: $($_.Exception.Message)"
}
# ---- Inline Policies ----
try {
$inline = (aws iam list-user-policies --user-name $userName --region $Region --output json | ConvertFrom-Json).PolicyNames
$info.InlinePolicies = $inline -join "|"
if ($ExportPolicyDocuments) {
foreach ($name in $inline) {
try {
$doc = aws iam get-user-policy --user-name $userName --policy-name $name --region $Region --output json | ConvertFrom-Json
($doc.PolicyDocument | ConvertTo-Json -Depth 10) |
Out-File (Join-Path $policyDocsDir "$($userName)_${name}_inline.json")
} catch {
Write-Warning "インラインポリシー $name のドキュメント取得失敗: $($_.Exception.Message)"
}
}
}
} catch {
Write-Warning "ユーザー $userName のインラインポリシー情報取得失敗: $($_.Exception.Message)"
}
# ---- LastActivityDate ----
$dates = @()
foreach ($k in @("PasswordLastUsed","AccessKey1LastUsed","AccessKey2LastUsed")) {
if ($info[$k] -and $info[$k] -notmatch "Never|Error") {
try {
$dates += [datetime]$info[$k]
} catch {
Write-Warning "日付変換エラー ($userName - $k): $($info[$k])"
}
}
}
$info.LastActivityDate = if ($dates.Count) {
($dates | Measure-Object -Maximum).Maximum.ToString("yyyy-MM-dd HH:mm:ss")
} else { "Never" }
# ---- アカウント状態判定 ----
if ($consoleEnabled -or $activeKeys -gt 0) {
if ($consoleEnabled -and $activeKeys -gt 0) {
$info.AccountStatus = "有効 (コンソール+API)"
} elseif ($consoleEnabled) {
$info.AccountStatus = "有効 (コンソール)"
} else {
$info.AccountStatus = "有効 (API)"
}
}
$results += [pscustomobject]$info
}
Write-Progress -Activity "完了" -Completed
# ---- CSV 出力 ---------------------------------------------------
$csv = Join-Path $OutputDir "iam-users-full-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv"
$results | Export-Csv -Path $csv -NoTypeInformation -Encoding UTF8
# 統計情報
$activeAccounts = ($results | Where-Object { $_.AccountStatus -match "有効" }).Count
$inactiveAccounts = ($results | Where-Object { $_.AccountStatus -eq "無効" }).Count
$consoleAccounts = ($results | Where-Object { $_.ConsoleLoginStatus -eq "有効" }).Count
$apiAccounts = ($results | Where-Object { $_.AccessKeysStatus -match "有効" }).Count
Write-Host "`n=== 完了:IAM ユーザー情報出力 ===" -ForegroundColor Green
Write-Host "CSV: $csv" -ForegroundColor Yellow
Write-Host "ログ: $logFile" -ForegroundColor Yellow
if ($ExportPolicyDocuments) { Write-Host "ポリシードキュメント: $policyDocsDir" -ForegroundColor Yellow }
Write-Host "`n=== アカウント状態統計 ===" -ForegroundColor Cyan
Write-Host "総ユーザー数: $totalUsers" -ForegroundColor White
Write-Host "有効アカウント: $activeAccounts" -ForegroundColor White
Write-Host "無効アカウント: $inactiveAccounts" -ForegroundColor White
Write-Host "コンソールログイン有効: $consoleAccounts" -ForegroundColor White
Write-Host "APIアクセス有効: $apiAccounts" -ForegroundColor White
} catch {
Write-Error "スクリプト実行エラー: $($_.Exception.Message)"
throw
} finally {
Stop-Transcript
}
# 基本実行
.\iam-export.ps1
# リージョン指定
.\iam-export.ps1 -Region us-east-1
# ポリシードキュメントも出力
.\iam-export.ps1 -ExportPolicyDocuments
# 出力ディレクトリ指定
.\iam-export.ps1 -OutputDir "C:\iam-backup"
コメント