Leveraging your API to PowerShell Graph API


VPN offers!

1. NordVPN

2. Surfshark

3. ExpressVPN

If you’re a developer and want to connect your PowerShell scripts with the Microsoft Graph API, then read on. This article will cover how to retrieve information from graphs using PowerShell in an easy-to-follow manner that can be applied across many different industries or tasks.

The “microsoft graph api” is a Microsoft API that allows users to use PowerShell scripts to access information from the Graph.

Leveraging your API to PowerShell Graph API

The Microsoft Graph API is a REST API service that lets you read, edit, and administer practically every element of Azure AD and Office 365 from a single endpoint. Learn how to convert your API to a PowerShell Graph API in this post.


If you want to follow along with this post with me, make sure you first complete the following requirements:

  • Windows PowerShell 5.1 is installed (this is the version I tested with). Other versions may or may not function; however, this cannot be assured.)
  • A tenant in Azure
  • Authenticated to Azure using a subscription account that has global admin or app registration rights and a global admin to approve your app registration requests.

Creating a Microsoft Graph API Application Identity

To use the Microsoft Graph API, you must first create an account and get an OAuth token. This is generally accomplished via the Azure Portal’s creation of an application identity. The Azure interface allows you to establish an application identity. To do so, follow these steps:

  • Navigate to Azure Active Directory in the Azure Portal.
  • Click the New registration button under App Registrations in the Manage menu on the left.

Before building the PowerShell Graph API, you must first authenticate.Before building the PowerShell Graph API, you must first authenticate.

  • Click Register after giving your application a name.
  • For future usage, copy the Application Id guid.

Creating an App Registration in Azure PortalCreating a new application

Secrets for the Microsoft Graph API

AppId/Secret and Certificate-based authentication are the two basic ways for logging in to the Graph API. When using PowerShell to connect to the graph API, you must first login.

Let’s look at how to use both approaches to authenticate.


An application ID/secret is similar to a username/password combination. Instead of a username, the application id is a GUID, and the password is merely a randomized string.

To create a secret – click on Certificates & secrets in the left menu and press on New client secret.

Creating an application client secret in AzureMaking a client-only secret

Enter a description for the secret and choose an expiration date. It’s now only a question of requesting permission to access the information you need.


It is possible to generate a self-signed certificate and submit the public key to Azure. This is the more secure and recommended method of authentication.

To begin, you’ll need to create a self-signed certificate. Fortunately, PowerShell made this simple.

# Your name as a renter (can something more descriptive as well) # Where to export the certificate without the private key $TenantName = “contoso.onmicrosoft.com” $CerOutputPath = “C:TempPowerShellGraphCert.cer” $CerOutputPath = “C:TempPowerShellGraphCert.cer” # Where do you want it to be stored in the certificate store? $StoreLocation = “Cert:CurrentUserMy” $StoreLocation = “Cert:CurrentUserMy” # The new certificate’s expiration date $ExpirationDate = $ExpirationDate = $ExpirationDate = (Get-Date). AddYears(2) # Splat to make it easier to read @CreateCertificateSplat = $CreateCertificateSplat DnsName = $TenantName CertStoreLocation = $StoreLocation NotAfter = $ExpirationDate FriendlyName = “AzureApp” “Exportable” is the value of KeyExportPolicy. “Signature” is the keyspec. HashAlgorithm = “SHA256” Provider = “Microsoft Enhanced RSA and AES Cryptographic Provider” # Produce a certificate @CreateCertificateSplat $Certificate = New-SelfSignedCertificate # Get certificate path $CertificatePath = Join-Path -Path; $CertificatePath = Join-Path -Path; $Certificat $Certificate.Thumbprint $StoreLocation -ChildPath # Remove the private key from the certificate and export it. -Certificate -Certificate -Certificate -Certificate -C $CertificatePath -FilePath $CerOutputPath | Out-Null $CertificatePath -FilePath $CerOutputPath

Now, upload the self-signed Certificate that you exported to $CerOutputPath to your Azure Application by clicking on Certificates & secrets in the left menu and pressing on Upload Certificate.

A certificate may be uploaded. to Azure ApplicationA certificate may be uploaded.

The application’s permissions are being added.

It’s critical to provide your app the right rights, not just for its operation but also for its security. The documentation contains information on this and (nearly) everything else in the Microsoft Graph API.

