自動化厨のプログラミングメモブログ │ CODE:LIFE

Python/VBA/GAS/JavaScript/Raspberry Piなどで色んなことを自動化

SharePoint Onlineの棚卸し。サイトごとのユーザー権限一覧を出力するPowerShellスクリプト

(この記事はClaude Sonnet 4により執筆しています)

はじめに

SharePoint Onlineを使っていると、気がつけばサイトが増えて権限管理が複雑になっていませんか?

「あのサイトには誰がアクセスできるんだっけ?」 「外部ユーザーに権限を与えすぎていないか確認したい」 「コンプライアンス監査のために権限一覧が必要」

そんな悩みを解決するために、SharePoint Onlineテナント内のすべてのサイト権限を一括で取得し、CSV形式で出力するPowerShellスクリプトを開発しました。

今回は、このツールの使い方と、開発中に遭遇したPnP.PowerShellモジュールのつまづきポイントとその解決策をご紹介します。

🎯 このツールでできること

主な機能

  • 全サイト権限監査: テナント内すべてのサイト(チームサイト、コミュニケーションサイト、OneDrive等)の権限設定を自動収集
  • 詳細情報取得: ユーザー名、ログイン名、メールアドレス、割り当てロールを包括的に取得
  • CSV出力: Excel等での分析に適したフォーマットで結果をエクスポート
  • 視覚的確認: Out-GridViewによる結果の即座確認

出力例

SiteUrl,Principal,LoginName,Email,Roles
https://contoso.sharepoint.com/sites/sales,田中太郎,i:0#.f|membership|tanaka@contoso.com,tanaka@contoso.com,編集
https://contoso.sharepoint.com/sites/sales,営業チーム,c:0o.c|federateddirectoryclaimprovider|abc123...,,"フル コントロール"
https://contoso.sharepoint.com/sites/hr,人事部グループ,c:0o.c|federateddirectoryclaimprovider|def456...,,編集

Out-GridViewでの結果表示画面

🚀 使い方

前提条件

このツールを使用する前に、以下の環境準備が必要です:

1. PowerShell 7.x のインストール

最新のPnP.PowerShellモジュールはPowerShell 7.x以上が必要です:

# PowerShellのバージョン確認
$PSVersionTable.PSVersion

PowerShell 7.xがインストールされていない場合:

2. Visual Studio Code のインストール

