Connect to Microsoft Graph API with PowerShell

Today, I’m going to walk you through how to connect to Microsoft Graph using PowerShell. We will cover the differences between Delegated Access and App-Only Access, and various methods for each type of access. Additionally, we will delve into the details of each script to explain how they work and their objectives. All these scripts are available in my GitHub repository: Microsoft Graph Authentication Scripts.


Differences between Delegated Access and App-Only Access

Delegated Access: This type of access is used when a user is involved in the authentication process, granting permissions to the application on behalf of the user. This method requires user consent and operates under the permissions of the signed-in user. It’s commonly used in scenarios where the application needs to perform actions on behalf of the user, such as reading emails, accessing user profile information, or managing group memberships.

App-Only Access: Designed for background services or daemon applications that do not require a user to be present. This method grants the application permissions directly and allows it to operate with higher privileges. It’s ideal for scenarios where the application needs to perform administrative tasks or access data across multiple users, such as automating user management or processing data in batches.


Delegated Access

Interactive Authentication

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# Define the required scopes
$scopes = @(
    "User.Read.All",
    "Group.ReadWrite.All"
)

# Connect to Microsoft Graph using interactive authentication
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -Scopes $scopes -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script installs the necessary PowerShell module and defines the scopes required for accessing user and group information. It then attempts to authenticate interactively, prompting the user to log in. This method is useful for running scripts that need to operate within the user’s context and requires explicit user consent.


Device Code Flow

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# Define the required scopes
$scopes = @(
    "User.Read.All",
    "Group.ReadWrite.All"
)

# Connect to Microsoft Graph using device authentication
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -Scopes $scopes -UseDeviceCode -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script is similar to the interactive authentication but uses the device code flow. It provides a code that the user must enter on a separate device, making it suitable for devices with limited input capabilities, such as IoT devices or restricted environments.


Using an Access Token

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# App Registration details
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientsecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Set the body for the OAuth request
$body = @{
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = $clientID
    Client_Secret = $clientsecret
}

# Connect to Microsoft Graph using access token
try {
    Write-Host "Authenticating to Microsoft Graph..."

    # Get the OAuth token
    $oauth = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $body
    $accessToken = $oauth.access_token | ConvertTo-SecureString -AsPlainText -Force

    # Connect to Microsoft Graph
    Connect-MgGraph -AccessToken $accessToken -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script is for scenarios where you already have an OAuth access token from another authentication flow or tool. It allows you to authenticate to Microsoft Graph using this token, avoiding the need for interactive login. This is useful for automation scripts where tokens are managed separately.


Using App Registration

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# App Registration details
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

# Connect to Microsoft Graph using app registration
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -ClientId $clientID -TenantId $tenantID -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script authenticates to Microsoft Graph using the client ID and tenant ID from an app registration. This method does not require user interaction and is suitable for background services where you need to authenticate without a user context.


App-Only Access

Using a Certificate Thumbprint

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# App Registration details
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$certificatePath = "Cert:\CurrentUser\My" # For current user
# OR
$certificatePath = "Cert:\LocalMachine\My" # For local machine

# Get certificate thumbprint
$certificateName = "Microsoft Graph Certificate"
$certificateThumbprint = Get-ChildItem -Path $certificatePath | Where-Object { $_.Subject -match $certificateName } | Select-Object -First 1 FriendlyName, Subject, Thumbprint

# Connect to Microsoft Graph using certificate thumbprint
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -ClientId $clientID -TenantId $tenantID -CertificateThumbprint $($certificateThumbprint.Thumbprint) -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script authenticates using a certificate identified by its thumbprint. It’s a secure method for authenticating without storing client secrets in your script, suitable for applications running in secure environments where certificates are managed centrally.


Using a Certificate Name

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# App Registration details
$tenantID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

$certificatePath = "Cert:\CurrentUser\My" # For current user
# OR
$certificatePath = "Cert:\LocalMachine\My" # For local machine

# Get certificate subject name
$certificateName = "Microsoft Graph Certificate"
$certificateSubject = Get-ChildItem -Path $certificatePath | Where-Object { $_.Subject -match $certificateName } | Select-Object -First 1 FriendlyName, Subject, Thumbprint

# Connect to Microsoft Graph using certificate subject name
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -ClientId $clientID -TenantId $tenantID -CertificateSubjectName $($certificateSubject.Subject) -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script is similar to the thumbprint method but identifies the certificate by its subject name. This is useful if you know the certificate’s subject name but not its thumbprint, allowing for flexibility in certificate management.


Using Certificate

# Install module Microsoft.Graph.Authentication
Install-Module -Name Microsoft.Graph.Authentication

# Define certificate thumbprint
$thumbprint = "XXXXXXXX"

$certificatePath = "Cert:\CurrentUser\My\$($thumbprint)" # For current user
# OR
$certificatePath = "Cert:\LocalMachine\My\$($thumbprint)" # For local machine

# Get certificate
$certificate = Get-Item -Path $certificatePath

# Connect to Microsoft Graph using certificate
try {
    Write-Host "Authenticating to Microsoft Graph..."
    Connect-MgGraph -ClientId $clientID -TenantId $tenantID -Certificate $certificate -NoWelcome | Out-Null
    Write-Host "Successfully authenticated to Microsoft Graph."
}
catch {
    Write-Error "Failed to authenticate to Microsoft Graph: $($_.Exception.Message)"
}

Explanation and Objective: This script directly uses a certificate stored on your machine. By specifying the certificate path, it securely connects to Microsoft Graph without the need for storing credentials in your script. This is particularly suitable for services that need high-security authentication methods.


Disconnecting from Microsoft Graph

To ensure that your connection to Microsoft Graph is properly terminated and resources are freed, you can use the following script block. This is especially important in environments where scripts run continuously or in automation pipelines to prevent resource leaks and ensure security :

CLEAN {
    if (Get-MgContext) {
        try {
            Disconnect-MgGraph
            Write-Host "Disconnected from Microsoft Graph"
        }
        catch {
            Write-Error "Failed to disconnect from Microsoft Graph : $($_.exception.message)"
        }
    }
}

Explanation and Objective: This script block checks if there is an active Microsoft Graph context using Get-MgContext. If a context is found, it attempts to disconnect from Microsoft Graph using Disconnect-MgGraph, ensuring a clean disconnection. The advantage of using a CLEAN block is that it allows you to disconnect from Microsoft Graph even if there is an unexpected error during execution or if you interrupt the script with CTRL+C. This functionality is available from PowerShell 7.3 and newer versions, so it will not work on earlier versions of PowerShell. Using this approach helps maintain the health of your scripts and services by preventing lingering connections and potential security risks.


These methods will help you connect to Microsoft Graph securely and efficiently, depending on your specific use case and requirements. By understanding the differences between Delegated Access and App-Only Access, and utilizing the appropriate authentication method, you can ensure that your applications and services are both robust and secure.

For more detailed steps and additional information, refer to the official Microsoft documentation: Microsoft Graph PowerShell Authentication Commands.

Leave a Comment