I’m going to collect all of my tenant’s security events once I have this set up. I need SecurityEvents to be able to accomplish that. Read. All of this is a bare minimum of authorization. This allows me to collect and act on information about Impossible Travel incidents, people connecting using VPN/TOR, and other topics.

The SecurityEvents must be added. Read. To add a permission to your application, go to API Permissions and then Add Permission. This will show you not just the Graph API, but also a plethora of other Azure apps. Once you understand how to connect to the Microsoft Graph API, most of these apps are simple to connect to.

Click on Microsoft Graph > Application Permissions > Security Events and check the SecurityEvents.Read.All. After that press the Add Permission button.

Did you notice that the Admin consent needed column on that permit was set to Yes? This signifies that the permission must be approved by a tenant admin before it can be included to the application.

Application Permission needing admin consentPermission approved by the tenant’s administrator

If you’re a global admin, click Grant admin permission for or have a Global Admin approve it. A key element of OAuth authentication is asking for permission from the user rather than an admin just establishing read/write access. However, in Microsoft Graph, this enables us to circumvent it for the vast majority of rights.

You’ve most likely seen this on Facebook or Google: “Are you willing to provide application X access to your profile?”

Granting application permissionConsent from the administrator

Now that you’re ready, let’s log in and grab some data!

Obtain an Access Token (Application Id and Secret)

We’ll need to send a request to a Microsoft Graph OAuth endpoint to receive an access token for this. We must also provide the following information in the body of the request:

  • client id — url encoded version of your application ID
  • client secret — url encoded secret of your application
  • scope – A url that specifies what you wish to access in url-encoded form.
  • grant type – The type of authentication you’re using.

The URL for the endpoint is https://login.microsoftonline.com/<tenantname>/oauth2/v2.0/token. You can request an access token with PowerShell and the Graph API using the code snippet below.

# Define AppId, secret and scope, your tenant name and endpoint URL $AppId = ‘2d10909e-0396-49f2-ba2f-854b77c1e45b’ $AppSecret = ‘abcdefghijklmnopqrstuv12345’ $Scope = “https://graph.microsoft.com/.default” $TenantName = “contoso.onmicrosoft.com” $Url = “https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token” # Add System.Web for urlencode Add-Type -AssemblyName System.Web # Create body $Body = @{ client_id = $AppId client_secret = $AppSecret scope = $Scope grant_type = ‘client_credentials’ } # Splat the parameters for Invoke-Restmethod for cleaner code $PostSplat = @{ ContentType = ‘application/x-www-form-urlencoded’ Method = ‘POST’ # Create string by joining bodylist with ‘&’ Body = $Body Uri = $Url } # Request the token! $Request = Invoke-RestMethod @PostSplat

Obtain an Access Token (Using a Certificate)

Using a certificate to authenticate to the Microsoft Graph API differs from the standard AppId/Secret route. To get an access token using a certificate, follow these steps:

  1. Make a JWT (Java Web Token) header.
  2. Make a payload in JWT.
  3. Sign the JWT header AND payload using the self-signed certificate you produced earlier. This generates a self-created access token that may be used to request a Microsoft Graph access token.
  4. Make a request body that includes the following:
  • client_id=<application id>
  • client_assertion=<the JWT>
  • client assertion type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
  • scope=<URLEncoded scope>
  • grant type=client credentials
  1. Make a post request with body to the oauth endpoint with Authorization=<JWT> in it’s header.

The steps to implement this weren’t evident in Microsoft’s instructions, but here’s the PowerShell script:

$TenantName = “<your tenant name>.onmicrosoft.com” $AppId = “<your application id” $Certificate = Get-Item Cert:CurrentUserMy<self signed and uploaded cert thumbprint> $Scope = “https://graph.microsoft.com/.default” # Create base64 hash of Certificate $CertificateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash()) # Create JWT timestamp for expiration $StartDate = (Get-Date “1970-01-01T00:00:00Z” ).ToUniversalTime() $JWTExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End (Get-Date).ToUniversalTime().AddMinutes(2)).TotalSeconds $JWTExpiration = [math]::Round($JWTExpirationTimeSpan,0) # Create JWT validity start timestamp $NotBeforeExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End ((Get-Date).ToUniversalTime())).TotalSeconds $NotBefore = [math]::Round($NotBeforeExpirationTimeSpan,0) # Create JWT header $JWTHeader = @{ alg = “RS256” typ = “JWT” # Use the CertificateBase64Hash and replace/strip to match web encoding of base64 x5t = $CertificateBase64Hash -replace ‘+’,’-‘ -replace ‘/’,’_’ -replace ‘=’ } # Create JWT payload $JWTPayLoad = @{ # What endpoint is allowed to use this JWT aud = “https://login.microsoftonline.com/$TenantName/oauth2/token” # Expiration timestamp exp = $JWTExpiration # Issuer = your application iss = $AppId # JWT ID: random guid jti = [guid]::NewGuid() # Not to be used before nbf = $NotBefore # JWT Subject sub = $AppId } # Convert header and payload to base64 $JWTHeaderToByte = [System.Text.Encoding]::UTF8.GetBytes(($JWTHeader | ConvertTo-Json)) $EncodedHeader = [System.Convert]::ToBase64String($JWTHeaderToByte) $JWTPayLoadToByte = [System.Text.Encoding]::UTF8.GetBytes(($JWTPayload | ConvertTo-Json)) $EncodedPayload = [System.Convert]::ToBase64String($JWTPayLoadToByte) # Join header and Payload with “.” to create a valid (unsigned) JWT $JWT = $EncodedHeader + “.” + $EncodedPayload # Get the private key object of your Certificate $PrivateKey = $Certificate.PrivateKey # Define RSA signature and hashing algorithm $RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1 $HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256 # Create a signature of the JWT $Signature = [Convert]::ToBase64String( $PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($JWT),$HashAlgorithm,$RSAPadding) ) -replace ‘+’,’-‘ -replace ‘/’,’_’ -replace ‘=’ # Join the signature to the JWT with “.” $JWT = $JWT + “.” + $Signature # Create a hash with body parameters $Body = @{ client_id = $AppId client_assertion = $JWT client_assertion_type = “urn:ietf:params:oauth:client-assertion-type:jwt-bearer” scope = $Scope grant_type = “client_credentials” } $Url = “https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token” # Use the self-generated JWT as Authorization $Header = @{ Authorization = “Bearer $JWT” } # Splat the parameters for Invoke-Restmethod for cleaner code $PostSplat = @{ ContentType = ‘application/x-www-form-urlencoded’ Method = ‘POST’ Body = $Body Uri = $Url Headers = $Header } $Request = Invoke-RestMethod @PostSplat

The Request Access Token Output: An Overview

You should see an object with four attributes after you’ve gotten an access token, either through the application ID/secret or via certificate.

  • token type — Describes the type of token.
  • expires in – The length of time the access token is valid in seconds.
  • ext expires in — Similar to expires in, but with the added benefit of resilience in the event of a token service failure.
  • What we came for: access token

After that, you’ll build a header with token type and access token and use PowerShell to make queries to the Microsoft Graph API.

Using the Microsoft Graph API to Make Requests

Now you may start making API queries.

Using our example, you’ll need the URL for displaying security warnings first. Keep in mind that the Microsoft Graph API documentation might help you figure out what you’ll need.

In this case, you need a header with Authorization=Bearer <access_token> and a GET request towards the Graph API Alerts endpoint. Here’s how to do that with PowerShell.

# Make a header @ Authorization = “$($Request.token type) $($Request.access token)” $Header = @ Authorization = “$($Request.token type) $($Request.access token)” $Uri = “https://graph.microsoft.com/v1.0/security/alerts” $Uri = “https://graph.microsoft.com/v1.0/security/alerts” # Get a list of all security warnings. Invoke-RestMethod -Uri $SecurityAlertsRequest -Headers $Uri $Header -Method Get -ContentType “application/json” $SecurityAlerts = $SecurityAlertsRequest.Value $SecurityAlerts = $SecurityAlertsRequest.Value $SecurityAlertsRequest.Value $SecurityAlertsRequest.Valu

If the $SecurityAlerts variable has any security warnings, it should now look like this:

choose event from $SecurityAlerts Date/Time/Title of the event title (DateTime) —————————————————————————————————— 2019-08-05T17:59:47.6271981Z Unusual travel 2019-08-05T08:23:01.7325708Z 2019-08-05T08:23:55.5000456Z (anonymous IP address) 2019-08-04T22:06:51.063797Z anonymous IP address 2019-08-04T21:56:10.981437Z anonymous IP address 2019-08-08T09:30:00Z anonymous IP address Forwarding/redirect rule creation 2019-07-19T13:30:00Z Start or export an eDiscovery search 2019-07-19T08:00:00Z Start or export an eDiscovery search

The following is a JSON representation of a single security alert:

“id”: “censored”, “azureTenantId”: “censored”, “azureSubscriptionId”: “censored”, “riskScore”: null, “tags”: [], “activityGroupName”: null, “assignedTo”: null, “riskScore”: null, “riskScore”: null, “riskScore”: null, “riskScore”: null, “risk “AnonymousLogin” is the category, “closedDateTime” is null. “comments”: “null”, “confidence”: “null”, “confidence”: “null”, “confidence”: “nul “createdDateTime”: “2019-08-08T09:46:59.65722253Z”, “description”: “Sign-in from an anonymous IP address (e.g. Tor browser, anonymizer VPNs)”, “createdDateTime”: “2019-08-08T09:46:59.65722253Z”, “createdDateTime”: “2019-08-08T09:46:59.65722253Z”, “created “detectionIds”: [], “eventDateTime”: “2019-08-08T09:46:59.65722253Z”, “feedback”: null, “lastModifiedDateTime”: “2019-08-08T09:54:30.7256251Z”, “recommendedActions”: [], “severity”: “medium”, “sourceMaterials”: [], “status”: “newAler “provider”: “IPC”, “providerVersion”: null, “subProvider”: null, “vendor”: “Microsoft”, “providerVersion”: null, “subProvider”: null, “vendor”: “Microsoft” “cloudAppStates”: [], “fileStates”: [], “hostStates”: [], “historyStates”: [], “malwareStates”: [], “networkConnections”: [], “processes”: [], “registryKeyStates”: [], “triggers”: [], “userStates”: [

API Output Paging: Understanding and Managing

The number of objects returned by the Microsoft Graph API is limited per function. This is a function-specific limit, so let’s pretend it’s 1000 items. That implies your request may only include a maximum of 1000 items.

When this limit is reached, the remaining items will be sent through paging. This is accomplished by include the @odata.nextLink attribute in the response to your request. @odata.nextLink is a URL to access the next page of your request.

By utilizing a loop and checking for this property, you may read through all of the items:

$Uri = “https://graph.microsoft.com/v1.0/auditLogs/signIns” $Uri = “https://graph.microsoft.com/v1.0/auditLogs/signIns” $Uri = “https://graph.microsoft.com/v1.0/audit Invoke-RestMethod -Uri $AuditLogRequest -Headers $Uri -Method Get -ContentType “application/json” $Header -Method Get -ContentType “application/json” @ $AuditLogs $AuditLogs $AuditLogs $Audit () $AuditLogs+= while($AuditLogRequest.’@odata.nextLink’ -ne) $AuditLogRequest.value $null) Invoke-RestMethod -Uri $AuditLogRequest -Headers $AuditLogRequest.’@odata.nextLink’ -Method Get -ContentType “application/json” $Header -Method Get -ContentType “application/json”


It’s really simple to obtain data from the Graph API after you’ve learned how to login with it. It’s a strong tool that gets much less usage than it deserves.

Fortunately, there are numerous modules available to use the Microsoft Graph API, but you may need to design your own to fulfill your specific requirements. You should be well on your way if you use the abilities you’ve gained in this article.

I posted an in-depth essay on my blog on restricting guest access in Office 365, and I recommend that you read it.

The “powershell microsoft.graph module” is a PowerShell module that allows users to access Microsoft Graph API. The “powershell microsoft.graph module” is quite useful for those who want to leverage their API to PowerShell Graph API.

Frequently Asked Questions

How does Microsoft Graph API connect to PowerShell?

A: Microsoft Graph API is an interface that can be used to connect with a Microsoft SQL Server database and allows you to run your queries against it. You would use PowerShell, which is a command-line interface for administering Windows computers and applications, as the application that provides data from the database.

How do you connect a graph to API?

A: In order to connect a graph to API, you would need some kind of an endpoint or URL. You can provide it as the first parameter in your request by using https://graph.api.ai/v1/

Is graph API deprecated?

A: Graph API is not deprecated, but it may be removed in the future.

Related Tags

  • powershell graph api user authentication
  • invoke-webrequest graph api
  • powershell graph api invoke-restmethod
  • powershell graph api delegated permissions
  • connect-mggraph