{"id":196398,"date":"2024-05-30T19:52:52","date_gmt":"2024-05-31T00:52:52","guid":{"rendered":"https:\/\/itblog.ldlnet.net\/?p=196398"},"modified":"2024-06-04T11:18:50","modified_gmt":"2024-06-04T16:18:50","slug":"get-m365graphmbreport-ps1","status":"publish","type":"post","link":"https:\/\/itblog.ldlnet.net\/index.php\/2024\/05\/30\/get-m365graphmbreport-ps1\/","title":{"rendered":"Get-M365GraphMBReport.ps1"},"content":{"rendered":"\n<p>I have been updating my scripts from using Exchange Online PowerShell to using the Microsoft Graph SDK as the Microsoft Graph is WAY more powerful of a tool to use. In the old script, I used the Get-MailboxStatistics cmdlet to get all the mailbox sizes for users and maybe some other data. That has since moved to the Reports tab in the M365 Admin Center where you can get different reports on usage and adoption. <br>This was a great opportunity to be able to run this report in a PowerShell script that you could automate if needed. I am sure there are other ways maybe through PowerApps or Power Automate that would do the same thing. You could essentially put this script in a Power Automate function and send the report where you need it once completed. Of course, modification would need to be done for the Input\/and Output locations for the CSV, AND you could also make the script send an email through the Microsoft Graph SDK in another set of commands. That is for more down the road. I am on the catch up when it comes to using the SDK.<\/p>\n\n\n\n<p>This script will Connect to MS Graph with Powershell using the auth token method for authentication so you don&#8217;t have to logon. Make sure you have the Azure Enterprise Application setup, the &#8216;Reports.Read.All&#8217; and Users.Read.All scope permissions granted to the API in Azure. You will need your AppID, TenantID, and Secret Key form the Azure App Registrations Overview Page to proceed. The script explains that though.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SCRIPT<\/h2>\n\n\n<pre class=\"lang:PowerShell nums:True\" title=\"Get-M365GraphMBReport.ps1\">\n\n<#\n\n.SYNOPSIS\n\nGet an M365 Mailbox Usage Report of all members of a Commercial Tenant with M365 Exchange Online Mailboxes. It will tell you what their mailbox usage details for all mailboxes in the cloud that are active.\nThe report will be in CSV Format and will output to a predetermined directory based on the Parameters set in the script.\n\n\n\n.NOTES\n\n    Name: Get-M365GraphMBReport\n\n    Author: Lance Lingerfelt\n\n    Version: 2.0\n\n    Modify Date: 2024, May 30\n\n    Parameter Values:\n\n    $ReportsPath sets the path to a default directory and will create the directory if needed later in the script. Setting a value is NOT mandatory but script will setup a directory of C:\\MatlockScripts\\Reports\n    $AppID is the Application (client) ID of an App Registration in Azure AD - Required\n    $Secret is the client secret of the App Registration in Azure AD - Required\n    $TenantID is the Tenant ID of the Azure AD Tenant - Required\n   \n.EXAMPLE\n\nConnect to a Comerical Tenant in the Script\n\n    .\\Get-M365GraphMBReport.ps1 -ClientID \"00000000-0000-0000-0000-000000000000\" -ClientSecret xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -TenantID \"00000000-0000-0000-0000-000000000000\"\n\n#>\n\n\n[CmdletBinding(SupportsShouldProcess = $true)]\nParam(\n    [Parameter(Mandatory = $false)]\n    [string] $ReportsPath = \"C:\\LDLNETScripts\\Reports\",\n    \n    [Parameter(Mandatory = $true)]\n    [string] $AppID,\n\n    [Parameter(Mandatory = $true)]\n    [string] $Secret,\n\n    [Parameter(Mandatory = $true)]\n    [string] $TenantID\n\n    )\n\n# ================================================\n#               DO NOT MODIFY BEGIN\n# ================================================\n\n$ErrorActionPreference = 'Continue'\n\n$Date = Get-Date -Format \"MM\/dd\/yyyy\"\n\n# Set Logging Configuration\n$Log = [PSCustomObject]@{\n    Path = \"C:\\LDLNETScripts\\Logs\\Get-M365GraphMBReport\"\n    Name = \"$($Date).log\"\n}\n# ================================================\n#                DO NOT MODIFY END\n# ================================================\n#\n# ================================================\n#                   SCRIPT BEGIN\n# ================================================\n\n# Log Start of Script\nWrite-Host \"Start of Script\" -ForegroundColor Red\nWrite-VerboseLog \"Start of Script\"\n\n# Create Report Path if not there\nWrite-VerboseLog \"Creating Report Path if not there\" \nWrite-Host \"Creating Report Path if not there\"-ForegroundColor Blue\nif (!(Test-Path $ReportsPath)) {\n    New-Item -Type Directory -Path $ReportsPath\n}\n\n# Create New Logger Instance if Enabled\nif ($PSCmdlet.ShouldProcess(\"Create New Logger Instance\", $Log.Path)) {\n    # Import Logger Module\n    try {\n        if ( -not (Get-Module -Name PoShLog -ListAvailable) ) {\n            Install-Module -Name PoShLog -Scope CurrentUser -Force\n        }\n        else {\n            Import-Module -Name PoShLog -Force\n        }\n    }\n    catch {\n        Write-Host -Object \"Unable to import logger module. Error: $($_.Exception.Message)\"\n        exit 1\n    }\n\n    # Import Microsoft Graph Modules for User and Mailbox settings\n    try {\n        if ( -not (Get-Module -Name Microsoft.Graph.Mail -ListAvailable) ) {\n            Install-Module -Name Microsoft.Graph.Mail -Scope CurrentUser -Force\n        }\n        else {\n            Import-Module -Name Microsoft.Graph.Mail -Force\n        }\n        if ( -not (Get-Module -Name Microsoft.Graph.Users -ListAvailable) ) {\n            Install-Module -Name Microsoft.Graph.Users -Scope CurrentUser -Force\n        }\n        else {\n            Import-Module -Name Microsoft.Graph.Users -Force\n        }\n    }\n    catch {\n        Write-Host -Object \"Unable to import Microsoft Graph module(s). Error: $($_.Exception.Message)\"\n        exit 1\n    }\n}\n\n# Authenticate and connect to Microsoft Graph using the Token Method and the Microsoft Graph SDK variables set in the cmdlet.\n# You can replace with your authentication method if you wish to use a different method.\n$tenantId = $TenantID\n$clientId = $AppID\n$clientSecret = $Secret\n\n$body = @{\n    grant_type    = \"client_credentials\"\n    scope         = \"https:\/\/graph.microsoft.com\/.default\"\n    client_id     = $clientId\n    client_secret = $clientSecret\n}\n\n$tokenResponse = Invoke-RestMethod -Method Post -Uri \"https:\/\/login.microsoftonline.com\/$tenantId\/oauth2\/v2.0\/token\" -ContentType \"application\/x-www-form-urlencoded\" -Body $body\n\n# Convert the client secret to a SecureString\n$securetoken = ConvertTo-SecureString $tokenResponse.access_token -AsPlainText -Force\n\n$accessToken = $securetoken\n\n# Use the token to connect to Microsoft Graph\nWrite-VerboseLog \"Connecting to Microsoft Graph SDK Endpoint\" \nWrite-Host \"Connecting to Microsoft Graph SDK Endpoint\"-ForegroundColor Red\nConnect-MgGraph -AccessToken $accessToken \n\n# Get the mailbox usage details for the last 180 days\nWrite-VerboseLog \"Getting Mailbox Usage Details and Information for Each User Past 180 Days\" \nWrite-Host \"Getting Mailbox Usage Details and Information for Each User Past 180 Days\" -ForegroundColor Green \n\n#Run the report and Convert the values to GB or MB respectively - It creates a input file called M365_Mailbox_Detials_In.csv\nGet-MgReportMailboxUsageDetail -Period D180 -OutFile $ReportsPath\\M365_Mailbox_Detials_In.csv\n$report = import-csv $ReportsPath\\M365_Mailbox_Detials_In.csv\n$report.Foreach({\n    $_.\"storage used (Byte)\" = '{0:N2} MB' -f ($_.\"storage used (Byte)\" \/ 1MB)\n})\n$report.Foreach({\n    $_.\"Issue Warning Quota (Byte)\" = '{0:N2} GB' -f ($_.\"Issue Warning Quota (Byte)\" \/ 1GB)\n})\n$report.Foreach({\n    $_.\"Prohibit Send Quota (Byte)\" = '{0:N2} GB' -f ($_.\"Prohibit Send Quota (Byte)\" \/ 1GB)\n})\n$report.Foreach({\n    $_.\"Prohibit Send\/Receive Quota (Byte)\" = '{0:N2} GB' -f ($_.\"Prohibit Send\/Receive Quota (Byte)\" \/ 1GB)\n})\n$report.Foreach({\n    $_.\"Deleted Item Size (Byte)\" = '{0:N2} MB' -f ($_.\"Deleted Item Size (Byte)\" \/ 1MB)\n})\n$report.Foreach({\n    $_.\"Deleted Item Quota (Byte)\" = '{0:N2} GB' -f ($_.\"Deleted Item Quota (Byte)\" \/ 1GB)\n})\n\n# Export the Results\nWrite-Host \"Exporting Results to Path [$ReportsPath]\" -ForegroundColor Yellow\nWrite-VerboseLog \"Exporting Results to Path [$ReportsPath]\"\n\n$report | Export-Csv $ReportsPath\\M365UserMBReport_$(Get-Date -Format yyyyMMddThhmmss).csv -notypeinformation\n\nWrite-Host \"Mailbox Usage report has been exported to [$ReportsPath]\" -ForegroundColor Green\nWrite-VerboseLog \"Mailbox Usage report has been exported to [$ReportsPath]\" \n\n#Delete the input file\nRemove-Item $ReportsPath\\M365_Mailbox_Detials_In.csv\n\nif (Test-Path $ReportsPath\\M365_Mailbox_Detials_In.csv) {\n    Write-Host \"Unable to delete the input file. Please delete it manually. Filepath: [$ReportsPath]\\M365_Mailbox_Detials_In.csv\" -ForegroundColor Red\n    Write-VerboseLog \"Unable to delete the input file. Please delete it manually. Filepath: [$ReportsPath]\\M365_Mailbox_Detials_In.csv\"\n}\nelse {\n    Write-Host \"Input file has been deleted.\" -ForegroundColor White\n    Write-VerboseLog \"Input file has been deleted.\"\n}\n\n# Disconnect from the Microsoft Graph SDK endpoint\nWrite-Host \"Disconnecting from Microsoft Graph SDK Endpoint\" -ForegroundColor Red\nWrite-VerboseLog \"Disconnecting from Microsoft Graph SDK Endpoint\"\nDisconnect-MgGraph\n\n# Log End of Script\nWrite-Host \"End of Script\" -ForegroundColor Red\nWrite-VerboseLog \"End of Script\"\n# ================================================\n#                   SCRIPT END\n#=================================================\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">OUTPUT<\/h2>\n\n\n\n<p>You will receive a CSV file that will look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1867\" height=\"341\" src=\"https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2024\/05\/image-1.png\" alt=\"\" class=\"wp-image-196399\"\/><figcaption class=\"wp-element-caption\">Mailbox Usage Report<\/figcaption><\/figure>\n\n\n\n<p>As you will see in the report, I converted the values to MB and GB respectively, you can make adjustments to the script at you see fit. I am always happy to get feedback and additions to the script as well. Thanks again to Github Copilot for helping with coding some of this script. Feel free to expand it from there, but this script can give you a great report of all your mailbox users in M365 when preparing for migrations or archiving.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<p><a href=\"https:\/\/ourcloudnetwork.com\/generate-mailbox-usage-reports-with-microsoft-graph-powershell\/#:~:text=Connect-MgGraph%20-scopes%20Reports.Read.All%20%24path%20%3D%20%22C%3AtempMailboxReport.csv%22%20Get-MgReportMailboxUsageDetail%20-Period,1MB%29%20%7D%29%20%24report%20%7C%20Export-CSV%20-Path%20%24path%20-NoTypeInformation\">Generate Usage Reports with Microsoft Graph PowerShell<\/a><br><a href=\"https:\/\/baswijdenes.com\/report-mailbox-and-onedrive-size-in-powershell-via-microsoft-graph-api\/\">Report Mailbox and OneDrive Size in PowerShell via MS Graph API (baswijdenes.com)<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">About Lance Lingerfelt<\/h2>\n\n\n\n<div class=\"wp-block-media-text is-stacked-on-mobile\" style=\"grid-template-columns:22% auto\"><figure class=\"wp-block-media-text__media\"><img loading=\"lazy\" decoding=\"async\" width=\"468\" height=\"412\" src=\"https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2024\/03\/ProfLDL1.jpg\" alt=\"Lance Lingerfelt Profile Photo\" class=\"wp-image-196223 size-full\"\/><\/figure><div class=\"wp-block-media-text__content\">\n<p class=\"has-small-font-size\">Lance Lingerfelt is an M365 Specialist and Evangelist with over 20 years of experience in the Information Technology field. Having worked in enterprise environments to small businesses, he is able to adapt and provide the best IT Training and Consultation possible. With a focus on AI, the M365 Stack, and Healthcare, he continues to give back to the community with training, public speaking events, and this blog.<\/p>\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>I have been updating my scripts from using Exchange Online PowerShell to using the Microsoft Graph SDK as the Microsoft Graph is<\/p>\n<p class=\"link-more\"><a class=\"myButt \" href=\"https:\/\/itblog.ldlnet.net\/index.php\/2024\/05\/30\/get-m365graphmbreport-ps1\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":196400,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"footnotes":""},"categories":[195,2,265,194,3,301],"tags":[9,303,393,362,392,8,363],"class_list":["post-196398","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-general","category-microsoft365","category-office365","category-powershell","category-training","tag-exchange","tag-exchange-online","tag-graph-sdk","tag-microsoft-graph","tag-ms-graph-sdk","tag-powershell","tag-powershellsdk","odd"],"_links":{"self":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/196398","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/comments?post=196398"}],"version-history":[{"count":7,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/196398\/revisions"}],"predecessor-version":[{"id":196408,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/196398\/revisions\/196408"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/media\/196400"}],"wp:attachment":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/media?parent=196398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/categories?post=196398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/tags?post=196398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}