SharePoint Online 外部ユーザー一覧を取得する方法|リンク共有ゲストをPowerShellでCSV出力

SharePoint Online で外部ユーザーにリンク共有したものの、テナント全体で「誰に共有しているか」を一覧化できず困ることがあります。本記事では、標準レポートの限界と、PowerShell で全サイトを走査してゲストユーザーをCSV化する実践手順を解説します。

目次

この記事でわかること

  • SharePoint Online の標準機能だけでは「リンク共有された外部ユーザー」をテナント横断で一覧化しにくい理由
  • SharePoint Online Management Shell(PowerShell)で、全サイトコレクションを走査して外部ユーザー(ゲスト)を抽出し、CSVに出力する方法
  • 「外部ユーザー一覧」と「共有リンクの実態」が必ずしも一致しないケースと、棚卸し精度を上げる考え方

SharePoint Onlineで「リンク共有された外部ユーザー」を一覧取得したい、が難しい理由

SharePoint Online では、ドキュメント ライブラリやフォルダーを「右クリック → アクセスの管理 → 共有」から外部ユーザーに共有できます。しかし、テナント全体で“外部ユーザー(ゲスト)だけの一覧”を取りたいと思っても、標準のレポート機能だけで完結させるのは簡単ではありません。

なぜなら SharePoint の外部共有は「ユーザー」ではなく「リンク(共有方法)」が中心に設計されており、共有の種類(特定ユーザー向け/匿名リンクなど)によって、外部ユーザーがゲストとして残るかどうかが変わるからです。

まず押さえる:外部共有の種類と“外部ユーザーとして残るか”の違い

外部共有は、同じ“外部”でも挙動が複数あります。ここを整理しないと、PowerShell の取得結果が「少ない/多い」「意図と違う」と感じやすくなります。

共有の形相手のサインインゲスト(外部ユーザー)として残る可能性PowerShellでの一覧化実務上の注意
特定のユーザー向けリンク(Specific people)基本的に必須高い(サイトのユーザー一覧に出やすい)比較的しやすい「誰に共有したか」を追いやすい。棚卸しの中心に向く
匿名リンク(Anyone / 匿名リンク)不要低い(ユーザーとして記録されないことがある)難しい“リンクを知っている人”がアクセスできるため、可否の設計が重要
組織内限定リンク必須外部ユーザーは対象外対象外社内共有。今回の要件からは除外

この記事で紹介する PowerShell の方法で取得できるのは、主に「SharePoint 側にゲストとして存在している外部ユーザー」です。匿名リンクでアクセスしているだけの相手を“ユーザー一覧”として特定することは、仕組み上むずかしい点を先に理解しておきましょう。

標準レポートだけで「外部ユーザー一覧」を直接取得できない

SharePoint の管理画面には「外部ユーザーと共有されているコンテンツ(Shared with external users)」のようなレポートがありますが、そこに出るのは共有されているファイルやリンクの情報が中心です。テナント全体の外部ユーザー(ゲスト)だけを横断的に抜き出して、一覧(CSV)として出力する用途には向きません。

確認場所見えるもの見えにくいもの向いている用途
サイトの使用状況/共有レポート外部共有されているコンテンツの傾向外部ユーザーの一覧(メールアドレスを横断で集計など)「外部共有が多いサイト」を俯瞰する
個別ファイルの「アクセスの管理」そのアイテムの共有相手、リンクの種類テナント全体の集計、棚卸しピンポイント調査

そこで代替策として、SharePoint Online Management Shell(PowerShell)で各サイトコレクションから外部ユーザーを抽出し、CSV に出力して一覧化します。

