Copilot 導入前のオーバーシェアリング対策|「組織全体のサイトのアクセス許可」レポートの CSV で、直すサイトの順番を決める
Copilot は利用者が開けるものを読みに行きます。配る前に、SharePoint 管理センターの「組織全体のサイトのアクセス許可」レポートの CSV を取り、誰に開いているかと中身の機密度を掛け合わせて直す順番を決め、所有者に頼み、30日後に突き合わせるまでの進め方を、集計のスクリプトと依頼文の骨子つきで説明します。
目次 クリックで開く
社内の全員に開いたままの人事のフォルダーがひとつあれば、Copilot を配ったその日から、誰かの質問への答えにその中身が混ざりえます。誰でも開けるサイトを先に片づけたいのに、SharePoint のサイトは数百あり、どこから手を付ければよいのかが決まりません。
手を付ける順番を決めるのは、サイトの数ではなく、誰に開いているかと、中身がどれだけ重いかです。どちらも管理センターのレポートと手元の台帳から引けるので、導入の準備を任された情報システムや総務の担当でも、所有者に頼むところまで進められます。人数の多い順に並べると見落とすサイトがある理由も、あわせて書きます。
例に使う会社・サイト・数字は架空で、Microsoft 365 と生成 AI の導入を支援している当社が、レポートと同じ列で作りました。
Copilot は、使う人が開けるファイルから答えを作る
Copilot は、使っている人が少なくとも表示の権限を持つ組織のデータだけを回答に使います(Microsoft Copilot のデータ、プライバシー、セキュリティ)。裏返すと、権限の付け方が広すぎるサイトは、そのまま広い範囲の回答の材料になります。手を入れる先は Copilot の設定ではなく、SharePoint の権限です。しかも SharePoint の共有の設定は、既定では最も寛容な選択肢になっています(SharePoint 高度な管理で Copilot とエージェントの準備をする)。
この記事の手順で最後にできるのが、この一覧です。この例の420サイトのうち、Copilot を配る前に手を付けるのは、上の22サイトになりました。色の濃い「隠してから直す」は、所有者が直すまで Copilot から一時的に隠しておくサイト、その下の「中身を確かめる」は、所有者に中身と範囲を確かめてもらうサイトです。残りのうち64サイトは広く開いている理由を所有者に聞き、334サイトは定期点検に回します。
なお、ここで「Copilot」と書くのは Microsoft 365 Copilot のことです。ライセンスと価格のページはこの名前のままで、Learn では 2026 年からアプリの改称に合わせて Microsoft Copilot と書かれています(Learn の概要ページ)。
材料は「組織全体のサイトのアクセス許可」レポートの CSV。21列のうち8列で順番を決める
使うのは、SharePoint 管理センターの[レポート]>[データ アクセス ガバナンス]にあるスナップショット レポートのひとつ、「組織全体のサイトのアクセス許可」です。画面では「おすすめ」の印が付いています。日本語版の Learn の一覧では「organization全体のサイトのアクセス許可 (推奨)」、英語版では Site permissions across your organization と書かれています(データ アクセス ガバナンス レポート)。
このレポートは SharePoint 高度な管理(SharePoint Advanced Management)の機能です。組織で少なくとも1人のユーザーに Copilot ライセンスを割り当てると、SharePoint 管理者が Copilot の導入を支える SharePoint 高度な管理の機能を使えるようになり、ライセンスを受け取るユーザーは SharePoint 管理者でなくてもかまいません(Copilot ライセンスに含まれる機能・前提条件)。全社に配る前に、点検を担当する人1人にライセンスを割り当てて、点検から始める順番が組めます。
前提条件のページに並ぶ土台のライセンス(Office 365 E3・E5・A5、Microsoft 365 E1・E3・E5・A5、政府向けのクラウド)には Business 系の名前がありませんが、当社が試した Microsoft 365 Business Premium と Microsoft 365 Copilot Business(1ライセンス)の試用の組み合わせでは、SharePoint 管理センターの[高度な管理]に「サブスクリプションの状態: アクティブ」と出ていました。データ アクセス ガバナンスのレポートは[レポートの作成]を押すと生成中になり、サイトの[設定]タブにもこのあと使う項目が出ていました(見たのはそこまでで、設定は変えていません)。ほかの Business 系の組み合わせも、同じ画面で確かめられます。Microsoft 365 E5 だけの場合も、データ アクセス ガバナンスのレポートは開けますが、スナップショットのレポートと是正の操作は無く、アクティビティのレポートは最大1万サイトまでです。
作るとすぐ CSV が届くわけではありません。レポートは SharePoint と OneDrive で別々に作られ、初回は組織の大きさにかかわらず最大5日、2回目からは24時間以内にでき、データは作成の最大48時間前のものです。もう一度取れるのは30日ごとです。管理センターの画面に出るのはアクセスできる人の多い上位100サイトだけで、CSV なら最大100万サイトまで落とせます。なお、英語版の Learn には、アクセスできない状態にロックしたサイトとアーカイブしたサイトはこのレポートに入らない、という注があります。
試用環境で[レポートの作成]を押した直後に「レポートを生成しています」になったのは SharePoint のレポートだけで、OneDrive のレポートは、続けて画面の上の[レポートの実行]を押したときに始まりました。どちらも確認の画面は出ませんでした。30日に1回しか取れないので、押す前に、今取ってよいかを決めておきます。
作成で止まったときに見る所もあります。Learn の既知の問題に、レポートで名前を隠さない設定にしていると、データ アクセス ガバナンスのレポートが動かないことがある、と書かれています。この設定は Microsoft 365 管理センターの[設定]>[組織の設定]>[サービス]>[レポート]にあり、画面の表記は「すべてのレポートでユーザー、グループ、サイト名を隠蔽する」で、既定ではチェックが入っています(名前を隠す)。Copilot の利用状況のレポートで名前を出すためにこのチェックを外すと(利用状況のレポートの記事)、このレポートが動かないことがあります。止まったときは、グローバル管理者がこのチェックを入れ直して保存します(英語版の Learn の表記では、Display concealed user, group, and site names in all reports をオフにする、と書かれています)。
CSV の列は Learn に21列が載っています(列名は英語版の表記)。使い道が「順番」の8列で、直す順番を決めます。
| 列(Learn の表記) | 何が入っているか | 使い道 |
|---|---|---|
| Everyone permission count | 「Everyone」(ゲストを含む全員)に付けた権限の数 | 順番 |
| EEEU permission count | 「外部ユーザーを除くすべてのユーザー」(社内の全員)に付けた権限の数 | 順番 |
| Number of users having access | サイトのどこかにアクセスできる人の数。グループを展開し、重複を除いて数える | 順番 |
| Anyone link count | 「すべてのユーザー」リンク(Anyone)の数 | 順番 |
| People In Your Org link count | 「組織内のユーザー」リンク(People in your organization)の数 | 順番 |
| Site Sensitivity | サイトに付いた秘密度ラベル | 順番(中身の機密度) |
| File count | サイト内のファイルのおおよその数 | 順番(同じ対応の中の並び) |
| Site URL | サイトの URL | 順番(台帳の機密度を引く) |
| Primary admin / Primary admin email | アクティブなサイトでプライマリとした管理者と、そのメール | 依頼の宛先 |
| Site ID / Site Name | サイトの識別子と名前 | 30日後の突き合わせ |
| 残りの9列 | TenantID、テンプレート、外部共有の可否、公開か非公開か、ゲスト・外部参加者・グループへの権限の数、継承を切った項目の数、作成日時 | 依頼のときに所有者へ添える |
EEEU と Everyone の数は、隠れたシステムのグループを通した権限を数えません。1以上なら、誰かが社内の全員やゲストを含む全員に権限を付けた(公開のチームサイトにした場合を含む)と読めます。
誰に開いているか × 中身の機密度で、4つの対応に分ける
Learn は、是正の手を決めるときに考えることとして、さらされている中身の機密度、その量、利用者の仕事への影響を挙げています(データ アクセス ガバナンス レポートからの修復アクション)。CSV が教えてくれるのは「誰に開いているか」までなので、中身の重さはサイトの秘密度ラベルと、自分で作る台帳から決め、2つを掛け合わせます。
誰に開いているかは、この記事では次の6段を上から順に当てはめ、最初に当たった段に入れます。
| 範囲 | 当てはめる列 | どういう状態か |
|---|---|---|
| ゲストを含む全員 | Everyone permission count が1以上 | ゲストを含めた全員が開ける |
| 社内の全員 | EEEU permission count が1以上 | 社員なら誰でも開ける。公開(Public)のチームサイトにすると自動でこの状態になる |
| 大人数 | Number of users having access が400以上 | いま権限を持つ人が多い。区切りは自社で決める(この例では社員の半分ほど) |
| 社外の誰でも開けるリンク | Anyone link count が1以上 | リンクを持つ人なら社外の人も開ける |
| 組織内のリンク | People In Your Org link count が1以上 | リンクを持つ社員が開ける |
| メンバーだけ | 上のどれでもない | サイトのメンバーと、個別に共有された人だけ |
この順番は、Copilot からどう見えるかで決めました。社外の誰でも開けるリンクは、社外へ出るという意味では重いのですが、作っただけでは Copilot に出ないので、社内の全員より下に置いています。社外への共有は、この表とは別の点検で扱ってください。
機密度は3つに分けます。秘密度ラベルが自社の「極秘」「社外秘」にあたるか、台帳で「高い」としたサイトは「高い」、ラベルか台帳で普通と分かるものは「ふつう」、どちらにも手がかりの無いものは「分からない」です。台帳は Site URL・部署・機密度・広く開く理由・理由を書いたときの範囲・理由を書いたときの人数の6列の表です。最初は前の3列だけの表で始めてかまいません(後ろの3列が無ければ、スクリプトは空として扱います)。人事・給与・経理・法務・経営企画のように中身が重いと分かっている部署のサイトから書きます。この例では部署のサイトの70行だけを書いたので、台帳に無いプロジェクトのサイトが「分からない」に入り、294サイトといちばん多い列になりました。
これが判断の表です。18マスすべてに対応を1つずつ決め、この例の全サイトが1マスにだけ入ることを集計の中で確かめています。区切りや対応を自社で変えるときも、対応の決まっていないマスを残さないでください。4つの対応は、終わったら台帳に戻して閉じます。
所有者の答えは2通りあります。機密度を答えてもらったサイトは、台帳の機密度を書くと、次の回はそのマスの対応に移ります(社内の全員に開いた「分からない」サイトが「高い」と分かれば「隠してから直す」、「ふつう」なら「理由を聞く」)。この範囲が必要だと答えてもらったサイトは、理由と、そのときの範囲(6段のどれか)と人数を台帳に書くと、次の回から「定期点検へ」に回ります。ただし、社内の全員・ゲストを含む全員に開いた機密度の高いサイトには理由を効かせず、範囲を狭めるまで残します。また、理由を書いたときより範囲が広がっていたり(段が上がった、人数が1.2倍を超えた)すると、理由を効かせずに表の対応へ戻し、「知らせ」の列に書きます。答えをもらったときと条件が変わったサイトは、もう一度聞くためです。同じ段の中でリンクが増えただけのときは戻さないので、そこは四半期ごとの点検で見ます。1.2倍は、400人の区切りと同じく、この記事で決めた値です。スクリプトの -Grow と -Large で自社の値に変えられます。台帳の人数は「802」のように数字だけで書きます。
| 対応 | すること | 終わったら |
|---|---|---|
| 隠してから直す | 制限付きコンテンツ検出で Copilot と組織全体の検索から一時的に隠し、所有者に権限を直してもらう | 30日後のレポートで外れていれば、隠すのをやめる。機密度の高いサイトは、全員に開いたまま残す理由を認めず、範囲を狭めるまで残る |
| 中身を確かめる | サイト アクセス レビューで、所有者に中身と、その範囲に開いている理由を確かめてもらう | 答えを台帳に書く。機密度を書けば、次の回はそのマスの対応に移る。範囲が必要なら理由とそのときの範囲・人数を書き、次から「定期点検へ」に移る |
| 理由を聞く | 全社向けのお知らせのように、わざと広く開いているサイトの理由を聞く | 理由とそのときの範囲・人数を台帳に書く。次から「定期点検へ」に移る(範囲が広がれば戻る) |
| 定期点検へ | 今回は手を付けない | 毎月・四半期ごとの点検で動きを見る |
同じ対応の中は、範囲の広い順、そのなかでファイルの多い順に並べます。Learn が挙げる観点のうち「量」を、File count で代わりに見ています。
人数の多い順に並べると、社内の全員に開いたサイトが下に沈む
管理センターの画面は、アクセスできる人の多い順にサイトを並べます。公式の説明でも、このレポートは人数の多いサイトを優先して示し、是正を必要な所に集中させるためのものとされています。ところが人数の列は、共有リンクを作ったり、社内の全員に権限を付けたりしただけでは増えません。これは、利用者が実際に開いて初めて本当の露出になる「潜在的な露出」と呼ばれています(サイトのアクセス許可レポート)。
この例では、「隠してから直す」の8サイトは人数の順位で277位から393位、人数は12人から57人でした。100位の人数が180人なので、画面の一覧を上から見ていくと一度も行き当たりません。「中身を確かめる」まで広げた22サイトでも、上位100に入るのは4サイトです。社内の全員に権限が付いていても、人数にはメンバーなど個別に権限を持つ人しか表れないためです。人数は「いま権限を持つ人の数」として使い、社内の全員とリンクは別の列で見ます。
「組織内のユーザー」リンクと社内の全員への権限は、Copilot から見ると別物
「組織内のユーザー」リンクと、社内の全員(外部ユーザーを除くすべてのユーザー)への権限は、どちらも「社内なら誰でも」に聞こえます。けれど、Copilot に出るまでの道筋が違います。
「組織内のユーザー」リンクも「すべてのユーザー」リンク(Anyone)も、作っただけでは検索結果にも Copilot にも出ません。リンクを受け取った人が開いて初めて、その人から見つけられるようになります(共有可能なリンクのしくみ)。「組織内のユーザー」リンクは、SharePoint や OneDrive の画面、Outlook のメール、Teams のチャットから個人あてに送ると、受け取った人の分が最大100人まで自動で開いた扱いになります。グループあてや、Teams のチャネルへの投稿は対象外です。一方、社内の全員への権限が付いた項目は、社員全員に見え、Copilot の検索結果にもそのまま出ます(特別な SharePoint グループのレポート)。
判断の表で、組織内のリンクだけのサイトを社内の全員より後に並べたのはこのためです。リンクの数が多いサイトから手を付けると、Copilot から見て急ぐサイトが後に回りかねません。ただし、どちらのリンクも転送できる鍵のようなもので、組織内のリンクには管理者が有効期限の決まりを設定できます。リンクの使い方の社内ルールとテナントの共有の設定は、OneDrive・SharePoint のリンク共有の社内ルールにまとめています。
所有者に頼み、その間は制限付きコンテンツ検出で隠す
冒頭の一覧ができたら、上から所有者に頼みます。データ アクセス ガバナンスのレポートの画面から送れるサイト アクセス レビューが使えます(サイト アクセス レビューを開始する)。「組織全体のサイトのアクセス許可」レポートから送ったレビューでは、所有者はメールのリンクから、権限を持つ人の多いサイト・リスト・フォルダー・ファイルの順に並んだ一覧を開き、リンクの数と、社内の全員や Everyone が付いているか(はい/いいえ)を見て、[アクセスの管理]から外せます。送れるのは、画面からは一度に最大100サイト、このレポートからは暦の月ごとに1,000件までで、送る前に所有者あてのコメントを書き足せます。所有者は見直しが終わったら[レビューの完了]を選び、コメントを足して送ります。コメントは管理者に届き、それまでレビューは保留中のままです。対象は SharePoint のサイトだけです。
この例では、2つの対応のうち3サイトで所有者の列(Primary admin)が空でした。所有者のメールが無効だと、レビューは失敗します。空のサイトは、アクティブなサイトの画面で所有者を確かめてから頼みます。所有者のいないサイトを見つけて知らせる仕組みとしては、SharePoint 高度な管理にサイトの所有権ポリシーがあります。
コメントには、次の骨子を書いておくと、メールを開いた所有者が何を判断すればよいか迷いません。
【お願い】[日付]に Copilot の利用を広げる前に、このサイトの共有の範囲を確かめてください。
【このサイトを選んだ理由】このサイトは[社内の全員/ゲストを含む全員/社外の誰でも開けるリンク]に開いています。台帳では中身は[人事の評価記録など]です(台帳に無い場合:中身が分からないため、教えてください)。
【してほしいこと】メールのリンク先で、権限を持つ人の多い項目から順に、「外部ユーザーを除くすべてのユーザー」や Everyone が付いているもの、リンクの多いものを確かめ、全員に見せる必要が無ければ[アクセスの管理]から外してください。終わったら[レビューの完了]を選び、全員に見せる必要がある場合は、その理由を完了のときのコメントに書いてください。
【期限】[日付]まで。30日後にもう一度レポートを取り、範囲が変わったかを確かめます。
【その間のこと】(隠してから直すサイトだけ)確認が終わるまで、このサイトは Copilot と組織全体の検索に出ないようにしています。サイトの中身はこれまでどおり開けます。サイトの中から始めた検索にはこの設定は効かず、開いている文書を要約するような使い方も止まりません。
【問い合わせ先】[情報システムの担当・連絡先]
「隠してから直す」のサイトは、所有者が直すまでの間、制限付きコンテンツ検出で Copilot と組織全体の検索から隠しておきます(SharePoint サイトとコンテンツの検出を制限する)。SharePoint 管理センターの[サイト]>[アクティブなサイト]でサイトを選び、[設定]タブの「コンテンツ検出を制限する」(PRO の印付き。試用環境に作ったサイトではオフでした)をオンにします。2026年10月の Learn の日本語版はこの項目を「Microsoft Copilot からのコンテンツを制限する」(英語版は Restrict content from Microsoft Copilot)と書いていますが、試用環境の画面の表記は「コンテンツ検出を制限する」でした。権限は変わらないので、すでに開ける人はこれまでどおり開けます。サイトの中から始めた検索や、Microsoft 365 のフィード・おすすめには効きません。開いている文書の要約のように、使っている最中の内容を扱う場面にも効きません。使えるのは SharePoint のサイトだけで、条件は、組織に Copilot ライセンスがあり、SharePoint 高度な管理が使えることです。
この機能は一時的な統制として設計されていて、使いすぎると検索と Copilot の回答の完全さに響くので、選んで使うよう注意書きがあります。反映には時間がかかり、アイテムが50万を超えるサイトでは1週間を超えることもあります。だから隠すのは「隠してから直す」に絞り、隠した日から所有者への依頼を始めます。
制限付き SharePoint 検索は、組織全体の検索と Copilot に使うサイトを、許可リスト(最大100サイト)に絞る機能です。Learn では、この機能は廃止予定で、2026年7月31日から新しく有効にすることはできず、代わりに制限付きコンテンツ検出のような仕組みを使うよう書かれています(制限付き SharePoint 検索)。これから計画を立てるなら、前提にしないでください。サイトに入れる人そのものを絞りたいときは、指定したグループの人だけに限る制限付きアクセス制御があり、グループ外の人は、以前に権限やリンクで開けていても開けなくなります。
サイトではなくファイルの単位で、重いものを Copilot に使わせたくない場合は、Microsoft Purview のデータ損失防止で、秘密度ラベルの付いたファイルとメールを Copilot の回答に使わせない設定もあります(Purview のデータ損失防止と Copilot)。ラベルの考え方は、Outlook の機密ラベルの記事の前半にまとめています。
30日後のレポートで、直ったかを確かめる
直ったかどうかは、所有者の返事ではなくレポートで確かめます。1回目から30日後に2回目を取り、同じ決まりで対応を付け直して、Site ID で1回目と突き合わせます。レポートは作成の最大48時間前のデータなので、直した直後に取ると、まだ反映されていないことがあります。
この例では、22サイトのうち13サイトが、範囲が狭まって2つの対応から外れました(突き合わせの状態は「表の対応が下がって外れた」。台帳に機密度を書いて外れたサイトも同じ状態に入ります)。経営会議資料は、社内の全員への権限が3件から1件に減っただけで、まだ「隠してから直す」のままです。変わらなかった6サイトはどれも「中身を確かめる」でした。経理_請求書受付は範囲が狭まっていませんが、所有者の答え(取引先から請求書を受け取るリンク)を台帳に書いたので、「定期点検へ」に移りました。突き合わせでは「理由を書いて定期点検へ」として、直ったサイトと分けて出します。1回目には組織内のリンクだけだった品質_監査記録は、社内の全員への権限が0件から2件に増えて、新しく「隠してから直す」に入っています。1回目には無かった公開のチームサイトが1つ、「中身を確かめる」に入り、1回目にあったサイトが1つ、2回目のレポートから消えていました。
突き合わせたら、状態ごとに次のようにします。外れたサイトのうち、隠していたものは制限付きコンテンツ検出を外します。公式の手順も、権限を直したら一時的な保護を外すところまでを1つの流れにしています(Copilot のための安全で管理されたデータ基盤を構成する)。隠しているかどうかは、1回目の対応で見ます。1回目が「隠してから直す」のサイトは、2回目に「中身を確かめる」へ下がっていても隠したまま、範囲が狭まるまで所有者に2回目の依頼を出します。1回目から「中身を確かめる」のサイトは隠していないので、2回目の依頼で答えをもらい、台帳に書きます。新しく入ったサイトと新しくできたサイトには、1回目と同じ手順を当てます。レポートから消えたサイトは、アーカイブやロックでレポートから外れた可能性があるので、アクティブなサイトの画面で状態を確かめます。
30日に1回のスナップショットを待たずに、新しく社内の全員に開いたサイトを見つけるには、直近28日の共有を追うアクティビティ レポートを使います。「外部ユーザーを除くすべてのユーザー」と共有したサイトのレポートは、24時間ごとに取り直せます(EEEU アクティビティ レポート)。
Copilot を配った後の点検
Microsoft は、「組織全体のサイトのアクセス許可」のようなスナップショット レポートを四半期ごとに、共有リンクと「外部ユーザーを除くすべてのユーザー」のアクティビティ レポートを毎月取ることを勧めています。SharePoint 管理センターの[高度な管理]から始めるコンテンツ管理評価も、30日ごとにやり直して進み具合を追うよう書かれています。
四半期ごとの点検は、同じ台帳と同じスクリプトで回ります。この例の2回目では、全社向けのお知らせ・規程・ヘルプなどと経理_請求書受付のあわせて6サイトが、台帳に書いた理由で「定期点検へ」に移りました。所有者から答えをもらって台帳に書いたサイトは、範囲が広がらない限り、次の回は聞かずに済みます。Copilot を配る範囲は、2つの対応が片づいた部署から広げていくのが、この進め方に合います。Copilot が社内のデータを読みに行く仕組み(Work IQ)については、Copilot Cowork と Work IQ の記事にまとめています。
スクリプトの保存と実行
集計は、Windows に入っている PowerShell 5.1 で動かしました。自社のファイルで動かすときにつまずきそうな点は、わざとその状態のファイルを作って先に試しておいたので、3つに分けて書きます。
1つ目は保存のしかたです。スクリプトは「UTF-8(BOM 付き)」で保存します。PowerShell 5.1 は BOM の無いファイルを日本語の Windows では Shift_JIS として読むため、BOM なしで保存して試したところ、スクリプトの中の日本語が化けて止まりました。台帳は Excel の「CSV UTF-8(コンマ区切り)」で保存します。普通の「CSV(コンマ区切り)」で保存した台帳は列名が読めず、スクリプトがそこで止まります。レポートの CSV は、ダウンロードしたときの文字コードを確かめていません。Shift_JIS で保存し直した CSV で試すと、サイト名やラベルが化けて当たらなくなるので、化けた文字を見つけたら止まるようにしてあります。
2つ目は実行のしかたです。Windows のパソコンでは、PowerShell の実行ポリシーが既定の Restricted のままだと、コマンドは打てても、スクリプトは実行できません(実行ポリシーについての about_Execution_Policies)。端末の設定は変えずに、powershell.exe に -ExecutionPolicy を付けると、その回のセッションだけ実行ポリシーを決められ、設定は残りません。ただし、グループ ポリシーで実行ポリシーが決められている端末では、その設定のほうが優先されます。情報システムの決まりに従ってください。1回目と2回目で出力のファイル名を分け、次のように実行します(CSV のファイル名は、ダウンロードしたものに合わせて書き換えます)。
powershell -NoProfile -ExecutionPolicy Bypass -File .\prioritize.ps1 -Report .\SitePermissions_SharePoint_20260914.csv -Ledger .\site_ledger.csv -Out .\fix_order_1.csv
powershell -NoProfile -ExecutionPolicy Bypass -File .\prioritize.ps1 -Report .\SitePermissions_SharePoint_20261014.csv -Ledger .\site_ledger_2.csv -Out .\fix_order_2.csv
powershell -NoProfile -ExecutionPolicy Bypass -File .\compare.ps1 -First .\fix_order_1.csv -Second .\fix_order_2.csv -Out .\check_after.csv
3つ目は列名です。スクリプトは Learn 英語版の列名で書いてあり、ダウンロードした CSV の見出しが日本語で出るかは確かめていません。見出しが違うと、スクリプトは足りない列の名前を出して、何も書き出さずに止まります。そのときは、先頭の列名の表($col)の右側を CSV の見出しに書き換えます。Learn 日本語版の表の訳語で見出しを作った CSV で試し、書き換える前は止まり、書き換えた後は英語の見出しのときと同じ一覧になることを確かめました。台帳の Site URL は、末尾の「/」と大文字・小文字の違いをそろえてから突き合わせ、レポートに無い URL があれば件数と1件目を知らせます(止まりはしません)。知らせが出たら、台帳の URL をレポートから写し直して実行し直してください。理由を効かせずに聞き直すサイトがあれば、その件数も知らせ、一覧の「知らせ」の列に理由を書きます。2回目のレポートで、全社ポータルにゲストを含む全員の権限を、経理_請求書受付の人数を500に、社内報の人数を1,000に変えて試し、3サイトとも「定期点検へ」に入らずに表の対応へ戻ることを確かめました。出力の「優先」の列の1〜4が、4つの対応(隠してから直す・中身を確かめる・理由を聞く・定期点検へ)です。
# prioritize.ps1:「サイトのアクセス許可」レポートの CSV に、自分で作るサイトの台帳を突き合わせて、直す順番を付ける
# このファイルは UTF-8(BOM 付き)で保存する。台帳は Excel の「CSV UTF-8(コンマ区切り)」で保存する。
param(
[Parameter(Mandatory = $true)][string]$Report, # 管理センターからダウンロードした CSV
[Parameter(Mandatory = $true)][string]$Ledger, # 台帳(Site URL, 部署, 機密度, 広く開く理由, 理由を書いたときの範囲, 理由を書いたときの人数)
[Parameter(Mandatory = $true)][string]$Out, # 書き出す一覧(1回目と2回目で名前を変える)
[int]$Large = 400, # 「大人数」とみなす人数(自社で決める)
[double]$Grow = 1.2 # 理由を書いたときより人数がこの倍を超えたら、範囲が広がったとみなす(自社で決める)
)
$ErrorActionPreference = 'Stop'
# CSV の列名。見出しが日本語で出たときは、右側をダウンロードした CSV の見出しに書き換える
$col = [ordered]@{
Id = 'Site ID'; Name = 'Site Name'; Url = 'Site URL'; Admin = 'Primary admin'; Mail = 'Primary admin email'
Label = 'Site Sensitivity'; Users = 'Number of users having access'; Files = 'File count'
Org = 'People In Your Org link count'; Anyone = 'Anyone link count'
EEEU = 'EEEU permission count'; Everyone = 'Everyone permission count'
}
$highLabels = @('極秘', '社外秘') # 自社の秘密度ラベルの名前に合わせる
$normalLabels = @('社内限定', '公開')
# 判断の表:開いている範囲 × 中身の機密度 → 優先(1 が先)
$table = @{
'ゲストを含む全員' = @{ '高い' = 1; '分からない' = 1; 'ふつう' = 2 }
'社内の全員' = @{ '高い' = 1; '分からない' = 2; 'ふつう' = 3 }
'大人数' = @{ '高い' = 2; '分からない' = 3; 'ふつう' = 4 }
'社外の誰でも開けるリンク' = @{ '高い' = 2; '分からない' = 3; 'ふつう' = 4 }
'組織内のリンク' = @{ '高い' = 3; '分からない' = 4; 'ふつう' = 4 }
'メンバーだけ' = @{ '高い' = 4; '分からない' = 4; 'ふつう' = 4 }
}
$scopes = @('ゲストを含む全員', '社内の全員', '大人数', '社外の誰でも開けるリンク', '組織内のリンク', 'メンバーだけ')
$actions = @{ 1 = '隠してから直す'; 2 = '中身を確かめる'; 3 = '理由を聞く'; 4 = '定期点検へ' }
# 読み込みと列の検査(列が足りなければ、何も書き出さずに止める)
$sites = @(Import-Csv $Report -Encoding UTF8)
$ledgerRows = @(Import-Csv $Ledger -Encoding UTF8)
$missing = @($col.Values | Where-Object { $sites[0].PSObject.Properties.Name -notcontains $_ })
if ($missing) { throw "レポートの CSV に次の列がありません:$($missing -join ', ')。先頭の列名の表を CSV の見出しに合わせてください。" }
# 台帳:Site URL と機密度は必須。理由まわりの3列(広く開く理由・理由を書いたときの範囲・理由を書いたときの人数)は無ければ空として扱う
$heads = @($ledgerRows[0].PSObject.Properties.Name)
if (($heads -join '') -match [char]0xFFFD) { throw '台帳の見出しが化けています。台帳は Excel の「CSV UTF-8(コンマ区切り)」で保存し直してください。' }
$missing = @('Site URL', '機密度' | Where-Object { $heads -notcontains $_ })
if ($missing) { throw "台帳に次の列がありません:$($missing -join ', ')。見出しの名前を確かめてください。" }
foreach ($c in '広く開く理由', '理由を書いたときの範囲', '理由を書いたときの人数') {
if ($heads -notcontains $c) { $ledgerRows | ForEach-Object { $_ | Add-Member -NotePropertyName $c -NotePropertyValue '' } }
}
$bad = @($ledgerRows | Where-Object { $_.'理由を書いたときの人数' -notmatch '^\d*$' })
if ($bad) { throw "台帳の「理由を書いたときの人数」は数字だけで書いてください(人 などを付けない):$($bad[0].'Site URL')" }
$bad = @($ledgerRows | Where-Object { $_.'機密度' -notin @('高い', 'ふつう') })
if ($bad) { throw "台帳の機密度が「高い」「ふつう」以外の行があります:$($bad[0].'Site URL')" }
# 文字化けの検査:UTF-8 として読めない文字(U+FFFD)があれば止める。CSV を UTF-8 で保存し直す
$bad = @($sites | Where-Object { ($_.($col.Name) + $_.($col.Label)) -match [char]0xFFFD })
if ($bad) { throw "レポートの CSV のサイト名かラベルが化けています($($bad.Count)行)。CSV を UTF-8 で保存し直してください。" }
# URL の表記ゆれ(末尾の / や大文字・小文字)をそろえてから突き合わせる
function Key($u) { "$u".Trim().TrimEnd('/').ToLowerInvariant() }
$weight = @{}; $reason = @{}; $was = @{}
foreach ($r in $ledgerRows) {
$k = Key $r.'Site URL'; $weight[$k] = $r.'機密度'; $reason[$k] = $r.'広く開く理由'; $was[$k] = $r
}
$known = @{}; foreach ($s in $sites) { $known[(Key $s.($col.Url))] = $true }
$stray = @($weight.Keys | Where-Object { -not $known[$_] })
if ($stray) { "台帳にあってレポートに無い URL:$($stray.Count)件(例:$($stray[0]))" }
$rows = foreach ($s in $sites) {
$n = @{}; foreach ($k in 'Users', 'Files', 'Org', 'Anyone', 'EEEU', 'Everyone') { $n[$k] = [int]$s.($col[$k]) }
$scope = if ($n.Everyone -gt 0) { $scopes[0] }
elseif ($n.EEEU -gt 0) { $scopes[1] }
elseif ($n.Users -ge $Large) { $scopes[2] }
elseif ($n.Anyone -gt 0) { $scopes[3] }
elseif ($n.Org -gt 0) { $scopes[4] }
else { $scopes[5] }
$url = $s.($col.Url); $label = $s.($col.Label); $w = $weight[(Key $url)]; $why = $reason[(Key $url)]
$level = if ($highLabels -contains $label -or $w -eq '高い') { '高い' }
elseif ($normalLabels -contains $label -or $w -eq 'ふつう') { 'ふつう' }
else { '分からない' }
$no = $table[$scope][$level]
$tableNo = $no; $note = ''
# 所有者が範囲を必要と答え、台帳に理由を書いたサイトは定期点検へ。ただし全員に開いた機密度の高いサイトは、狭めるまで残す。
# 理由を書いたときより範囲が広がっていたら(段が上がった、人数が増えた)、理由を効かせず表の対応に戻して知らせる
if ($why -and $no -le 3 -and -not ($level -eq '高い' -and $scope -in $scopes[0..1])) {
$w0 = $was[(Key $url)]; $i0 = [array]::IndexOf($scopes, $w0.'理由を書いたときの範囲')
if ($i0 -lt 0) { $note = '理由を書いたときの範囲が台帳に無い' }
elseif ([array]::IndexOf($scopes, $scope) -lt $i0) { $note = "範囲が広がった($($w0.'理由を書いたときの範囲')→$scope)" }
elseif ($n.Users -gt [int]$w0.'理由を書いたときの人数' * $Grow) { $note = "人数が増えた($($w0.'理由を書いたときの人数')→$($n.Users)人)" }
else { $no = 4 }
}
[pscustomobject]@{
'優先' = $no; '対応' = $actions[$no]; '開いている範囲' = $scope; '機密度' = $level; '広く開く理由' = $why; '表の優先' = $tableNo; '知らせ' = $note
'Site ID' = $s.($col.Id); 'Site Name' = $s.($col.Name); 'Site URL' = $url
'Primary admin' = $s.($col.Admin); 'Primary admin email' = $s.($col.Mail)
'Everyone' = $n.Everyone; 'EEEU' = $n.EEEU; 'Users' = $n.Users; 'Anyone links' = $n.Anyone; 'Org links' = $n.Org; 'Files' = $n.Files
'範囲の順' = [array]::IndexOf($scopes, $scope)
}
}
# 同じ優先の中は、開いている範囲の広い順、ファイルの多い順(さらされている量の多い順)
$rows | Sort-Object '優先', '範囲の順', @{ Expression = 'Files'; Descending = $true }, 'Site ID' |
Select-Object -Property * -ExcludeProperty '範囲の順' |
Export-Csv $Out -NoTypeInformation -Encoding UTF8
$rows | Group-Object '優先' | Sort-Object Name | ForEach-Object { '{0}:{1}サイト' -f $actions[[int]$_.Name], $_.Count }
$notes = @($rows | Where-Object { $_.'知らせ' })
if ($notes) { "理由を効かせず聞き直すサイト:$($notes.Count)件(例:$($notes[0].'Site Name') $($notes[0].'知らせ'))" }
30日後の突き合わせは、2つの一覧を次のスクリプトに渡します。1回目に無かったサイトと、2回目のレポートから消えたサイトも、2つの対応に入るものは状態を分けて書き出します。prioritize.ps1 で作った一覧でないもの(優先の列が無いもの)を渡すと止まります。
# compare.ps1:1回目と30日後の一覧(どちらも prioritize.ps1 で作ったもの)を Site ID で突き合わせ、
# 「隠してから直す」「中身を確かめる」(優先1・2)に入ったサイトがどうなったかを見る
# このファイルも UTF-8(BOM 付き)で保存する。
param(
[Parameter(Mandatory = $true)][string]$First, # 1回目の一覧
[Parameter(Mandatory = $true)][string]$Second, # 30日後の一覧
[Parameter(Mandatory = $true)][string]$Out
)
$ErrorActionPreference = 'Stop'
$f = @{}; Import-Csv $First -Encoding UTF8 | ForEach-Object { $f[$_.'Site ID'] = $_ }
$s = @{}; Import-Csv $Second -Encoding UTF8 | ForEach-Object { $s[$_.'Site ID'] = $_ }
foreach ($t in @($f.Values)[0], @($s.Values)[0]) {
if (-not $t -or $t.PSObject.Properties.Name -notcontains '優先') { throw '優先の列がありません。prioritize.ps1 で作った一覧を渡してください。' }
}
function Width($r) { [int]$r.'Everyone' + [int]$r.'EEEU' + [int]$r.'Anyone links' }
$ids = @($f.Keys) + @($s.Keys) | Sort-Object -Unique
$rows = foreach ($id in $ids) {
$x = $f[$id]; $y = $s[$id]
$n1 = if ($x) { [int]$x.'優先' } else { 9 }
$n2 = if ($y) { [int]$y.'優先' } else { 9 }
if ($n1 -gt 2 -and $n2 -gt 2) { continue }
$state = if (-not $y) { 'レポートから消えた' } # 削除・アーカイブ・ロックしたサイトはレポートに出ない。アクティブ サイトで確かめる
elseif (-not $x) { '新しくできたサイト' }
elseif ($n1 -le 2 -and $n2 -gt 2 -and [int]$y.'表の優先' -le 2) { '理由を書いて定期点検へ' } # 範囲は狭まっていない
elseif ($n1 -le 2 -and $n2 -gt 2) { '表の対応が下がって外れた' } # 範囲が狭まったか、台帳に機密度を書いた
elseif ($n1 -gt 2) { '新しく入った' }
elseif ((Width $y) -lt (Width $x) -or [int]$y.'Users' -lt [int]$x.'Users') { '一部だけ減った' }
else { '変わらない' }
$r = if ($y) { $y } else { $x }
[pscustomobject]@{
'状態' = $state; '1回目の対応' = $(if ($x) { $x.'対応' }); '2回目の対応' = $(if ($y) { $y.'対応' })
'Site Name' = $r.'Site Name'; 'Site URL' = $r.'Site URL'; 'Primary admin' = $r.'Primary admin'
'1回目の範囲' = $(if ($x) { $x.'開いている範囲' }); '2回目の範囲' = $(if ($y) { $y.'開いている範囲' })
}
}
$rows | Sort-Object '状態', 'Site Name' | Export-Csv $Out -NoTypeInformation -Encoding UTF8
$rows | Group-Object '状態' | ForEach-Object { '{0}:{1}サイト' -f $_.Name, $_.Count }
制限付きコンテンツ検出は、管理センターのほか、SharePoint Online の PowerShell で Set-SPOSite -Identity <サイトの URL> -RestrictContentOrgWideSearch $true と設定でき、どのサイトで有効になっているかの一覧は Start-SPORestrictedContentDiscoverabilityReport で作れると案内されています。
この記事の数字は説明のための例で、自社の CSV では件数も並びも変わります。管理画面は、当社の試用環境で2026年10月に見た範囲(レポートの作成を押すところまで)に合わせ、見ていない画面の名前は 2026年10月24日に確認した Learn の表記にしました。完成したレポートと CSV、Copilot の画面は、この記事を書いた時点ではまだ見ていません。また、この点検はサイトの単位です。どのファイルやフォルダーが社内の全員や Everyone に開いているかを1件ずつ知りたいときは、「特別な SharePoint グループを通じて共有されているサイトとファイル」のレポート(画面の表記。Learn の日本語版は「…を介して共有されたサイトとファイル」)を使います。SharePoint と OneDrive の両方が入り、グローバル管理者が SharePoint 高度な管理の管理者ロールを割り当てる必要があります(Learn のページ)。OneDrive のサイト単位の点検は、「組織全体のサイトのアクセス許可」レポートの OneDrive 版で見ます。
最初の一歩は、レポートの作成と台帳の3列
冒頭の人事のフォルダーを抱えたサイトを、Copilot を配る前に探し当てる最初の手は、「組織全体のサイトのアクセス許可」レポートの作成です。届くまでの数日は、人事・給与・経理・法務のように中身の重い部署のサイトから、台帳の最初の3列(Site URL・部署・機密度)を書き始める時間に充ててください。届いた CSV と台帳を prioritize.ps1 に渡したところから、この記事の手順が始まります。
自社の CSV で同じ一覧を作りたいときは、当社の Microsoft 365 導入支援のページからご相談ください。
AI活用支援
Claude・ChatGPT・Gemini・Copilotのどれをどの業務に使うかの見極めから、社内のAIチャット環境、権限と情報の扱いの設計、MCPやAPIでの既存システム連携、研修・伴走までを支援します。
