PowerShell scripts leveraging the Microsoft Graph API for M365 automation including authentication, permission scopes, and common Graph operations across services.
Microsoft Graph is the unified API for accessing Microsoft 365 services. The Microsoft.Graph PowerShell SDK wraps Graph API calls as native PowerShell cmdlets, making it the recommended approach for all modern Microsoft 365 automation.
# Install the full SDK (includes all service modules)Install-Module -Name Microsoft.Graph -Force# Install only the modules you need (faster, smaller footprint)Install-Module -Name Microsoft.Graph.Users -ForceInstall-Module -Name Microsoft.Graph.Groups -ForceInstall-Module -Name Microsoft.Graph.Mail -ForceInstall-Module -Name Microsoft.Graph.Sites -ForceInstall-Module -Name Microsoft.Graph.Teams -ForceInstall-Module -Name Microsoft.Graph.Identity.SignIns -Force# Check the installed versionGet-InstalledModule -Name Microsoft.Graph | Select-Object Name, Version
Installing individual sub-modules instead of the full Microsoft.Graph bundle significantly reduces installation time and import overhead. You can always add more sub-modules later.
For scheduled tasks and automation scripts that run unattended, authenticate as an app registration rather than a user.
# Connect using a client secret (app registration)$ClientId = "your-app-client-id"$TenantId = "your-tenant-id"$ClientSecret = "your-client-secret" | ConvertTo-SecureString -AsPlainText -Force$Credential = New-Object System.Management.Automation.PSCredential($ClientId, $ClientSecret)Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $Credential# Connect using a certificate (more secure than client secret)Connect-MgGraph -TenantId $TenantId -ClientId $ClientId -CertificateThumbprint "ABC123..."
Application authentication grants the permissions assigned to the app registration in Azure Portal > App registrations > API permissions. These are application permissions, not delegated permissions.
Every Graph operation requires specific permission scopes. Request only the permissions your script actually needs.
# Find cmdlets and their required permissionsFind-MgGraphCommand -Command Get-MgUser | Select-Object -ExpandProperty Permissions# Find the command for a given API endpointFind-MgGraphCommand -Uri "/users" -Method GET
Graph API responses are paginated. The -All switch in Graph cmdlets handles pagination automatically.
# Use -All to retrieve all pages automatically$allUsers = Get-MgUser -All# For direct API calls, handle pagination manually$uri = "https://graph.microsoft.com/v1.0/users"$users = @()do { $response = Invoke-MgGraphRequest -Method GET -Uri $uri $users += $response.value $uri = $response.'@odata.nextLink'} while ($uri)Write-Host "Total users: $($users.Count)"
Avoid using -All against very large tenants without filtering first. Retrieving tens of thousands of objects without a -Filter parameter can be slow and may hit throttling limits. Use -Filter to narrow results where possible.