PowerShell 7.xではPowerShell ISEが使用できないため、VS Codeの使用を強く推奨します:

  • Visual Studio Code をダウンロード・インストール
  • PowerShell拡張機能をインストール(ms-vscode.powershell

VS Codeでの推奨設定:

{
    "powershell.powerShellDefaultVersion": "PowerShell (x64)",
    "terminal.integrated.defaultProfile.windows": "PowerShell"
}

📄 スクリプト全文

実際に使用するスクリプトファイルの全文をご紹介します。以下のコードをコピーして使用してください。

SPO-Setup.ps1(初回セットアップ用)

# SharePoint Online 初回セットアップスクリプト
# このスクリプトは初回のみ実行してください

Write-Host "SharePoint Online 初回セットアップを開始します..." -ForegroundColor Green

# テナントの設定(環境に合わせて変更してください)
$TenantName = "your-tenant.onmicrosoft.com"
$TenantUrl = "https://your-tenant.sharepoint.com"

# アプリケーションの設定(任意のアプリ名とパスワードに変更してください)
$ApplicationName = "sharepoint-client-ps"
$CertificatePassword = "YourSecurePassword123!"

# パスワードをSecureStringに変換
$SecureCertPassword = ConvertTo-SecureString -String $CertificatePassword -AsPlainText -Force

# 設定ファイルのパス
$configPath = ".\SharePointOnlineClientConfig.json"

Write-Host "1. PnP.PowerShellモジュールをインストールしています..." -ForegroundColor Yellow

# モジュールインストール(初回のみ)
if (!(Get-Module -ListAvailable -Name "PnP.PowerShell")) {
    Write-Host "PnP.PowerShellモジュールが見つかりません。インストールします..." -ForegroundColor Yellow
    Install-Module -Name "PnP.PowerShell" -Force -AllowClobber
    Write-Host "PnP.PowerShellモジュールのインストールが完了しました。" -ForegroundColor Green
}
else {
    Write-Host "PnP.PowerShellモジュールは既にインストールされています。" -ForegroundColor Green
}

# モジュール読み込み
Import-Module -Name "PnP.PowerShell"

Write-Host "2. Entra IDアプリケーションと証明書を生成しています..." -ForegroundColor Yellow

# 証明書とEntraIDアプリを生成
try {
    $appInfo = Register-PnPEntraIDApp -ApplicationName $ApplicationName -Tenant $TenantName -CertificatePassword $SecureCertPassword -Store CurrentUser

    Write-Host "Entra IDアプリケーションと証明書の生成が完了しました!" -ForegroundColor Green
    Write-Host "以下の情報をメインスクリプトに設定してください:" -ForegroundColor Cyan
    Write-Host "ClientID: $($appInfo.ClientId)" -ForegroundColor White
    Write-Host "証明書パス: $($appInfo.CertificatePath)" -ForegroundColor White

    # 設定ファイルに情報を保存
    $config = @{
        TenantName          = $TenantName
        TenantUrl           = $TenantUrl
        ClientID            = $appInfo.'AzureAppId/ClientId'
        CertificatePath     = $appInfo.'Pfx file'
        ApplicationName     = $ApplicationName
        CertificatePassword = $CertificatePassword
        SetupDate           = Get-Date
    }

    $config | ConvertTo-Json -Depth 3 | Out-File -FilePath $configPath -Encoding UTF8
    Write-Host "設定情報を $configPath に保存しました。" -ForegroundColor Green

}
catch {
    Write-Error "Entra IDアプリケーションの生成に失敗しました: $_"
    exit 1
}

Write-Host "初回セットアップが完了しました!" -ForegroundColor Green
Write-Host "次回からは 'SPO-PermissionAudit.ps1' を実行してください。" -ForegroundColor Cyan

SPO-PermissionAudit.ps1(メイン実行用)

# SharePoint Online 全サイト権限リストアップスクリプト
# 事前に 'SPO-Setup.ps1' を実行してください

Write-Host "SharePoint Online 全サイト権限リストアップを開始します..." -ForegroundColor Green

# 設定ファイルから情報を読み込み
$configPath = ".\SharePointOnlineClientConfig.json"

if (!(Test-Path $configPath)) {
    Write-Error "設定ファイルが見つかりません: $configPath"
    Write-Host "先に 'SPO-Setup.ps1' を実行してください。" -ForegroundColor Yellow
    exit 1
}

try {
    $config = Get-Content -Path $configPath -Encoding UTF8 | ConvertFrom-Json

    $TenantName = $config.TenantName
    $TenantUrl = $config.TenantUrl
    $ClientID = $config.ClientID
    $CertificatePath = $config.CertificatePath
    $CertificatePassword = $config.CertificatePassword

    Write-Host "設定ファイルから情報を読み込みました。" -ForegroundColor Green
} catch {
    Write-Error "設定ファイルの読み込みに失敗しました: $_"
    exit 1
}

# 出力先のCSVファイルパス
$OutputCsvPath = "AllSitePermissions.csv"

# パスワードをSecureStringに変換
$SecureCertPassword = ConvertTo-SecureString -String $CertificatePassword -AsPlainText -Force

# モジュール読み込み
if (!(Get-Module -Name "PnP.PowerShell")) {
    Import-Module -Name "PnP.PowerShell"
}

# テナントに接続
Connect-PnPOnline $TenantUrl -Tenant $TenantName -ClientID $ClientID -CertificatePath $CertificatePath -CertificatePassword $SecureCertPassword

# サイト一覧を取得(Communication, Team, Groupなどすべて)
$sites = Get-PnPTenantSite

# 結果格納用
$results = @()

foreach ($site in $sites) {
    Write-Host "処理中: $($site.Url)"
    try {
        Connect-PnPOnline -Url $site.Url -Tenant $TenantName -ClientID $ClientID -CertificatePath $CertificatePath -CertificatePassword $SecureCertPassword
        $web = Get-PnPWeb -Includes RoleAssignments, RoleDefinitions

        foreach ($assignment in $web.RoleAssignments) {
            Get-PnPProperty -ClientObject $assignment -Property RoleDefinitionBindings, Member
            $roles = ($assignment.RoleDefinitionBindings | ForEach-Object { $_.Name }) -join ", "

            try {
                $GroupMembers = Get-PnPGroupMember -Identity $assignment.Member.LoginName

                foreach ($member in $GroupMembers) {
                    $results += [PSCustomObject]@{
                        SiteUrl   = $site.Url
                        Principal = $member.Title
                        LoginName = $member.LoginName
                        Email     = $member.Email
                        Roles     = $roles
                    }
                }
            }
            catch {
                Write-Warning "グループメンバー取得失敗: $($site.Url) - $($assignment.Member.LoginName) - $_"
                # グループメンバーが取得できない場合は、グループ自体を結果に追加
                $results += [PSCustomObject]@{
                    SiteUrl   = $site.Url
                    Principal = $assignment.Member.Title
                    LoginName = $assignment.Member.LoginName
                    Email     = ""
                    Roles     = $roles
                }
            }
        }
    }
    catch {
        Write-Warning "失敗: $($site.Url) - $_"
    }
}

# 結果を表示
$results | Out-GridView -Title "全サイトのユーザー権限一覧"

# CSVに出力
$results | Export-Csv -Path $OutputCsvPath -NoTypeInformation -Encoding utf8BOM

Write-Host "CSVファイルに出力しました: $OutputCsvPath" -ForegroundColor Green
Write-Host "処理が完了しました。" -ForegroundColor Green

💡 使用前の注意事項

セットアップスクリプトの編集箇所

SPO-Setup.ps1の以下の部分を環境に合わせて変更してください:

# テナントの設定(環境に合わせて変更してください)
$TenantName = "your-tenant.onmicrosoft.com"        # ← 実際のテナント名
$TenantUrl = "https://your-tenant.sharepoint.com"  # ← 実際のテナントURL

# アプリケーションの設定
$ApplicationName = "sharepoint-client-ps"           # ← 任意のアプリ名
$CertificatePassword = "YourSecurePassword123!"     # ← 強固なパスワード

ファイル配置

以下のファイルを同じフォルダに配置してください:

SharePointOnline/
├── SPO-Setup.ps1                      # 初回セットアップ用
├── SPO-PermissionAudit.ps1            # メイン実行用
├── SharePointOnlineClientConfig.json  # 設定ファイル(自動生成)
├── [アプリ名].pfx                     # 証明書(自動生成)
├── [アプリ名].cer                     # 証明書(自動生成)
└── AllSitePermissions.csv             # 出力結果(自動生成)

🚀 セットアップと実行手順

1. 初回セットアップ

環境準備とスクリプトのダウンロードが完了したら、セットアップを実行します:

# SharePointOnlineフォルダに移動
cd "C:\Scripts\SharePointOnline\"

# 初回セットアップを実行
.\SPO-Setup.ps1

セットアップスクリプトが以下を自動実行:

  1. PnP.PowerShellモジュールのインストール
  2. Entra ID(Azure AD)アプリケーションの作成
  3. 証明書の生成とアプリケーションへの登録
  4. 設定ファイルの作成

Out-GridViewでの結果表示画面

2. 権限監査の実行

セットアップ完了後は、シンプルに実行できます:

# 権限監査実行
.\SPO-PermissionAudit.ps1

実行が完了すると: - Out-GridViewで結果をプレビュー表示 - AllSitePermissions.csvにフル結果を出力

📊 実行結果の活用方法

Excel での分析

CSVファイルをExcelで開いて:

  • フィルター機能: 特定のサイトやユーザーの権限を絞り込み
  • ピボットテーブル: ロール別の権限分布を分析
  • 条件付き書式: 外部ユーザーや高権限ユーザーをハイライト

#ext#を含むユーザーを条件付き書式ハイライト

権限監査のポイント

  1. 外部ユーザーの確認: Email列で#ext#を含むアカウントをチェック
  2. 高権限の監査: Roles列で「フル コントロール」を持つユーザーを確認
  3. 孤立したアクセス: 異動したユーザーの権限が残っていないかチェック

⚡ パフォーマンス最適化のポイント

このスクリプトでは、以下の最適化を実装しています:

1. 効率的な権限取得

# サイトごとに権限情報を取得
$web = Get-PnPWeb -Includes RoleAssignments, RoleDefinitions

foreach ($assignment in $web.RoleAssignments) {
    Get-PnPProperty -ClientObject $assignment -Property RoleDefinitionBindings, Member
    $roles = ($assignment.RoleDefinitionBindings | ForEach-Object { $_.Name }) -join ", "
}

2. エラーハンドリング

try {
    Connect-PnPOnline -Url $site.Url -Tenant $TenantName -ClientID $ClientID -CertificatePath $CertificatePath -CertificatePassword $SecureCertPassword
    $web = Get-PnPWeb -Includes RoleAssignments, RoleDefinitions
    # 権限処理...
} catch {
    Write-Warning "失敗: $($site.Url) - $_"
}

3. グループメンバー展開の適切な処理

try {
    $GroupMembers = Get-PnPGroupMember -Identity $assignment.Member.LoginName
    # メンバーごとに結果に追加
} catch {
    Write-Warning "グループメンバー取得失敗: $($site.Url) - $($assignment.Member.LoginName)"
    # グループ自体を結果に追加
    $results += [PSCustomObject]@{
        SiteUrl   = $site.Url
        Principal = $assignment.Member.Title
        LoginName = $assignment.Member.LoginName
        Email     = ""
        Roles     = $roles
    }
}

実行時間の目安

  • 小規模環境(~50サイト): 5-15分
  • 中規模環境(50-200サイト): 15-60分
  • 大規模環境(200+サイト): 1時間以上

🔧 PnP.PowerShellのつまづきポイントと解決策

開発中に遭遇した主要な問題と解決方法をご紹介します。

0. 環境要件の課題

問題:

PnP.PowerShell モジュールがWindows PowerShell(5.1)で正常に動作しない
PowerShell ISEでデバッグができない

解決策:

PowerShell 7.x + VS Code環境の構築:

# 1. PowerShell 7.xのバージョン確認
$PSVersionTable.PSVersion
# Major: 7, Minor: 4 以上が必要

# 2. VS CodeでPowerShellターミナルを開く
# Ctrl+Shift+P → "PowerShell: Show Integrated Console"

# 3. VS CodeでのPowerShell設定確認
Get-Host
# Name: Visual Studio Code Host が表示されればOK

重要なポイント:

  • Windows PowerShell(青いアイコン)ではなく、PowerShell 7.x(黒いアイコン)を使用
  • PowerShell ISEは使用不可のため、VS Code + PowerShell拡張で代替
  • ターミナルの既定設定をPowerShell 7.xに変更推奨

PowerShell 7.x

1. モジュールインストールエラー

問題:

Install-Module : パッケージ 'PnP.PowerShell' が見つかりませんでした
または
Import-Module : 指定されたモジュール 'PnP.PowerShell' が読み込まれませんでした

解決策:

# PowerShell 7.xで実行(重要!)
# 管理者権限でPowerShellを起動し、信頼できるリポジトリを設定
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name PnP.PowerShell -Force -AllowClobber -Scope CurrentUser

# インストール確認
Get-Module -ListAvailable -Name PnP.PowerShell

2. 証明書認証の設定

問題:

Connect-PnPOnline : AADSTS70002: Error validating credentials
または
Register-PnPEntraIDApp : 権限が不足しています

解決策: 証明書ベース認証の正しい設定手順:

# PowerShell 7.x + VS Codeで実行
# 2. Entra IDアプリの作成と証明書登録
$appInfo = Register-PnPEntraIDApp -ApplicationName "sharepoint-client-ps" -Tenant "your-tenant.onmicrosoft.com" -CertificatePassword $SecureCertPassword -Store CurrentUser

3. 権限取得エラー

問題:

Get-PnPRoleAssignment : アクセスが拒否されました
または
Get-PnPTenantSite : 権限が不足しています

解決策: Entra IDアプリケーションに最低限必要な権限を追加:

  • Sites.Read.All: すべてのサイトコレクションの読み取り
  • Group.Read.All: Entra IDグループ情報の読み取り
  • User.Read.All: ユーザー情報の読み取り

必要なアクセス許可

4. 大量サイト処理時のタイムアウト

問題:

Connect-PnPOnline : リクエストがタイムアウトしました
または
処理が途中で停止する

解決策: 接続リトライロジックの実装:

# PowerShell 7.x + VS Codeでの安定した処理
foreach ($site in $sites) {
    Write-Host "処理中: $($site.Url)"
    try {
        Connect-PnPOnline -Url $site.Url -Tenant $TenantName -ClientID $ClientID -CertificatePath $CertificatePath -CertificatePassword $SecureCertPassword
        $web = Get-PnPWeb -Includes RoleAssignments, RoleDefinitions
        # 権限処理を継続...
    } catch {
        Write-Warning "失敗: $($site.Url) - $_"
        # 次のサイトに進む
        continue
    }
}

🔒 セキュリティ考慮事項

機密情報の保護

  • 証明書ファイル: .pfxファイルは適切に保護
  • 設定ファイル: 機密情報を含む設定ファイルのアクセス制御
  • 実行ログ: 個人情報を含む可能性があるため適切に管理

📈 定期実行の設定

権限監査を定期的に実行する場合は、Windowsタスクスケジューラーを活用:

REM タスクスケジューラー用バッチファイル
cd /d "C:\Scripts\SharePointOnline\"
powershell.exe -ExecutionPolicy Bypass -File ".\SPO-PermissionAudit.ps1"
pause

まとめ

SharePoint Onlineの権限管理は複雑になりがちですが、この自動化ツールにより:

  • 効率化: 手動での確認作業を大幅短縮
  • 可視化: 権限状況を一覧で把握可能
  • 監査対応: コンプライアンス要件への対応を支援

PnP.PowerShellは強力なツールですが、認証周りで躓きやすいポイントがあります。今回紹介した解決策を参考に、ぜひ権限監査の自動化にチャレンジしてみてください。

セキュリティとガバナンスの向上に、このツールが役立てば幸いです。


参考情報: - PnP PowerShell 公式ドキュメント - Microsoft 365 コンプライアンス センター

注意: 本ツールは動作確認済みですが、しっかりと内容をご確認の上ご利用ください。