NTFSアクセス権を一覧化するなら、Get-Aclで各フォルダーのACLを読み取り、Access内のACEを1行ずつ展開してCSVへ出します。最初に対象ルートを一つへ限定し、Get-ItemとGet-Aclで読み取れること、出力先が対象ツリーの外にあり必要担当者だけ読めることを確認してください。この記事のスクリプトはACLを変更せず、所有者、継承保護、IdentityReference、許可/拒否、権利、継承元を保持します。Get-Acl | Select-Object *だけをCSV化するとAccessが文字列へ潰れ、実用的な一覧になりません。
出力する列と監査範囲を決める
- Path:対象ファイルまたはフォルダーの完全パス。機密なプロジェクト名を含むことがある。
- Owner:所有者。SID表示になる場合も変換せず証拠として保持する。
- AreAccessRulesProtected:継承が保護されているか。Trueなら親からの通常継承が遮断されている。
- IdentityReference:ユーザーまたはグループ。解決不能SIDも欠落させない。
- AccessControlType:AllowまたはDeny。Denyを除外しない。
- FileSystemRights、InheritanceFlags、PropagationFlags、IsInherited:権利と継承の意味を再現する列。
- Error:アクセス拒否、消失、長いパス等を成功行と分けて記録する。
対象が共有フォルダーなら、NTFS ACLだけでなくSMB共有アクセス権も実効アクセスへ影響します。本記事のCSVはNTFSの明示・継承ACEを棚卸しするもので、共有権限、ユーザーのグループ展開、条件付きACE、ユーザー権利、アプリ側認可を合成した「実効アクセス」を保証しません。目的をNTFS ACLのスナップショットと明記します。
最初はルート1件だけを確認する
$root = 'D:\Data\Finance'
Get-Item -LiteralPath $root | Select-Object FullName, Attributes, LastWriteTime
$acl = Get-Acl -LiteralPath $root
$acl | Select-Object Path, Owner, AreAccessRulesProtected
$acl.Access | Select-Object IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags
-LiteralPathを使うと角括弧等をワイルドカードとして解釈しません。権限不足のまま管理者へ昇格すると結果件数が変わるため、監査要件に応じて専用読み取りアカウントを使い、誰の権限で取得したか記録します。所有権取得やバックアップ特権の乱用で読める状態へ変えません。
フォルダーACLをCSVへ出す実用例
$root = 'D:\Data\Finance'
$out = 'D:\AuditOutput\finance-folder-acl.csv'
$errors = 'D:\AuditOutput\finance-folder-acl-errors.csv'
$items = @((Get-Item -LiteralPath $root -ErrorAction Stop)) + @(
Get-ChildItem -LiteralPath $root -Directory -Recurse -Force -ErrorAction SilentlyContinue
)
$rows = foreach ($item in $items) {
try {
$acl = Get-Acl -LiteralPath $item.FullName -ErrorAction Stop
foreach ($ace in $acl.Access) {
[pscustomobject]@{
Path = $item.FullName
Owner = $acl.Owner
AreAccessRulesProtected = $acl.AreAccessRulesProtected
IdentityReference = $ace.IdentityReference.Value
FileSystemRights = $ace.FileSystemRights.ToString()
AccessControlType = $ace.AccessControlType.ToString()
IsInherited = $ace.IsInherited
InheritanceFlags = $ace.InheritanceFlags.ToString()
PropagationFlags = $ace.PropagationFlags.ToString()
}
}
} catch {
[pscustomobject]@{ Path = $item.FullName; Error = $_.Exception.Message } |
Export-Csv -LiteralPath $errors -Append -NoTypeInformation -Encoding utf8
}
}
$rows | Export-Csv -LiteralPath $out -NoTypeInformation -Encoding utf8
例はフォルダーだけを対象にし、ルート自身を明示的に加えます。-Forceは隠し項目を列挙しますが、アクセス制御を回避しません。Get-ChildItem側の非終端エラーをSilentlyContinueにすると画面ノイズは減りますが、列挙できなかったサブツリーを捕捉しにくいため、本番版では-ErrorVariableやtry/catchを使って列挙エラーも別CSVへ記録します。エラー0件と仮定しません。
エラーを失わない改良
$enumerationErrors = @()
$children = Get-ChildItem -LiteralPath $root -Directory -Recurse -Force -ErrorAction SilentlyContinue -ErrorVariable +enumerationErrors
$enumerationErrors | ForEach-Object {
[pscustomobject]@{ Stage = 'Enumeration'; Target = $_.TargetObject; Message = $_.Exception.Message }
} | Export-Csv -LiteralPath $errors -NoTypeInformation -Encoding utf8
ACL取得エラーと列挙エラーを同じError列へ混ぜず、Stageを追加すると再試験対象が分かります。処理中にフォルダーが移動・削除されると、列挙後のGet-Aclで不在になることがあります。共有利用が少ない時間帯を選び、開始・終了時刻、対象ルート、件数、エラー件数を記録します。エラー行を落として「全件成功」と報告しません。
ファイルも対象にする場合
ファイル単位ACLが必要な監査だけ、-Directoryを外してファイルを含めます。数百万ファイルでは時間、I/O、CSV容量、ウイルス対策スキャン、共有性能へ影響します。まずMeasure-Objectで概数を取り、部署や第1階層ごとに分割し、処理時間と容量を見積もります。ACLがフォルダー継承だけなら、フォルダーの継承境界を優先する方が実務的です。
再解析ポイントやジャンクションを含むツリーでは、意図しない別ボリューム、循環、重複の可能性があります。AttributesにReparsePointがある項目を事前抽出し、追跡するか除外するかを監査範囲に明記します。対象を推測で再帰し続けず、解決後のパスが承認ルート内か確認します。
長いパスとPowerShell版の注意
Windowsの長いパス対応は、OSポリシーを有効にするだけで全アプリが自動対応するわけではなく、アプリ側のlongPathAware対応も必要です。Windows PowerShell 5.1とPowerShell 7、プロバイダー、利用APIで結果が異なる可能性があります。長いパスのエラーが出たら、まずPowerShell版と失敗パスを記録し、代表パスでPowerShell 7を検証します。
拡張長パス接頭辞を機械的に全パスへ付けると、相対要素やUNC表記が変わり、コマンドレットごとの対応差が出ます。本番スクリプトへ入れる前にローカルとUNCの双方でテストします。長いパスを有効化するGPOやレジストリ変更は端末全体へ影響するため、ACL出力の途中で行わず別変更として承認・再起動・戻し方を設計します。
CSVの保護と検証
パス、ユーザー名、グループ名、権利は攻撃者に有用な情報です。出力先は監査担当だけが読めるフォルダーにし、対象ツリーの中、Web公開領域、一般共有、ユーザーの同期フォルダーへ置きません。CSVをExcelで開く場合、先頭が=、+、-、@の値を式として扱うCSVインジェクションにも注意し、信頼できないパス名を含むファイルは保護ビューや安全なインポート方法を使います。
- ルート自身がCSVに含まれることを確認する。
- 対象フォルダー数、ACE行数、継承・明示、Allow・Denyの各件数を集計する。
- 代表フォルダーをGet-Aclの画面出力およびセキュリティ詳細設定と突き合わせる。
- 解決不能SID、空のAccess、アクセス拒否、長いパス、再解析ポイントを抽出する。
- CSVとエラーCSVのハッシュ、取得時刻、PowerShell版、実行アカウントを記録する。
変更や復元は別工程にする
このCSVをSet-Acl、icacls /restore、アクセスルール作成へ直接流し込まないでください。文字列化した権利、ACE順序、継承、所有者、SACLを完全復元できるバックアップ形式ではありません。変更が必要なら、対象パスを限定し、Get-Aclのオブジェクト保存やicacls /save等の対応手段、バックアップ、承認、テスト、実効アクセス検証、個別ロールバックを別計画にします。
CSV取得中はACL、所有者、継承を一切変更しません。読み取れない場所があれば権限を奪取せず、所有部署と管理者へエラー一覧を渡します。再取得時は前回と同じ版・スコープ・アカウントを使い、差分が実変更なのか取得条件の差なのかを区別します。

コメント