In recent posts, I have discussed methods to secure or limit programmatic access to Microsoft Graph PowerShell. Such as in my popular post ‘How to Secure Access To Microsoft Graph PowerShell‘ or in my book ‘Microsoft Graph PowerShell for Administrators‘. In both cases, the simplest method to limit someone from programmatically accessing Microsoft Graph PowerShell is to disable the Microsoft Graph Command Line Tools application in Microsoft Entra or require and restrict who it is assigned to. If you did this, when you next try to connect to Microsoft Graph using the Connect-MgGraph cmdlet, you will be presented with the following error:
In this post, I will show you how to circumvent these restrictions and access Microsoft Graph PowerShell without being assigned to an enterprise application.
Requirements
Performing these steps requires you to have 2 PowerShell modules installed:
- Microsoft.Graph (for interacting with resources using Microsoft Graph PowerShell)
- Az (To obtain an access token for the Microsoft Graph resource)
Both of these modules can be installed using the following commands:
Install-Module Microsoft.Graph -scope CurrentUser
Install-Module Az -scope CurrentUser
Obtain an access token
The first step is to obtain an access token from the first-party Microsoft Azure PowerShell application. As this application has the Directory.AccessAsUser.All permission scope consented to it, it can be used to access the directory with the equivalent permissions of the user requesting the token. For example, if the user is a User Administrator, they can perform nearly all user administration tasks programmatically, and so on.
Start by connecting to Azure PowerShell. I have opted to include the -Tenant parameter, making it easier to access subscriptions only to your tenant if you also have access to subscriptions for other tenants.
Connect-azAccount -Tenant %TenantIDhere%
The next step is to obtain your access token and ensure the correct resource types are available. In this instance, the resource is Microsoft Graph.
$token = Get-azAccessToken -ResourceTypeName MSGraph
Now that the token has been obtained, the Microsoft Graph PowerShell module will only accept it as a secure string. Use the below example to convert your token to a secure string and save it to a new variable.
$SecureToken = ConvertTo-SecureString $token.token -AsPlainText -Force
Understanding the token
The access token contains key information with authorises your access to services behind Microsoft Entra ID. At a glance, when you first receive your access token in the $token variable, extract it with $token.token, will just show a long string of random digits in your session.
These random digits are a base64 encoded JSON file, which contains claims making up the header, payload and signature of the access token.
Some key information included within your access token include:
- aud – The token audience, or in other words, the resource the token
- amr – The authentication type that the identity used to authenticate. This is likely to include pwd and mfa.
- app_displayname – The name of the application authenticated against.
- appid – The id of the application authenticated against.
- scp – The permission scopes that are exposed to the application that the client has requested.
- tid – the tenant id that the user is signing into. Also the owner of the application.
Many other properties are contained within the access token which can be evaluated by systems such as Conditional Access to verify access to the destination resource by the user is allowed. A detailed list of all properties can be found on the Access Token claims reference page.
Connect to Microsoft Graph PowerShell
Using the AccessToken parameter, connect to Microsoft Graph PowerShell using the following command.
Connect-MgGraph -AccessToken $SecureToken
Once connected, you should get a welcome message in your console.
Running the Get-MgContext command you can retrieve details about your current session. Notice that you are now connected to the Microsoft Azure PowerShell application with the Directory.AccessAsUser.All permission. This is important as not only does this mean that this permission is already consented to the application, but it was also requested upon connection by the Az PowerShell module without being explicitly defined, like you would expect when using Microsoft Graph PowerShell.
Get-MgContext
ClientId : 1950a258-227b-4e31-a9cf-717495945fc2
TenantId : xxx
Scopes : {AuditLog.Read.All, Directory.AccessAsUser.All, email, offline_access…}
AuthType : UserProvidedAccessToken
TokenCredentialType : UserProvidedAccessToken
CertificateThumbprint :
CertificateSubjectName :
SendCertificateChain : False
Account :
AppName : Microsoft Azure PowerShell
ContextScope : Process
Certificate :
PSHostVersion : 7.4.5
ManagedIdentityId :
ClientSecret :
Environment : Global