Microsoft365のメール数やファイルサイズをPowerShellで取得する
Microsoft365からGoogle Workspaceに移行するといっても、Exchange OnlineやSharepointのそれぞれのオブジェクト数を割り出さないと移行スケジュールが建てられません。
そこで、この「オブジェクト数」を調査する為に、PowerShellの追加モジュールである「Graph Powershell SDK」を使って、Exchange OnlineやSharepointのオブジェクト数を割り出してみようと思います。
目次
今回利用するツール等
PowerShellは現在のWindowsには標準でインストール済みではあるのですが、実はバージョンが低いものが入っており、起動する度に最新版を入れろとメッセージが出てくるので、まずはPowerShellの最新版からのインストールより説明します。
また、Graphと名前がついていますが、Graph APIでは全領域をカバーできておらず、PowerShellはAzureの細部にまで手が伸ばせるため、こういった作業の時には必須のツールとなっています。
このオブジェクト取得によってGoogle Workspaceへ移行したい場合にはどれくらいの日数で移行できるのか?といった算出の為の元データとなるため、事前準備の段階から取得しておき、GWM実施直前でも取得してどれくらい増量したのか?といった調査に使えます。
※ちなみにmacOSでもインストールすることが可能です。
図:macOSでも動かしてみた
調査の為の事前準備
PowerShell最新版のインストール
Windowsの場合
まずはインストール済みのPowershellではなく最新版のPowerShellをインストールします。
- こちらのサイトを開く
- MSIパッケージとなるので、ここからx64版もしくはarm64版、環境に合わせてダウンロードする
- ダウンロードしたインストーラを起動する
- 色々オプションが出てきますが基本デフォルトのまま次へ進んでインストールを完了する
- スタートメニューをクリックし、検索でPowerShellと入れるとPowershell7というのが出てきます。古いバージョンも共存してるので注意。
- これをタスクバーにピン留めすると良いでしょう。
図:インストーラを起動する
図:PowerSehll7が本体です
macOSの場合
macOSの場合もGithubにpkgファイルがリリースされているので同様にインストールは可能です。但し、macOSの場合はターミナル上で動くコマンドであるため、独立したアプリという形ではありません。
また、Homebrew経由でインストールも可能です。その場合、以下のコマンドでインストールが可能です。
1 |
brew install powershell/tap/powershell |
インストールができたらターミナル上で「pwsh」コマンドを打てばPowerShellになります。あとはps1ファイルをそのまま実行したり、PowerShellコマンドをそのまま実行することが可能です。
図:ターミナルがPowerShellになる
Graph PowerShell SDKのインストール
続けて、PowerShell7を管理者権限で起動して以下のコマンドを実行します。
1 2 |
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser Install-Module Microsoft.Graph -Scope CurrentUser -Repository PSGallery -Force |
動き始めるまでちょっと時間が掛かるので辛抱して待ちます。すると色々とインストールが始まります。インストール後は、以下のコマンドでインストール済みかどうか確認出来ます。
1 |
Get-InstalledModule Microsoft.Graph |
図:モジュールのインストール
アカウント接続
次の作業として同じくPowerShell7にて、Microsoft365と接続します。以下のコマンドを実行します。
1 |
Connect-MgGraph |
するとブラウザが起動して、ログインを促してくるので特権管理者アカウントでログインします。「Authentication complete. You can return to the application. Feel free to close this browser tab.」と出たらブラウザは閉じてオッケー。
PowerShell側は「Welcome to Microsoft Graph!」と出たら接続完了。実際にはここにMicrosoft365の各種スコープを付けて許可をしてあげる必要があるので、後述のPowerShellコマンドではそれらを付与して実行しています。
図:実行時の初回認証
PowerShellで調査する
VSCodeで開発する
今回のPowerShellスクリプトの開発は、MicrosoftのVisual Studio Code上で行っています。もはや開発者であれば知らない人はいないであろう、テキストエディタであり実行環境です。
そこに拡張機能としてこれもMicrosoft謹製のPowerShell for Visual Studio Codeをインストールして作成をすると良いでしょう。
図:拡張機能をインストールする
図:ps1ファイルを編集中の様子
Exchange Online
単一のアカウントの情報を取得する
単純に特定の単一アカウントにおけるOutlook上のフォルダ別のメールの数およびサイズを計測するコードを作成してみます。特定のフォルダのIDを取得しそのサブフォルダ内まで含めて探索して、カウントします。
以下はアーカイブフォルダおよびそのサブフォルダ内を探索します。これは以下のメソッドを利用しています。
- Get-MgUserMailFolder : 対象ユーザのメールフォルダを取得する
- Get-MgUserMessageCount : 対象ユーザのメッセージの件数を取得する
- Get-MgUserMailFolderChildFolder : 対象ユーザの対象フォルダのサブフォルダを取得する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
$global:foldersize = 0 # スコープ指定して接続 Connect-MgGraph -Scopes Mail.ReadBasic #接続用のアカウント $userId = "ここに探索する対象のメアドを入れる" #フォルダ別にアイテム数とサイズを表示する関数 function Get-MessageCountRecursively { param( [string]$userId, [string]$folderId ) # 現在のフォルダ内のメッセージ数を取得 $count = Get-MgUserMessageCount -UserId $userId -Filter "parentFolderId eq '$folderId'" # 現在のフォルダのサイズを取得 $targetbox = Get-MgUserMailFolder -UserId $userId -MailFolderId $folderId $global:foldersize = $global:foldersize + $targetbox.AdditionalProperties.sizeInBytes #サブフォルダを取得する $subfolders = Get-MgUserMailFolderChildFolder -UserId $userid -MailFolderId $folderId #サブフォルダを再帰処理 foreach ($subfolder in $subfolders) { # サブフォルダ内のメッセージ数を再帰的に取得 $count += Get-MessageCountRecursively -UserId $userId -FolderId $subfolder.Id $singlecnt = Get-MessageCountRecursively -UserId $userId -FolderId $subfolder.Id #サブフォルダ内のサイズを取得 $targetbox = Get-MgUserMailFolder -UserId $userId -MailFolderId $subfolder.Id $global:foldersize = $global:foldersize + $targetbox.AdditionalProperties.sizeInBytes } return $count } #アーカイブフォルダのIDを取得 $rootFolderId = (Get-MgUserMailFolder -UserId $userid -Filter "displayName eq 'アーカイブ'").Id #アーカイブおよびそのサブフォルダ内のメールの数を取得 $totalMessageCount = Get-MessageCountRecursively -UserId $userId -FolderId $rootFolderId Write-Host "アーカイブメール件数: $totalMessageCount" Write-Host "アーカイブメールサイズ: $($global:foldersize) バイト" |
もし、対象ユーザの全フォルダの全件数とサイズの合計を出したい場合には、$rootFolderIdの指定方法を以下のように変更しフォルダを大元のルートフォルダに指定します。受信トレイの親フォルダのIDつまり大元のルートフォルダを指定し、そこを基準に処理をします。
1 2 3 |
$rootFolderId = (Get-MgUserMailFolder -UserId $userid -Filter "displayName eq '受信トレイ'").parentFolderId $totalMessageCount = Get-MessageCountRecursively -UserId $userId -FolderId $rootFolderId Write-Host "全メールサイズ: $global:foldersize" |
但しこれでは調査するだけでなおかつ単一ユーザの情報を知ることが出来るだけなので、実際には全ユーザの情報をまとめてCSV出力するなどしなければ実際の現場では活用しにくいです。
rootFolderIdでは-Filterというオプションを付けてdisplayNameが受信トレイとeq(イコール)のものという条件をつけていますが、ここを日付を指定し「特定の日以前 or 以降の受信日のメール」みたいな指定方法が可能です。Redditでこのあたりが詳しく紹介されています。
1 2 3 4 5 |
$DaysRange = (Get-Date).AddDays(-1) $time = Get-Date ($DaysRange).ToUniversalTime() -UFormat '+%Y-%m-%dT%H:%M:%S.000Z' Get-MgUserMailFolderMessage -All -UserId $user -MailFolderId $myfolder -filter "ReceivedDateTime ge $time" |
上記の例では、ReceivedDateTime ge $timeとあり、受信日が$timeの日付より以降(ge)が指定されています。こうすることで指定期間内のメールの件数やサイズに限定することが可能です。geではなくleとすれば以下となるので日付的には指定日より前という表現になります。フィルタについてはこちらに公式ドキュメントがあります。
※但し、この手法は所謂オンライン・アーカイブと呼ばれる受信トレイ内とは別にあるアーカイブフォルダ内のデータは取得できません。
図:メールの件数とサイズを算出できました
まとめて取得しCSVでエクスポートする
mailという名前の列にメアドを縦に列挙しただけのinbox.csvというCSVファイルを用意します。ここに全ユーザを列挙しておきます。今回のコードは共有メールボックスについてはエラーとなり動作しません。
基本的なコードは前述と同じですが、reportというカスタムオブジェクトを用意し、値をどんどん格納していきます。メールアカウントは今回はもう簡単に「Get-MgUserMessageCount -UserId $userId」でざっくり取得します。ファイルサイズだけ関数を使ってサブフォルダ以下まで探索して取得します。
最終的にresult.csvとして出力して完了というコードになります。ちなみに、$PSScriptRootはps1スクリプトの実行されているカレントディレクトリのパスを取得するもので、inbox.csvはこのスクリプトと同じ場所に保存する必要があり、またresult.csvも同じ場所に出力されることになります。
※但し、この手法は所謂オンライン・アーカイブと呼ばれる受信トレイ内とは別にあるアーカイブフォルダ内のデータは取得できません。
図:出力された結果のCSV
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
$global:foldersize = 0 $report = @() #ユーザリストのCSV $Users = Import-CSV "$PSScriptRoot\inbox.csv" # スコープ指定して接続 Connect-MgGraph -Scopes Mail.ReadBasic #フォルダ別にアイテム数とサイズを表示する関数 function Get-MessageCountRecursively { param( [string]$userId, [string]$folderId ) # 現在のフォルダのサイズを取得 $targetbox = Get-MgUserMailFolder -UserId $userId -MailFolderId $folderId $global:foldersize = $global:foldersize + $targetbox.AdditionalProperties.sizeInBytes #サブフォルダを取得する $subfolders = Get-MgUserMailFolderChildFolder -UserId $userid -MailFolderId $folderId #サブフォルダを再帰処理 foreach ($subfolder in $subfolders) { #サブフォルダ内のサイズを取得 $targetbox = Get-MgUserMailFolder -UserId $userId -MailFolderId $subfolder.Id $global:foldersize = $global:foldersize + $targetbox.AdditionalProperties.sizeInBytes } return $count } #ユーザ情報を表示する foreach($User in $Users) { #ユーザアドレスを取得する $userId = $User.mail #カウンタを初期化 $global:foldersize = 0 #ルートフォルダのIDを取得 $rootFolderId = (Get-MgUserMailFolder -UserId $userid -Filter "displayName eq '受信トレイ'").parentFolderId #カウントの実行開始 $totalMessageCount = Get-MessageCountRecursively -UserId $userId -FolderId $rootFolderId #配列データを構築する $report += New-Object PSObject -Property $([ordered]@{ "UserName" = $userId "mailcount" = Get-MgUserMessageCount -UserId $userId "mailsize" = $global:foldersize }) } #CSVでエクスポートする $report | export-csv $PSScriptRoot\result.csv |
オンライン・アーカイブを取得する
前述までの状態は通常のOutlookの個人のデータを取得する場合のPowerShellスクリプトになります。しかし企業の場合はIn-Place Archiveと呼ばれるオンライン・アーカイブと呼ばれるものを用意してる場合があります。デフォルトでは無効なのですが、有効化してる場合、ここにアーカイブしたデータは前述のコードでは取得できません。そこでこのデータを取得してみたいと思います。
オンライン・アーカイブを有効化する
オンライン・アーカイブはExchange管理センターから個別にユーザに対して有効化する必要があります。以下の手順で有効化すると特別なアーカイブスペースが用意されて、Business Basicだと50GBまで用意されます。
- Exchange管理センターを開く
- 左サイドバーから受信者→メールボックスを開く
- 対象のユーザをクリックする
- 右サイドバーが出てくるので、その他タブを開く
- メールボックスアーカイブの管理をクリックする
- メールボックスアーカイブのステータスを有効にチェックする
- 名前はこのアーカイブスペースの名前を入れます(例:Archivemanなど)
- 保存をクリックする
これで暫くすると、Web版およびローカル版のOutlookに7.の名前でもってオンライン・アーカイブスペースが表示されます。
図:管理センターから有効化可能
In-Place Archiveが表示されない
有効化して暫くしたら表示されるハズなのに表示されないケースがあります。その場合、PowerShellで以下のコマンドを実行して対象ユーザの更新を行い、ユーザは一度ログアウトしてログインし直すと表示されるようになります。
但し、Get-Mailboxメソッドを使うので、事前にモジュールをインストールが必要です。
1 2 |
#モジュールの追加インストールと接続 Install-Module ExchangeOnlineManagement |
これで特権管理者アカウントでログインをすると、メソッドが使えるようになります。
その後以下のようなPS1ファイルを作成してPowerShellで実行してみます。-ArchiveNameで指定する名前はコードではIn-Place Archive ユーザ名となっていますが、ここは前述の7.の項目のアーカイブの名前に該当する部分です。
1 2 3 4 5 6 7 8 9 10 11 12 |
#スコープを指定して接続 Connect-ExchangeOnline #ユーザのメアドを指定 $user = "更新する対象ユーザのメールアドレス" #ユーザのメールボックスに接続 Get-Mailbox $user | FL ArchiveName #設定を変更する $dn=Get-Mailbox $user | Select -ExpandProperty DisplayName Set-Mailbox $user -ArchiveName "In-Place Archive -$dn" |
図:アーカイブスペースが表示されました。
データを取得する
このIn-Place Archive内のデータを取得するのはちょっとだけ大変です。メールの件数とフォルダサイズを取得するわけなのですが、まずは以下のコマンドで調べてみます。こちらも前述のGet-Mailbox同様にExchangeOnlineManagementモジュールのインストールと、Connect-ExchangeOnlineでの接続が必要です。
1 |
Get-MailboxFolderStatistics -Identity "ここに対象のメアド" -Archive | Select-Object Name, FolderPath |
すると、以下のスクショのような結果が得られました。onlineは自分が作ったArchive用メール格納フォルダ。削除済みアイテムやらDeletetionsやらは自動で生成されてるものですが、これらは今回の対象からは除外したいです。よって、それらを考慮してメールの件数とファイルサイズを取得する必要があります。
図:余計なフォルダも出てくる
実際にオンラインアーカイブ内のメールの件数およびファイルサイズの合計値を出すスクリプトは以下のようになります。但し、注意点がいくつかあって
- アーカイブ内の余計なフォルダは除外したいのでexcludeFoldersでリストを作っておく
- Get-MailboxFolderStatisticsにてArchiveオプションにて情報を取得できます。
- 但し返ってくる値が 100kb( 100000 bytes)みたいな文字列で返ってくるので正規表現等で文字だけ取り出す
- 同様にアーカイブ内のフォルダのリストを取得して、今度はメールの件数を合計していく
- where-objectでは、-andを構文内で使うことで複数の条件を指定可能です。
といったちょっとトリッキーな流れになっています。この流れを関数化しておき、前述でも使ったreportのオブジェクトに結果として含めてCSV出力すると良いでしょう。ただ、ReceivedDateTimeを指定して期間指定してフィルタできるかどうかは不明です(調べた限りではできない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#スコープ指定して接続 Connect-ExchangeOnline #対象となるユーザのアドレス $Mailbox = "ここに対象のユーザのメアドを入れる" #除外するフォルダを指定 $excludeFolders = @( "インフォメーション ストアの先頭", "削除済みアイテム", "Recoverable Items", "Deletions" ) #対象のフォルダのサイズを取得実行 $text = (Get-MailboxFolderStatistics -Identity $Mailbox -Archive | Where-Object { $_.Name -notin $excludeFolders }).Foldersize # 正規表現で()内の数字を抽出 $matches = [regex]::Matches($text, "\((.*?)\)") # 合計値を初期化 $sum = 0 # 抽出された数字を処理 foreach ($match in $matches) { # bytesという文字列とカンマを取り除く $numberString = $match.Groups[1].Value -replace " bytes|,", "" # 数値に変換 $number = [int]$numberString # 合計に加算 $sum += $number } # ファイルサイズ合計値を出力 Write-Host "合計: $sum bytes" #アーカイブフォルダのリストを取得 $folderStats = Get-MailboxFolderStatistics -Identity $Mailbox -Archive | Where-Object { $_.Name -notin $excludeFolders } #対象フォルダ内のメールの件数を合計していく $totalItems = 0 foreach ($folder in $folderStats) { $totalItems += $folder.ItemsInFolder } #アーカイブ内のメールの件数合計を出力 Write-Host ("合計: {0} 件" -f $totalItems) |
図:サイズと件数合計を取得できた
共有メールボックスを取得する
Microsoft365のExchange OnlineはGoogle Workspaceと違い、共有メールボックスという指定のメンバー内で共同利用する特殊なメールボックスがあります。GWS的には共同トレイに該当するもので、特定個人に紐つかない独立したメールボックスです。Exchange管理センターから作成することができます。
この共有メールボックスに来てるメールのアイテム数とファイルサイズを調査したいと思い調べてみると、また違うメソッドを使う必要があるようです。それを元に構築したコードが以下のとおりです。結果は共有メールボックスのアドレス毎にアイテム数とファイルサイズを列挙し、CSVで出力するものになっています。
- sharedMailboxesの変数に調査する共有メールボックスのアドレスを列挙する
- 共有メールボックスの調査はGet-EXOMailboxStatisticsを利用して調べることが可能です。
- 調べた結果は割と素直に、ItemCountとTotalItemSizeの値を整えて取得が可能です。
- 最後にレポート用オブジェクトに格納し、Export-CsvにてPS1ファイルと同じ場所にCSV出力しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# Exchange Online に接続 (未接続の場合) Connect-ExchangeOnline # 🔹 ここで調べたい共有メールボックスのアドレスを指定 $sharedMailboxes = @( "hogehoge@domain.onmicrosoft.com" ) # メールボックスサイズとアイテム数を取得 $mailboxData = $sharedMailboxes | ForEach-Object { $mailboxStats = Get-EXOMailboxStatistics -Identity $_ # メールボックスのサイズ(バイト数)とアイテム数 $sizeBytes = $mailboxStats.TotalItemSize.Value.ToBytes() $itemCount = $mailboxStats.ItemCount # 結果をカスタムオブジェクトとして出力 [PSCustomObject]@{ Mailbox = $_ ItemCount = $itemCount SizeBytes = $sizeBytes } } # 🔹 結果をCSVファイルとして出力 $mailboxData | Export-Csv -Path "$PSScriptRoot\mailbox_sizes.csv" -NoTypeInformation -Force Write-Host "📢 結果を 'mailbox_sizes.csv' に出力しました。" |
図:共有メールボックスも出力できました
カレンダーを取得する
単一ユーザのイベント数を取得する
Microsoft365のオブジェクト調査対象はメールだけじゃありません。カレンダーもそういったものの1つです。しかし、カレンダーはユーザに1個だけ用意されてるわけじゃなく、予定表を追加にて自分の個人用の予定表に何個も追加して使い分けしてるのが定石です。これらのカレンダーのイベント数(オブジェクト数)も調査したい所です。
主に利用するメソッドは以下のとおりです。
カレンダー一覧を取得して回し、各カレンダーのイベント数を取得します。一度に100件取得して、ページネーションで分かれるのでその部分で再帰処理を掛けて全オブジェクト数を取得します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# Microsoft Graph API に接続 Connect-MgGraph -Scopes "Calendars.Read" # ユーザーIDを設定 $userId = "ここに取得対象のユーザのメールアドレスを入力する" # すべてのカレンダーを取得 $calendars = Get-MgUserCalendar -UserId $userId # 全カレンダーのイベントを格納する配列 $allEvents = @() # 各カレンダーのイベントを取得 foreach ($calendar in $calendars) { $calendarId = $calendar.Id Write-Host "Processing Calendar: $($calendar.Name)" # 最初のページのイベントを取得 $events = Get-MgUserCalendarEvent -UserId $userId -CalendarId $calendarId -Top 100 # 取得したイベントを格納 $calendarEvents = @() $calendarEvents += $events # ページネーション処理(次のページがある場合) while ($events.AdditionalData.'@odata.nextLink') { $nextLink = $events.AdditionalData.'@odata.nextLink' $events = Invoke-MgGraphRequest -Uri $nextLink $calendarEvents += $events } # 取得したイベントを全体のリストに追加 $allEvents += $calendarEvents } # 全イベント数を表示 Write-Host "Total Events Count: $($allEvents.Count)" |
図:個人の予定表のデータ全部を対象にする
図:カレンダーのオブジェクト数を取得してみた
全ユーザのイベント数とファイルサイズを取得
前述は単一ユーザのイベント数のみを取得していました。実際の現場では前述にもありましたがユーザリスト(inbox.csv)があって、それら全ユーザ分を取得しつつ、またイベントに付属の添付ファイルのファイルサイズも計測する必要があります(無い場合もある)。
よってこれらを踏まえて、ユーザリストを回しつつイベント数と添付ファイルがあればそのファイルサイズを取得、一覧表にまとめてCSVで出力というものを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# Microsoft Graph API に接続 Connect-MgGraph -Scopes "Calendars.Read" # ユーザーリストのCSVファイルを指定("mail" 列にユーザーのメールアドレスが含まれる) $userListFile = "$PSScriptRoot\inbox.csv" # 出力するCSVファイル名 $outputCsv = "$PSScriptRoot\calendar_events.csv" # CSVファイルからユーザーリストを読み込み $users = Import-Csv -Path $userListFile | Select-Object -ExpandProperty mail # 出力用のリスト $results = @() # 各ユーザーのカレンダーとイベントを取得 foreach ($userId in $users) { Write-Host "Processing User: $userId" # すべてのカレンダーを取得 try { $calendars = Get-MgUserCalendar -UserId $userId } catch { Write-Host " -> Failed to get calendars for $userId. Skipping..." continue } # ユーザーごとのイベントカウントとファイルサイズ $totalEventCount = 0 $totalFileSize = 0 # 各カレンダーのイベントを取得 foreach ($calendar in $calendars) { $calendarId = $calendar.Id Write-Host " -> Processing Calendar: $($calendar.Name)" # 最初のページのイベントを取得 try { $events = Get-MgUserCalendarEvent -UserId $userId -CalendarId $calendarId -Top 100 } catch { Write-Host " -> Failed to get events for calendar: $($calendar.Name). Skipping..." continue } # イベントを格納するリスト $calendarEvents = @() $calendarEvents += $events # ページネーション処理(次のページがある場合) while ($events.AdditionalData.'@odata.nextLink') { $nextLink = $events.AdditionalData.'@odata.nextLink' try { $events = Invoke-MgGraphRequest -Uri $nextLink $calendarEvents += $events } catch { Write-Host " -> Failed to retrieve next page of events. Skipping pagination..." break } } # イベントカウントを更新 $totalEventCount += $calendarEvents.Count # 各イベントの添付ファイルサイズを取得 foreach ($event in $calendarEvents) { $eventId = $event.Id try { # 添付ファイルを取得 $attachments = Get-MgUserEventAttachment -UserId $userId -EventId $eventId # 添付ファイルサイズを合計 foreach ($attachment in $attachments) { if ($attachment.PSObject.Properties["Size"]) { $totalFileSize += $attachment.Size } } } catch { Write-Host " -> Failed to retrieve attachments for event: $eventId. Skipping..." } } } # 結果をリストに追加 $results += [PSCustomObject]@{ UserAddress = $userId EventCount = $totalEventCount FileSize = $totalFileSize } } # CSVファイルに出力 $results | Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8 Write-Host "Processing completed. Results saved to $outputCsv" |
図:添付ファイルのサイズ等も含めて計測
図:出力されたCSVファイル
パブリックフォルダを取得する
パブリックフォルダ内のコンテンツはメールやカレンダー、ファイル類と広くいろいろなものがごっちゃになってるかと思います。これらのオブジェクト数を割り出すGet-PublicFolderStatisticsというメソッドがあります。現在研究中。
パブリックフォルダが表示されない
Outlookには特殊な機能として「パブリックフォルダ」というものがあります。これはExchange管理センターから作成できますが、これがユーザに表示されないことがあります。その覚書です。この原因は
- Exchange管理センターでパブリックフォルダが作成されてるが、アクセス許可を対象ユーザに与えていない
- ユーザにアクセス許可が与えられてるが、ユーザがOutlook上で自身で追加していない(勝手に表示されるわけじゃないため)
の2点になります。障害としてアクセス許可を削除して再度追加したら出てきたみたいなケースもあります。このパブリックフォルダ内のカレンダーやメール、カレンダー類は特殊な個別のメアドが与えられてるものになるので、共有メールボックスや自身のメアドとはまた違うものになるので要注意です。
図:アクセス許可を追加する
図:Outlook上で追加する
図:表示されるようになりました
スクリプトで取得する
Exchange管理センターで用意してるパブリックフォルダはルートとその下にぶら下がるサブフォルダで構成されています。各フォルダ名、アイテム数合計、ファイルサイズ合計を出すPowerShellのコマンドを作ってみました。ただ、サブフォルダ以下にさらにサブフォルダがある場合を考慮していないので、もしそうした構成の場合は再帰的に処理して孫フォルダ以下もすべて浚うように作り変える必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#CSVファイルの名前 $ReportOutput = "$PSScriptRoot\publicfolder.csv" #スコープを指定して接続 Connect-ExchangeOnline # すべてのパブリックフォルダを取得 $PublicFolders = Get-PublicFolder -Recurse # 結果を格納するリスト $FolderStats = @() # 各パブリックフォルダの内容を取得 foreach ($Folder in $PublicFolders) { # パブリックフォルダのパス $FolderPath = $Folder.Identity # コンテンツ数とサイズを取得 $Stats = Get-PublicFolderStatistics -Identity $FolderPath # 結果を格納 $FolderStats += [PSCustomObject]@{ FolderName = $FolderPath ItemCount = $Stats.ItemCount TotalSize = $Stats.TotalItemSize.ToString() } } # 結果をCSVとして出力 $FolderStats | Export-Csv -Path $ReportOutput -NoTypeInformation -Encoding UTF8 |
管理センターから取得する
Exchange Onlineは前述の通り様々な取得対象が存在しており、しかも簡単に取得ができませんでした。しかし、Sharepointの場合にはサイト毎のファイル数やファイルサイズは割と簡単に取得することが可能です。この手法はPowerShellを使わずに手に入れる方法です。
- こちらのリンクから自身のテナントのSharepoint管理センターを開く(テナント毎にURLが違うので要注意)
- するとアクティブなサイトというページが出てくる
- エクスポートをクリックする
- CSVでダウンロードされる
CSVの中身を開いてみると、サイト名の他にファイルがファイル数(つまりオブジェクト数)、使用済みストレージ (GB)がファイルサイズ合計となります。Teamsで使われてるかどうか?のフラグなどもあり、これで必要十分と言えば十分です。
図:CSVで簡単に手に入る
スクリプトで取得する
概要
Sharepoint管理センターを使わずにPowerShellにて取得する場合には、Exchange Onlineのように追加のモジュールをインストールしてからスクリプトを実行する必要がありますが、ここハマりポイントが2つありました。
- SharePoint Online 管理シェルが必要でmacOSではインストールまではできますが、Connect-SPOServiceが動作しませんので接続ができません。
- Windows11のPowerShell7で上記をインストールしたものの、やはり接続ができない。どうもPowerShell5系でないと動作しないようだ。
- 公式ではないPnP PowerShellというモジュールもあるようで、こちらはmacOSからも使えるようだ。但しAzureにアプリ登録のコマンドはWindowsのPowerShellからじゃないとできないという罠。
- そして対応を進めてわかったのが、「SharePoint Online 管理シェル」では標準でファイル数やファイルサイズを取得できないことが判明。故にPnP PowerShellを使うのが正解のようだ。
ということなので、公式ドキュメントにあるまま接続しようとするとエラーに遭遇して先に進めません。
追加モジュールのインストールと接続
ということでSharePoint Online Management Shellではなく、PnP PowerShellを使って取得をしてみることにします。その為には追加でモジュールのインストールが必要です。管理者権限のPowerShellで実行します。
1 |
Install-Module -Name PnP.PowerShell -Force -AllowClobber |
インストールが完了したら、Azure Portalにアプリの登録をするのですが専用のコマンドが用意されています。
1 |
Register-PnPAzureADApp -ApplicationName PnPApp001 -Tenant yourtenant.onmicrosoft.com -Store CurrentUser -Interactive |
yourtenantの部分はメアドの@より後ろの部分がそれに該当。これを実行するとログインと承認が求められるので許可するとアプリがAzure Portalに自動的に登録されます。上記コマンドだとすべてのアプリケーション欄にPnPApp001という名前で登録されます。開いてみて、アプリケーション(クライアント)IDの値が必要なので控えておく。
アプリのアクセス許可も自動的にすべて追加されています。
図:Azureにアプリ登録中
図:クライアントID等が必要
全サイトの情報を取得する
Azure Portalまで使ってClient IDを手に入れてようやくと思いきや、このコードが結構複雑。Sharepoint管理センターのような一覧がパッと取れるわけじゃないという。
- サイトのドキュメント内のものだけを対象に検索します。
- 直下→サブフォルダ内まで再帰的に処理してファイル件数とサイズを取得していかなければならない。
- 量が多いと429エラーが起きる可能性がある(回避策はこちらのサイト)
- 再帰処理をさせる為に関数に切り出しておく箇所がある
- サイトのURL毎にConnect-PnPOnlineで接続しなおさないときちんとデータが取れません。
- /sites/以外のURLも含まれてくるのでこれらは処理対象外として除外する
かなり苦労して、結局はSharepoint管理センターのCSV一発で取れるものと殆ど同じなので、ちょっと使い勝手が悪いなぁと思う。別の使い方(フォルダの階層構造をしらべる等)では応用して使えるかもといったところです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# CSVファイルの出力先パスを指定 $csvFilePath = "$PSScriptRoot\sharepoint_site_info.csv" #認証情報 $clientId = "ここにクライアントIDを入れる" # すべてのサイトコレクションを取得 $sites = Get-PnPTenantSite # 結果を格納する配列を初期化 $results = @() # 再帰的にフォルダ内のファイルを取得する関数 function Get-FilesInFolder { param ( [Parameter(Mandatory=$true)] [string]$FolderServerRelativeUrl, [Parameter(Mandatory=$true)] [object]$List ) # フォルダ内のアイテムを取得(ファイルとサブフォルダ) $items = Get-PnPListItem -List $List -FolderServerRelativeUrl $FolderServerRelativeUrl foreach ($item in $items) { if ($item.FileSystemObjectType -eq "File") { # ファイル数をカウント $global:totalFileCount++ # ファイルサイズを加算 $global:totalFileSize += $item["File_x0020_Size"] } elseif ($item.FileSystemObjectType -eq "Folder") { # サブフォルダがある場合、その中も再帰的に処理 Get-FilesInFolder -FolderServerRelativeUrl $item["FileRef"] -List $List } } } # 各サイトコレクションを処理 foreach ($site in $sites) { Write-Host "サイトコレクション: $($site.Url) を処理中..." # "/sites/" を含むURLのみ処理 if ($site.Url -match "/sites/") { #サイトごとに接続しなおす必要がある(でないとドキュメントが出てこない) Connect-PnPOnline -Url $site.Url -ClientId $clientId -Interactive # すべてのサイトを取得 $webs = Get-PnPWeb -Includes Title, Url, ServerRelativeUrl, Lists foreach ($web in $webs) { Write-Host " サイト: $($web.Title) を処理中..." # ファイル数とファイルサイズを初期化 $global:totalFileCount = 0 $global:totalFileSize = 0 # 各リストを処理 foreach ($list in $web.Lists) { # "ドキュメント"ライブラリのみを処理 if ($list.BaseType -eq "DocumentLibrary" -and $list.Title -eq "ドキュメント") { Write-Host " リスト: $($list.Title) を処理中..." # サイトのServerRelativeUrlを使ってShared Documentsフォルダの相対URLを組み立て $rootFolderServerRelativeUrl = $web.ServerRelativeUrl + "/Shared Documents" # ルートフォルダ内のファイルとサブフォルダを再帰的に取得 Get-FilesInFolder -FolderServerRelativeUrl $rootFolderServerRelativeUrl -List $list } } # 結果を配列に追加 $results += [PSCustomObject]@{ SiteUrl = $site.Url FileCount = $global:totalFileCount TotalFileSizeMB = $global:totalFileSize # ファイルサイズをMBに変換 } } } else { Write-Host " サイトURL ($($site.Url)) は処理対象外です。" } } # 結果をCSVファイルに出力 $results | Export-Csv -Path $csvFilePath -NoTypeInformation |
OneDrive Business
Microsoft365のOneDriveはURLを見るとわかるのですが、SharepointとしてのURLが表示されています。つまり仕組みはSharepointと同じで個人向けのサイトとして用意してるものと言えます。
Sharepointと似たようなものであるため、前述のSharepointのデータ取得法で出来ないか?現在研究中です。
管理センターから取得する
Sharepointの場合同様にOneDriveについても管理センターからユーザ別のファイル数とファイルサイズの合計がCSVで簡単に入手することが可能です。但しSharepoint管理センターではなくMicrosoft365管理センターからの入手になります。
- ここのリンクからMicrosoft365管理センターに入る
- 左サイドバー一番下の「すべてを表示」をクリックする
- 左サイドバーのレポート→利用状況をクリックする
- 新たな画面で左サイドにOneDriveがいるのでクリックする
- 利用状況タブが開かれていますが、右パネルの下に一覧が表示されています。但しユーザはメアドや名前じゃなく数値文字のIDのようなものとして表記されています。
- 一覧表を右スクロールしていくと、列の選択というのが出てくるのでクリックする
- 未チェックのものがあるので全部チェックを入れて保存をクリック
- ファイルやサイズなども表示されていたら、上部にある「エクスポート」をクリックする
- CSVがダウンロードされる
CSVの中の「File Count」がファイル数、Storage Used (Byte)が「ファイルサイズ(bytes)」となります。
図:利用状況レポートから出力する
図:CSVを覗いてみる
スクリプトで取得する
基本的にはSharepoint Onlineの時と同様ですが多少異なる点もあります。
- クライアントIDが必要な点はSharepointと同様です
- PnP PowerShellを使って取得する点も同様です。
- yourtenantの部分についても同様です。書き換えが必要です。
- 初回の接続時およびここのユーザの情報を取得時の2回、認証が必要になるため注意が必要です。
- ファイル数のカウントの為にGet-FileCount関数を作成し再帰的に処理をしています。
- 最後にCSV出力をして完成です
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#接続するテナントの $TenantAdminURL = "https://yourtenant-admin.sharepoint.com" #出力するCSVのパスと名前 $ReportOutput = "$PSScriptRoot\OneDriveUsage.csv" #認証情報 $clientId = "ここにクライアントIDを入れる" #PnPOnlineでOneDriveに接続する Connect-PnPOnline -Url $TenantAdminURL -ClientId $clientId -Interactive #すべてのユーザのOneDriveリストを取得する $OneDriveSites = Get-PnPTenantSite -IncludeOneDriveSites -Filter "Url -like '-my.sharepoint.com/personal/'" -Detailed #レポート用のオブジェクト $UsageData = @() #ユーザのOneDriveのファイル数をサブフォルダまで含めて再帰的に取得する function Get-FileCount($folderPath) { $count = 0 #すべてのフォルダのリストを取得する $files = Get-PnPListItem -List "Documents" -PageSize 1000 | Where-Object { $_.FieldValues.FileRef -like "$folderPath/*" } $count += $files.Count #サブフォルダを取得する $folders = Get-PnPFolderItem -FolderSiteRelativeUrl $folderPath -ItemType Folder foreach ($folder in $folders) { $count += Get-FileCount $folder.ServerRelativeUrl } return $count } #ユーザのOneDriveリストを回す ForEach($Site in $OneDriveSites) { Try { Write-host "探索サイト:"$Site.URL -f Yellow # OneDrive サイトに接続 Connect-PnPOnline -Url $Site.URL -ClientId $clientId -Interactive #対象ユーザのOneDriveのファイル数合計を取得する $TotalFiles = Get-FileCount "Documents" #出力用のレポートを作成する $UsageData += [PSCustomObject][ordered]@{ SiteName = $Site.Title Owner = $Site.owner UsedSpaceMB = $Site.StorageUsageCurrent TotalFiles = $TotalFiles } } Catch { write-host "エラー: $($_.Exception.Message)" -foregroundcolor Red } } #CSVで出力する $UsageData | Format-table $UsageData | Export-Csv -Path $ReportOutput -NoTypeInformation |
図:無事に全ユーザのOneDriveの情報を取得できた
関連リンク
- Using Get-MgUserMessageCount in Graph PowerShell
- Get-MgUserMailFolder: メール フォルダーを取得および管理する方法
- PowerShell Exchange Online使用して Microsoft 365 または Office 365 メールボックス情報を表示する
- Exchange Online PowerShell モジュールでサポートされているオペレーティング システム
- Windows PowerShell での Exchange Online への接続について
- How to get Mailbox size and Archive size in same table - powershell, exchange
- How to check mailbox size in Microsoft Exchange using PowerShell scripts
- 手順 1: Exchange Online PowerShell モジュールを読み込む
- Microsoft Graph PowerShell
- Get-MgUserMessageCount
- Get-MgBetaUserMessageCount
- Get-MgUserMailFolder
- Get-MgUserMailFolderChildFolder
- 実行中に変数の中身を確認する方法
- mailFolder を取得する
- ExoGraphGUI 1.2.0
- PowerShell Script to return the total email or item count in office 365 online archive mailbox
- How to get current and archive mailbox sizes from Powershell?
- Microsoft Graph PowerShell SDK をインストールする
- Microsoft Graph PowerShell から Microsoft365 に接続する
- Windows への PowerShell のインストール
- Running Get-MgUserDefaultCalendar in PowerShell gives Access is denied error
- Microsoft Graph PowerShell SDK を使い始める
- scope 'Mail.ReadBasic.All' that doesn't exist on the resource '00000003-0000-0000-c000-000000000000'
- 【Microsoft Azure】Microsoft Graph PowerShell SDKを使ったユーザー作成手順
- Exporting PST Files from Powershell
- How to count specific folder items in SharePoint site using PowerShell
- SharePoint Online: Get List Item Count using PowerShell
- Get List Item Count in SharePoint Online Using PowerShell
- Microsoft 365: Get OneDrive for Business Usage Report using PowerShell
- How to Get List of Exchange Online Mailboxes in Microsoft 365
- Get Mailbox Size for List of Users from CSV
- Get Exchange mailbox folder count using PowerShell
- Get mailbox size from csv exchange online
- Practical Graph: Working with Exchange Online Mailbox Data
- Powershell MSGraph module: Filtering by Date
- $filter クエリ パラメーターを使用する
- Powershell - Import local CSV
- Microsoft 365 の Outlook でメールをインプレース アーカイブに自動で移動する方法
- Exchange Online Archive を契約したので有効化の方法を知りたいです。
- オンラインアーカイブメールボックスでメールストレージを管理する
- Get-Mailbox: 「Get-Mailbox」という用語は認識されません
- アーカイブ メールボックスが Outlook または Web 上の Outlook に表示されない
- O365 In-Place archive not showing in Outlook web version
- How to get current and archive mailbox sizes from Powershell?
- 【Office 365】PowerShellでのリスト処理に役立った私的コマンド集(随時更新)
- PowerShell で New-ComplianceSearch を使用する方法
- Get shared mailbox size in Office 365 with PowerShell
- 【PowerShell】PnP PowerShell を利用して SharePoint リストを操作しよう①
- PnP PowerShell を利用するための Microsoft Entra ID アプリケーションを登録する方法
- SharePoint Online 用の PnP PowerShell モジュールをインストールする
- How should I get file count for only one SharePoint folder in PowerShell
- How to get the total number of nested files and folders inside the main folders inside a document library
- Get-PnPFolderItemでSharepointOnline/One Drive for Businessの一覧を取得する
- Outlook for Windows でパブリック フォルダーにアクセスする
- パブリック フォルダーおよびパブリック フォルダー アイテムの統計情報を表示する