How to Use Microsoft Graph API with PowerShell on Windows Server 2025

The Microsoft Graph API is the unified REST endpoint that gives you programmatic access to the entire Microsoft 365 ecosystem — Azure Active Directory (now Microsoft Entra ID), Exchange Online, SharePoint, Teams, Intune, and more — all through a single, consistent surface. On Windows Server 2025, combining the Microsoft Graph PowerShell SDK with modern authentication workflows unlocks powerful automation capabilities that go far beyond what legacy MSOL or AzureAD modules could achieve. Whether you need to bulk-provision users from an HR feed, assign licenses at scale, query enrolled devices, or enumerate registered applications, Graph PowerShell gives you a structured, permission-aware way to interact with your entire Microsoft tenant. This guide walks through installing the SDK, authenticating with different credential flows, exploring the key cmdlets, and building real-world automation scripts.

Prerequisites

  • Windows Server 2025 with PowerShell 5.1 or PowerShell 7.x (recommended)
  • An active Microsoft 365 / Azure tenant
  • An account with sufficient permissions (Global Admin or scoped roles such as User Administrator)
  • Internet access from the server to graph.microsoft.com and login.microsoftonline.com
  • For app-only auth: an Entra ID App Registration with a client secret or certificate
  • PowerShell execution policy set to RemoteSigned or higher

Step 1 — Install the Microsoft Graph PowerShell SDK

The Microsoft Graph PowerShell SDK is published to the PowerShell Gallery as a modular suite of sub-modules grouped under a meta-module. Installing the full suite gives you access to every Graph endpoint, while installing individual service modules keeps your environment lean.

# Set execution policy if not already done
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Trust the PowerShell Gallery (required on fresh Windows Server 2025 installs)
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

# Install the full Microsoft Graph meta-module (includes all service modules)
Install-Module Microsoft.Graph -Scope AllUsers -Repository PSGallery -Force

# Verify installation
Get-Module -ListAvailable Microsoft.Graph* | Select-Object Name, Version | Sort-Object Name

If you only need identity and user management, you can install just the sub-modules you need to reduce disk footprint and import times:

# Minimal install for user/group/device management
Install-Module Microsoft.Graph.Authentication -Scope AllUsers -Force
Install-Module Microsoft.Graph.Users -Scope AllUsers -Force
Install-Module Microsoft.Graph.Groups -Scope AllUsers -Force
Install-Module Microsoft.Graph.Devices.CorporateManagement -Scope AllUsers -Force
Install-Module Microsoft.Graph.Applications -Scope AllUsers -Force

Step 2 — Authenticating with Microsoft Graph

The Graph SDK supports several authentication patterns. For interactive scripts running under a user context, delegated authentication with Connect-MgGraph is simplest. For unattended server automation, app-only (application) authentication using a client secret or certificate is required.

Delegated Authentication (Interactive)

# Interactive browser-based login with specific permission scopes
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All", "Directory.Read.All"

# For headless server sessions — use device code flow
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All" -UseDeviceAuthentication
# Output: To sign in, use a web browser to open https://microsoft.com/devicelogin and enter code ABCD1234

App-Only Authentication with Client Secret

# Define tenant and application details (store secrets in a vault, not plain text)
$TenantId     = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ClientId     = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
$ClientSecret = ConvertTo-SecureString "YourClientSecretHere" -AsPlainText -Force

$Credential = [System.Management.Automation.PSCredential]::new($ClientId, $ClientSecret)

Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $Credential

App-Only Authentication with Certificate (Recommended for Production)

# Generate a self-signed certificate (or use your PKI-issued cert)
$Cert = New-SelfSignedCertificate `
    -Subject "CN=GraphAutomation" `
    -CertStoreLocation "Cert:LocalMachineMy" `
    -KeyExportPolicy Exportable `
    -KeySpec Signature `
    -KeyLength 2048 `
    -HashAlgorithm SHA256 `
    -NotAfter (Get-Date).AddYears(2)

# Export the public key (.cer) to upload to Entra ID App Registration
Export-Certificate -Cert $Cert -FilePath "C:ScriptsGraphAutomation.cer"

# Connect using the certificate thumbprint
Connect-MgGraph -TenantId $TenantId -ClientId $ClientId -CertificateThumbprint $Cert.Thumbprint

# Confirm connection context
Get-MgContext

Step 3 — Working with Users via Microsoft Graph

Once connected, the Microsoft.Graph.Users module provides cmdlets for reading, creating, updating, and disabling user accounts. All cmdlets follow a consistent verb-noun pattern mapped directly to the underlying Graph REST resources.

# List all users (returns first page — 100 by default)
Get-MgUser -All | Select-Object DisplayName, UserPrincipalName, AccountEnabled, Id

# Get a specific user by UPN
$User = Get-MgUser -UserId "[email protected]"

# Get users with specific properties (Graph uses -Select to limit returned fields)
Get-MgUser -All -Select "DisplayName,UserPrincipalName,JobTitle,Department,City" |
    Select-Object DisplayName, UserPrincipalName, JobTitle, Department

# Create a new user
$PasswordProfile = @{
    Password                      = "TempP@ssw0rd2025!"
    ForceChangePasswordNextSignIn = $true
}

New-MgUser `
    -DisplayName "Jane Smith" `
    -UserPrincipalName "[email protected]" `
    -MailNickname "jsmith" `
    -AccountEnabled $true `
    -PasswordProfile $PasswordProfile `
    -UsageLocation "US" `
    -JobTitle "Systems Engineer" `
    -Department "IT"

# Update a user's attributes
Update-MgUser -UserId "[email protected]" -JobTitle "Senior Systems Engineer" -OfficeLocation "Building A"

# Disable a user account
Update-MgUser -UserId "[email protected]" -AccountEnabled $false

# Delete a user (moves to deleted items for 30-day recovery window)
Remove-MgUser -UserId "[email protected]"

Step 4 — Working with Groups, Devices, and Applications

# List all groups
Get-MgGroup -All | Select-Object DisplayName, GroupTypes, MailEnabled, SecurityEnabled

# Create a new security group
New-MgGroup `
    -DisplayName "WS2025 Admins" `
    -Description "Windows Server 2025 Administrators" `
    -MailNickname "ws2025admins" `
    -SecurityEnabled $true `
    -MailEnabled $false

