SharePoint Online からサイト・リストの権限の一覧を取得するサンプル

こんにちは SharePoint サポートの森 健吾 (kenmori) です。

今回の投稿では、SharePoint Online のサイトから、配下の権限オブジェクトを取得するサンプルを記載します。
権限一覧の取得は、様々な移行シナリオなどで必要になることが多いため、最もサンプルが要望されるものの一つです。

今回は SharePoint Online 用に CSOM で権限一覧を取得しました。ただし、フォルダーやアイテム単位での権限などを考慮すると、処理時間やリスト ビューのしきい値など様々な問題を考慮する必要があるので、今回のサンプルではリストまでを取得する形となっております。必要に応じて、ここから拡張するなど、開発工数削減のため活用ください。

権限一覧取得プログラムは C# と PowerShell で記載しております。ただし、PowerShell では、下記公開資料に記載されているような抑制されたプロパティの取得 (例. HasUniqueRoleAssignments プロパティ) のロードが困難です。そのため、下記サンプルの動作上の差異として、PowerShell では固有の権限が割り当てられているか否かにかかわらず、すべてのリストの権限を無条件で取得するようにさせていただだきました。
このように、CSOM 開発では、稀に言語要件を決定する際に PowerShell が選択しにくい場合がありますので、ご注意ください。

タイトル : クライアント オブジェクトの取得によって全プロパティが取得されるわけではない
アドレス : https://msdn.microsoft.com/ja-jp/library/office/ee534974(v=office.14).aspx

ここから先のサンプルを使用するにあたり、必ず SharePoint Online Client Components SDK をインストールしてください。

タイトル : SharePoint Online Client Components SDK
アドレス : https://www.microsoft.com/en-us/download/details.aspx?id=42038 

 

C#
Visual Studio でソリューションを作成し、Microsoft.SharePoint.Client.dll と Microsoft.SharePoint.Client.Runtime.dll への参照を追加して、下記のコードを実装ください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SP = Microsoft.SharePoint.Client;

namespace GetSPWebListRoleAssignments
{
    class Program
    {
        static string fileName = "";
        static private void WriteToFile(string text, bool Append)
        {
          // 出力テキストファイルを Excel で読み込む場合は Shift-JIS
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fileName, Append, Encoding.GetEncoding("Shift_JIS")))
            {
                sw.WriteLine(text);
            }
        }

        static private void WriteObjectRoles(SP.ClientContext ctx, SP.SecurableObject obj, string url)
        {
            ctx.Load(obj.RoleAssignments);
            ctx.ExecuteQuery();
            foreach (SP.RoleAssignment ra in obj.RoleAssignments)
            {
                StringBuilder sb = new StringBuilder();
                ctx.Load(ra.Member);
                ctx.Load(ra.RoleDefinitionBindings);
                ctx.ExecuteQuery();
                sb.Append(url);
                sb.Append("\t");
                sb.Append(ra.Member.Title);
                sb.Append("\t");

                int cnt = 0;
                foreach (SP.RoleDefinition rd in ra.RoleDefinitionBindings)
                {
                    if (cnt != 0)
                    {
                        sb.Append(",");
                    }
                    cnt++;
                    sb.Append(rd.Name);
                }
                WriteToFile(sb.ToString(), true);
            }
        }

        static private void GetWebObjectRoles(SP.ClientContext ctx, SP.Web web)
        {
            if (web.HasUniqueRoleAssignments)
            {
                WriteObjectRoles(ctx, web, web.Url);
            }
            ctx.Load(web.Lists);
            ctx.ExecuteQuery();
            foreach (SP.List list in web.Lists)
            {
                ctx.Load(list, l => l.HasUniqueRoleAssignments, l => l.Hidden);
                ctx.Load(list.RootFolder, f => f.ServerRelativeUrl);
                ctx.ExecuteQuery();
                if (list.HasUniqueRoleAssignments && !list.Hidden)
                {
                    string url = web.Url + list.RootFolder.ServerRelativeUrl;
                    if (web.Url.EndsWith(web.ServerRelativeUrl))
                    {
                        url = web.Url.Replace(web.ServerRelativeUrl, "") + list.RootFolder.ServerRelativeUrl;
                    }
                    WriteObjectRoles(ctx, list, url);
                }
            }
            ctx.Load(web.Webs);
            ctx.ExecuteQuery();
            foreach (SP.Web subweb in web.Webs)
            {
                ctx.Load(subweb, w => w.HasUniqueRoleAssignments, w => w.Url, w => w.ServerRelativeUrl);
                ctx.ExecuteQuery();
                GetWebObjectRoles(ctx, subweb);
            }
        }

        static private void GetAllWebObjects(string weburl, string username, string password)
        {
            SP.ClientContext ctx = new SP.ClientContext(weburl);
            System.Security.SecureString pwd = new System.Security.SecureString();
            foreach (Char cpwd in password.ToArray())
            {
                pwd.AppendChar(cpwd);
            }

            ctx.Credentials = new SP.SharePointOnlineCredentials(username, pwd);
            SP.Web RootWeb = ctx.Web;
            ctx.Load(RootWeb, w => w.HasUniqueRoleAssignments, w => w.Url, w => w.ServerRelativeUrl);
            ctx.ExecuteQuery();
            WriteToFile("URL\tUser/Group\tRoles", false);
            GetWebObjectRoles(ctx, RootWeb);
        }

        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("Try the following to execute this application.");
                Console.WriteLine("example)");
                Console.WriteLine(" GetSPWebListRoleAssignments.exe \"https://tenant.sharepoint.com\" \"C:\\out.txt\" \"user@tenant.onmicrosoft.com\" \"password\"");
                Console.WriteLine();
                Console.WriteLine("Press [Enter] to continue...");
                Console.ReadLine();
                return;
            }

            fileName = args[1];
            string siteUrl = args[0];
            string userName = args[2];
            string password = args[3];
            GetAllWebObjects(siteUrl, userName, password);
        }
    }
}

 

PowerShell
次に PowerShell を記載いたします。下記のコードをテキストエディタに貼り付け、拡張子を ps1 として保存してください。

param (
  $siteUrl,
  $outfilename,
  $username,
  $password
)

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") > $null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") > $null

function WriteToFile($text, $append)
{
  $sw = New-Object System.IO.StreamWriter($outfilename, $append, [System.Text.Encoding]::GetEncoding("Shift_JIS"))
  try
  {
    $sw.WriteLine($text)
  }
  finally
  {
    $sw.Dispose()
  }
}

 

function GetObjectRoles($obj, $url)
{
  $context.Load($obj.RoleAssignments)
  $context.ExecuteQuery()
  foreach ($ra in $obj.RoleAssignments)
  {
    $sb = new-object System.Text.StringBuilder
    $cnt = $sb.Append($url)
    $cnt = $sb.Append("`t")
    $context.Load($ra.Member)
    $context.ExecuteQuery()
    $cnt = $sb.Append($ra.Member.Title)
    $cnt = $sb.Append("`t")
    $context.Load($ra.RoleDefinitionBindings)
    $context.ExecuteQuery()
    foreach ($rd in $ra.RoleDefinitionBindings)
    {
      $cnt = $sb.Append($rd.Name)
      $cnt = $sb.Append(",")
    }
    WriteToFile -text $sb.ToString() -append $true
  }
}

 

function GetWebObjectRoles($inweb, $url)
{
  GetObjectRoles -obj $inweb -url $url
  $lists = $inweb.Lists
  $context.Load($lists)
  $context.ExecuteQuery()
  foreach ($list in $lists)
  {
      $context.Load($list)
      $context.Load($list.RootFolder)
      $context.ExecuteQuery()
      if ($list.Hidden -ne $true)
      {
        $url = $inweb.Url + $list.RootFolder.ServerRelativeUrl
        if ($inweb.Url.EndsWith($inweb.ServerRelativeUrl))
        {
          $url = $inweb.Url.Replace($inweb.ServerRelativeUrl, "") + $list.RootFolder.ServerRelativeUrl
        }
        GetObjectRoles -obj $list -url $url
      }
  }

  $webs = $inweb.Webs
  $context.Load($webs)
  $context.ExecuteQuery()
  foreach ($aweb in $webs)
  {
      $context.Load($aweb)
      $context.ExecuteQuery()
      if ($aweb.Hidden -ne $true)
      {
        GetWebObjectRoles -obj $aweb -url $aweb.Url
      }
  }
}

 

function GetAllWebObjects()
{
  $context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
  $pwd = convertto-securestring $password -AsPlainText -Force
  $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $pwd)
  $context.Credentials = $credentials
  $rootweb = $context.Web
  $context.Load($rootweb)
  $context.ExecuteQuery()
  WriteToFile -text "URL`tUser/Group`tRoles" -append $false
  GetWebObjectRoles -inweb $rootweb -url $rootweb.Url
}

GetAllWebObjects

 

PowerShell にて、下記の様にコードを実行します。

.\GetSPWebListRoleAssignments.ps1 –siteUrl https://tenant.sharepoint.com/sites/site1 -username user@tenant.onmicrosoft.com –outfilename "C:\Out\Roles.txt" –password password

 

下記のサイトもご参考にしていただけますと幸いです。

タイトル : SharePoint Online に対して PowerShell を使用する方法
アドレス : https://blogs.technet.com/b/sharepoint_support/archive/2014/10/20/sharepoint-online-powershell.aspx
参考箇所 : 方法 2. SharePoint Online Client Component SDK

なお、本サンプルでは ExecuteQuery の実行回数が多いため、本番環境で利用する場合、調整やブロックを回避するためのコードを実装することをお勧めします。

タイトル : SharePoint Online で調整またはブロックを回避する
アドレス : /ja-jp/sharepoint/dev/general-development/how-to-avoid-getting-throttled-or-blocked-in-sharepoint-online

今回の投稿は以上になります。