PowerShellでテナント全体の外部ユーザーを一覧取得する全体像

  1. SharePoint 管理センター(https://<tenant>-admin.sharepoint.com)へ接続
  2. テナント配下のサイトコレクションを列挙(Get-SPOSite)
  3. 各サイトでユーザー一覧を取得(Get-SPOUser)
  4. 外部ユーザー(ゲスト)に該当するものだけ抽出(UserType / LoginName パターン)
  5. CSVへ出力して棚卸し・集計(Excel / Power BI)

前提条件

  • SharePoint 管理者(またはそれ相当の権限)
  • SharePoint Online Management Shell(モジュール:Microsoft.Online.SharePoint.PowerShell)

認証の注意(MFA環境では“対話ログイン”が必要になることがある)

環境によっては Get-Credential を使った接続がうまくいかないことがあります。特に多要素認証(MFA)を強制している場合は、対話ログイン(サインイン画面)を経由する接続が必要になることがあります。まずはテスト用端末で実行し、接続方法を確定させてから運用へ組み込むのが安全です。

基本サンプル:全サイトから外部ユーザーを抽出してCSVに出力

以下は、全サイトコレクションを対象に Get-SPOUser を実行し、LoginName に含まれるパターンで外部ユーザーを抽出する基本形です。

# SharePoint Online 管理シェル モジュールの読み込み
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking

# 設定値(自分のテナントに合わせて変更)
$AdminSiteURL = "https://<テナント名>-admin.sharepoint.com"
$ReportOutput = "C:\Temp\ExternalUsersRpt.csv"

# 接続に使用する資格情報の取得(MFA環境では別方式が必要になる場合があります)
$Cred = Get-Credential

# テナント管理センターに接続
Connect-SPOService -URL $AdminSiteURL -Credential $Cred

# 全サイトコレクションを取得
$SitesCollection = Get-SPOSite -Limit ALL

$ExternalUsers = @()

# 各サイトコレクションをループ
ForEach ($Site in $SitesCollection) {

    Write-Host -ForegroundColor Yellow "Checking Site Collection: $($Site.URL)"

    # サイトコレクション内の外部ユーザーを取得
    $ExtUsers = Get-SPOUser -Limit All -Site $Site.URL |
        Where-Object {
            $_.LoginName -like "*#ext#*" -or
            $_.LoginName -like "*urn:spo:guest*"
        }

    if ($ExtUsers.Count -gt 0) {
        Write-Host -ForegroundColor Green "Found $($ExtUsers.Count) External User(s)!"
        $ExternalUsers += $ExtUsers
    }
}

# 外部ユーザー一覧を CSV に出力
$ExternalUsers | Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8

ポイント

  • Get-SPOSiteでテナント内の全サイトコレクションを取得します。
  • Get-SPOUserでサイトごとのユーザーを列挙し、LoginName のパターン(#ext# / urn:spo:guest)でゲストユーザーを判別します。
  • 最後に CSV へ出力して、Excel でフィルター・ピボット集計ができます。

外部ユーザー判定の代替:UserTypeで「Guest」を抽出する

PowerShell 上では、UserType が Guest のユーザーを抽出する書き方も使えます。読みやすいので、LoginName パターンと併用するのがおすすめです。

Get-SPOUser -Site $Site.URL -Limit All |
    Where-Object { $_.UserType -eq "Guest" }

実務で効く改善:サイトURL付きでCSV化して“どこにいるか”を見える化

外部ユーザー棚卸しで必ず聞かれるのが「そのゲストはどのサイトで使われているの?」です。取得時点で SiteUrl を付与しておけば、後から調査し直す手間を大幅に減らせます。

$ExtUsers = Get-SPOUser -Limit All -Site $Site.URL |
    Where-Object {
        $_.UserType -eq "Guest" -or
        $_.LoginName -like "*#ext#*" -or
        $_.LoginName -like "*urn:spo:guest*"
    } |
    Select-Object DisplayName, LoginName, Email, UserType, IsSiteAdmin,
        @{Name="SiteUrl"; Expression = { $Site.URL }}

$ExternalUsers += $ExtUsers

CSVに出しておくと便利な列

列名用途優先度
SiteUrlどのサイトに属する外部ユーザーか把握高
LoginName抽出条件の核/重複排除のキーに使いやすい高
Email相手の特定(空欄になる場合あり)中
UserTypeGuest 判定の補助中
IsSiteAdmin外部ユーザーの権限が強すぎないか確認高

運用向けスクリプト:失敗サイトをログに残しつつ最後まで走らせる

サイト数が多いと、ロック中サイトや状態の違いで一部失敗することがあります。運用に組み込むなら、try/catchで失敗サイトをログに残しつつ、最後まで走り切る形にしておくのがおすすめです。

Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking

$AdminSiteURL = "https://<テナント名>-admin.sharepoint.com"
$OutDir = "C:\Temp"
$TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
$ReportOutput = Join-Path $OutDir ("ExternalUsers_" + $TimeStamp + ".csv")
$ErrorLog = Join-Path $OutDir ("ExternalUsers_Error_" + $TimeStamp + ".log")

# 接続(環境により対話ログインが必要な場合があります)
Connect-SPOService -URL $AdminSiteURL

# 必要に応じて -IncludePersonalSite $true で OneDrive 個人サイトも含められます(件数が増える点に注意)
$SitesCollection = Get-SPOSite -Limit ALL

$Results = New-Object System.Collections.Generic.List[object]

foreach ($Site in $SitesCollection) {
    Write-Host ("Checking: " + $Site.Url) -ForegroundColor Yellow

    try {
        $Users = Get-SPOUser -Site $Site.Url -Limit All |
            Where-Object {
                $_.UserType -eq "Guest" -or
                $_.LoginName -like "*#ext#*" -or
                $_.LoginName -like "*urn:spo:guest*"
            }

        foreach ($U in $Users) {
            $Results.Add([PSCustomObject]@{
                SiteUrl     = $Site.Url
                DisplayName = $U.DisplayName
                Email       = $U.Email
                LoginName   = $U.LoginName
                UserType    = $U.UserType
                IsSiteAdmin = $U.IsSiteAdmin
            })
        }
    }
    catch {
        $msg = ("[{0}] {1} : {2}" -f (Get-Date), $Site.Url, $_.Exception.Message)
        Add-Content -Path $ErrorLog -Value $msg
        Write-Host $msg -ForegroundColor Red
        continue
    }
}

$Results |
    Sort-Object SiteUrl, LoginName |
    Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8

この一覧は「アクセス権を持つ人の確定リスト」ではない点に注意

Get-SPOUser はサイトの「ユーザー情報」に存在するユーザーを返します。過去に共有されていたが今は権限が外れている、あるいは一度アクセスしただけで残っている、といったケースでも一覧に出ることがあります。棚卸しでは次の順で精度を上げるのが現実的です。

  • まずは本記事の方法で外部ユーザー候補を全量把握する
  • 外部共有が多いサイトや、機密度の高いサイトから優先的に、リンク種別やサイト権限(メンバー/閲覧者)を確認する
  • 不要なゲストは整理(共有解除、権限削除、運用ルール化)する

集計のコツ:CSVを「棚卸し資料」に変換する

CSVを出しただけでは意思決定(削除する/継続する/期限を付ける)につながりにくいので、次の観点で集計すると“使えるレポート”になります。

外部ユーザーごとに「所属サイト数」を出す

$data = Import-Csv "C:\Temp\ExternalUsers_yyyyMMdd_HHmmss.csv"

$data |
Group-Object LoginName |
Sort-Object Count -Descending |
Select-Object @{Name="LoginName";Expression={$_.Name}}, Count |
Export-Csv "C:\Temp\ExternalUsers_ByUser.csv" -NoTypeInformation -Encoding UTF8

サイトごとに「外部ユーザー数」を出す

$data = Import-Csv "C:\Temp\ExternalUsers_yyyyMMdd_HHmmss.csv"

$data |
Group-Object SiteUrl |
Sort-Object Count -Descending |
Select-Object @{Name="SiteUrl";Expression={$_.Name}}, Count |
Export-Csv "C:\Temp\ExternalUsers_BySite.csv" -NoTypeInformation -Encoding UTF8

この2種類を用意しておくと、

  • 「特定の外部ユーザーが広範囲にアクセスしていないか」
  • 「外部共有が集中しているサイトはどこか」

を短時間で把握できます。監査対応や情報漏えい対策でも、そのまま資料に転用しやすい形です。

重要:この方法で拾えない(拾いにくい)ケース

外部共有のすべてが「ゲストユーザー」という形で残るとは限りません。特に次のパターンは認識ズレが起きやすいので注意してください。

ケースなぜ拾えない/拾いにくいか現場での補完策
匿名リンク(Anyoneリンク)個人を特定せず「リンク」だけでアクセスできるため、ユーザーとして一覧化できない匿名リンクを禁止、または期限・パスワード必須にする。リンクの棚卸しを別途行う
一時的な共有・短期アクセス監査ログには残っても、サイトユーザーとして定着しない場合がある共有イベントの監査ログと突合し、“いつ誰に共有したか”を追跡する
過去の共有の残骸(使われていないゲスト)権限が外れてもユーザー情報に残ることがある優先順位を付けてレビューし、不要なゲストは整理する(運用ルール化)

セキュリティとガバナンス:外部共有を“管理できる状態”にする

外部共有は便利な一方、運用が崩れると「どこで、誰に、何が共有されているのか」が追えなくなります。棚卸しを楽にするためにも、次のようなルールを先に決めておくと効果的です。

ルール狙い具体例
共有リンクの種類を制限個人特定できない共有を減らす匿名リンクを禁止し、特定ユーザー向けリンクを基本にする
外部共有の期限を設ける共有が放置されるのを防ぐプロジェクト終了日+30日で共有解除する運用
棚卸しの定期実施ゲストの肥大化を防ぐ月次でCSVを出して差分確認、四半期でサイトオーナーにレビュー依頼
外部ユーザーの権限を最小化漏えい時の影響を限定外部ユーザーをサイト管理者にしない、編集権限は原則付与しない

よくあるエラーと対処

テナント全体を回すと、環境差によるエラーに遭遇しやすいです。代表例を表にまとめます。

症状原因の例対処の方向性
一部サイトで Access denied権限不足、サイトがロック中、削除保留など管理者権限とサイト状態を確認。原因が取れるまで対象サイトを一旦除外して切り分け
取得が極端に遅いサイト数が多い、ネットワーク遅延、スロットリング対象サイトを絞る/実行時間帯を変える/ログを残して最後まで走らせる設計にする
Email が空欄になるユーザー情報の保持状況や共有形態によるLoginName を主キーにして扱う。必要に応じて別台帳と突合する

まとめ

  • 標準レポートだけで「リンク共有された外部ユーザー一覧」をテナント全体から直接取り出すのは難しく、PowerShellで各サイトを走査して抽出→CSV化が現実的です。
  • 抽出は UserType=Guest と LoginNameのパターンを併用すると安定します。
  • 匿名リンクなど、仕組み上「ユーザーとして特定できない共有」もあるため、運用ルール(リンク種類の制限、期限、定期棚卸し)をセットで整備すると管理しやすくなります。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次