# Add a user to a group
$Group  = Get-MgGroup -Filter "DisplayName eq 'WS2025 Admins'"
$Member = Get-MgUser  -UserId "[email protected]"

New-MgGroupMember -GroupId $Group.Id -DirectoryObjectId $Member.Id

# List all devices registered in Entra ID
Get-MgDevice -All | Select-Object DisplayName, OperatingSystem, OperatingSystemVersion, TrustType

# List registered Entra ID applications
Get-MgApplication -All | Select-Object DisplayName, AppId, SignInAudience

Step 5 — Using the Microsoft Graph Beta Module

Many newer or preview features are only available on the /beta endpoint. The SDK ships a parallel Microsoft.Graph.Beta set of modules that mirror the stable ones but target the beta endpoint. You can use both in the same session.

Install-Module Microsoft.Graph.Beta -Scope AllUsers -Force

# Import the beta users module
Import-Module Microsoft.Graph.Beta.Users

# Beta cmdlets use the same Connect-MgGraph session — no separate auth needed
# Example: access properties only available in beta (e.g., signInActivity)
Get-MgBetaUser -All -Select "DisplayName,UserPrincipalName,SignInActivity" |
    Select-Object DisplayName, UserPrincipalName,
        @{N="LastSignIn"; E={ $_.SignInActivity.LastSignInDateTime }} |
    Sort-Object LastSignIn

Step 6 — Building Automation: Bulk User Creation from CSV

A common real-world task is bulk-creating users from an HR system export. The following script reads a CSV, creates each user, and assigns a Microsoft 365 license by SKU ID.

# CSV format: DisplayName,GivenName,Surname,UPN,Department,JobTitle,UsageLocation
$Users = Import-Csv -Path "C:Scriptsnew_users.csv"

# Microsoft 365 E3 SKU ID (get yours with Get-MgSubscribedSku)
$LicenseSkuId = "05e9a617-0261-4cee-bb44-138d3ef5d965"

foreach ($User in $Users) {
    $PasswordProfile = @{
        Password                      = "Welcome2025!"
        ForceChangePasswordNextSignIn = $true
    }

    try {
        $NewUser = New-MgUser `
            -DisplayName    $User.DisplayName `
            -GivenName      $User.GivenName `
            -Surname        $User.Surname `
            -UserPrincipalName $User.UPN `
            -MailNickname   ($User.UPN -split "@")[0] `
            -AccountEnabled $true `
            -PasswordProfile $PasswordProfile `
            -UsageLocation  $User.UsageLocation `
            -Department     $User.Department `
            -JobTitle       $User.JobTitle

        Write-Host "Created user: $($User.UPN)" -ForegroundColor Green

        # Assign license
        $License = @{
            AddLicenses    = @(@{ SkuId = $LicenseSkuId })
            RemoveLicenses = @()
        }
        Set-MgUserLicense -UserId $NewUser.Id -BodyParameter $License
        Write-Host "  License assigned to $($User.UPN)" -ForegroundColor Cyan
    }
    catch {
        Write-Warning "Failed to create $($User.UPN): $_"
    }
}

Step 7 — Exploring Graph with Microsoft Graph Explorer

Before writing PowerShell automation, use the Microsoft Graph Explorer at https://developer.microsoft.com/en-us/graph/graph-explorer to discover API endpoints interactively. Sign in with your admin account, select the HTTP method and endpoint, and inspect the raw JSON response. The Explorer displays the required permissions for each call, which maps directly to the -Scopes you pass to Connect-MgGraph. When you find an endpoint not yet wrapped by an SDK cmdlet, you can call it directly with Invoke-MgGraphRequest:

# Call any Graph endpoint directly — useful for beta or uncommon resources
$Response = Invoke-MgGraphRequest -Method GET `
    -Uri "https://graph.microsoft.com/v1.0/reports/getMailboxUsageDetail(period='D7')" `
    -OutputFilePath "C:ReportsMailboxUsage.csv"

# POST a custom Graph request body
$Body = @{
    displayName = "Automation Test Group"
    mailEnabled = $false
    securityEnabled = $true
    mailNickname = "automationtestgrp"
} | ConvertTo-Json

Invoke-MgGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/groups" -Body $Body -ContentType "application/json"

Conclusion

The Microsoft Graph PowerShell SDK transforms Windows Server 2025 into a capable automation platform for the entire Microsoft 365 and Entra ID ecosystem. By mastering the three authentication patterns — interactive delegated, device code, and certificate-based app-only — and combining them with the rich library of Graph cmdlets for users, groups, devices, and applications, you can replace dozens of legacy management scripts with a single, consistent toolchain. The Graph Explorer accelerates discovery of new APIs, and Invoke-MgGraphRequest ensures you are never limited by SDK coverage gaps. As Microsoft continues expanding Graph coverage, investing in this skill set pays dividends across identity, compliance, endpoint management, and reporting automation.