Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SMSAgentSoftware/664dc71350a6d926ea1ec7f41ad2ed77 to your computer and use it in GitHub Desktop.
Save SMSAgentSoftware/664dc71350a6d926ea1ec7f41ad2ed77 to your computer and use it in GitHub Desktop.
PowerShell code wrapper to interactively get an access token for Microsoft Graph using MSAL.Net via the Az.Accounts module
Function Get-MicrosoftGraphAccessToken {
[CmdletBinding()]
param (
[Parameter()]
[string]
$ClientId = "14d82eec-204b-4c2f-b7e8-296a70dab67e", # Microsoft Graph PowerShell, or your own app Id
[Parameter()]
[string]
$TenantId = "<YourTenantId>",
[Parameter()]
[string[]]
$Scopes = "https://graph.microsoft.com/.default",
[Parameter()]
[string]
$RedirectUri = "",
[Parameter()]
[switch]
$UseAzureIdentity
)
# Check for Az.Accounts module
$AzAccountsModule = Get-Module -Name Az.Accounts -ListAvailable
If ($null -eq $AzAccountsModule)
{
try
{
Install-Module -Name Az.Accounts -Force -AllowClobber -Scope CurrentUser -Repository PSGallery -ErrorAction Stop
}
catch
{
throw "Failed to install Az.Accounts module: $_"
}
}
# Import Az.Accounts module
try
{
Import-Module Az.Accounts -ErrorAction Stop
}
catch
{
throw $_
}
If ($UseAzureIdentity)
{
# For PS Core, it is necessary to load the required assemblies
If ($PSEdition -eq "Core")
{
# Find the location of the Azure.Common assembly
$LoadedAssemblies = [System.AppDomain]::CurrentDomain.GetAssemblies() | Select -ExpandProperty Location
$AzureCommon = $LoadedAssemblies |
Where-Object { $_ -match "\\Modules\\Az.Accounts\\" -and $_ -match "Microsoft.Azure.Common" }
$AzureCommonLocation = $AzureCommon.TrimEnd("Microsoft.Azure.Common.dll")
# Load the required assemblies
$dllsToLoad = @(
'Microsoft.IdentityModel.Abstractions.dll'
'Microsoft.Identity.Client.dll'
'Azure.Identity.dll'
'Azure.Core.dll'
'Microsoft.Identity.Client.Extensions.Msal.dll'
)
foreach ($dll in $dllsToLoad)
{
try
{
$dllLocation = Get-ChildItem -Path $AzureCommonLocation -Filter $dll -Recurse -File | Select -First 1 -ExpandProperty FullName
[void][System.Reflection.Assembly]::LoadFrom($dllLocation)
}
catch
{
throw $_
}
}
}
# Set the redirect Uri
If ($RedirectUri.Length -eq 0)
{
If ($PSEdition -eq "Core")
{
$RedirectUri = "http://localhost"
}
Else
{
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
}
}
# Set the credential options
$ibcOptions = [Azure.Identity.InteractiveBrowserCredentialOptions]::new()
$ibcOptions.ClientId = $ClientId
$ibcOptions.TenantId = $TenantId
$ibcOptions.RedirectUri = $RedirectUri
$ibcOptions.TokenCachePersistenceOptions = [Azure.Identity.TokenCachePersistenceOptions]::new()
if ($null -ne $script:authenticationRecord1976)
{
$ibcOptions.AuthenticationRecord = $authenticationRecord1976
}
# Acquire a token
$ibc = [Azure.Identity.InteractiveBrowserCredential]::new($ibcOptions)
$requestContext = [Azure.Core.TokenRequestContext]::new($Scopes)
$cancellationTokenSource = [System.Threading.CancellationTokenSource]::new([timespan]::FromSeconds(90)) # Automatic cancellation after 90 seconds
if ($null -eq $script:authenticationRecord1976)
{
try
{
$script:authenticationRecord1976 = $ibc.AuthenticateAsync($requestContext,$cancellationTokenSource.Token).GetAwaiter().GetResult()
}
catch
{
throw $_
}
}
return $ibc.GetTokenAsync($requestContext,$cancellationTokenSource.Token).GetAwaiter().GetResult().Token
}
else
{
# For PS Core, it is necessary to load the required assemblies
If ($PSEdition -eq "Core")
{
# Find the location of the Azure.Common assembly
$LoadedAssemblies = [System.AppDomain]::CurrentDomain.GetAssemblies() | Select -ExpandProperty Location
$AzureCommon = $LoadedAssemblies |
Where-Object { $_ -match "\\Modules\\Az.Accounts\\" -and $_ -match "Microsoft.Azure.Common" }
$AzureCommonLocation = $AzureCommon.TrimEnd("Microsoft.Azure.Common.dll")
# Load the required assemblies
$dllsToLoad = @(
'Microsoft.IdentityModel.Abstractions.dll'
'Microsoft.Identity.Client.dll'
'Microsoft.Identity.Client.Extensions.Msal.dll'
)
foreach ($dll in $dllsToLoad)
{
try
{
$dllLocation = Get-ChildItem -Path $AzureCommonLocation -Filter $dll -Recurse -File | Select -First 1 -ExpandProperty FullName
[void][System.Reflection.Assembly]::LoadFrom($dllLocation)
}
catch
{
throw $_
}
}
}
# Set the redirect Uri
If ($RedirectUri.Length -eq 0)
{
If ($PSEdition -eq "Core")
{
$RedirectUri = "http://localhost"
}
Else
{
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
}
}
if ($null -eq $script:publicClientApp1976)
{
$script:publicClientApp1976 = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientId).WithRedirectUri($RedirectUri).WithTenantId($TenantId).Build()
}
# Alternate code to create / register a token cache on disk instead of in-memory cache
#$cacheFilePath = [System.IO.Path]::Combine([Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper]::UserRootDirectory, "msal.cache")
#$cacheFileName = [System.IO.Path]::GetFileName($cacheFilePath)
#$cacheDir = [System.IO.Path]::GetDirectoryName($cacheFilePath)
#$storageProperties = [Microsoft.Identity.Client.Extensions.Msal.StorageCreationPropertiesBuilder]::new($cacheFileName,$cacheDir,$ClientId).Build()
#$cacheHelper = [Microsoft.Identity.Client.Extensions.Msal.MsalCacheHelper]::CreateAsync($storageProperties).GetAwaiter().GetResult()
#$cacheHelper.RegisterCache($publicClientApp.UserTokenCache)
# Acquire a token
$cancellationTokenSource = [System.Threading.CancellationTokenSource]::new([timespan]::FromSeconds(90)) # Automatic cancellation after 90 seconds
$account = $publicClientApp1976.GetAccountsAsync().GetAwaiter().GetResult() | Select -First 1
if ($account)
{
# Check the token cache first
try
{
$token = $publicClientApp1976.AcquireTokenSilent($Scopes,$account).ExecuteAsync($cancellationTokenSource.Token).GetAwaiter().GetResult().AccessToken
}
catch
{
$token = $publicClientApp1976.AcquireTokenInteractive($Scopes).ExecuteAsync($cancellationTokenSource.Token).GetAwaiter().GetResult().AccessToken
}
}
else
{
$token = $publicClientApp1976.AcquireTokenInteractive($Scopes).ExecuteAsync($cancellationTokenSource.Token).GetAwaiter().GetResult().AccessToken
}
return $token
}
}
# Examples
$token = Get-MicrosoftGraphAccessToken
$token = Get-MicrosoftGraphAccessToken -UseAzureIdentity
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment