Public/Get-AccessToken.ps1
function Get-AccessToken { <# .SYNOPSIS Get or refresh an access token using either authorization code flow (interactive) or client credentials (secret), that can be used to authenticate and authorize against resources in Graph API. .DESCRIPTION Get or refresh an access token using either authorization code flow (interactive) or client credentials (secret), that can be used to authenticate and authorize against resources in Graph API. .PARAMETER TenantID Specify the tenant name or ID, e.g. tenant.onmicrosoft.com or <GUID>. .PARAMETER ClientID Application ID (Client ID) for an Azure AD service principal.Uses Microsoft Graph PowerShell by default.(14d82eec-204b-4c2f-b7e8-296a70dab67e) If you need to use the old legacy Microsoft Intune Powershell, use ClientID d1ddf0e4-d672-4dae-b554-9d5bdfd93547 .PARAMETER ClientSecret Specify the client secret for an Azure AD service principal. .PARAMETER ClientCertificate Specify the client certificate. .PARAMETER RedirectUri Specify the Redirect URI (also known as Reply URL) of the custom Azure AD service principal. .PARAMETER DeviceCode Specify delegated login using devicecode flow, you will be prompted to navigate to https://microsoft.com/devicelogin .PARAMETER Interactive Specify to force an interactive prompt for credentials. .PARAMETER Refresh Specify to refresh an existing access token. .PARAMETER ClearCache Specify to clear existing access token from the local cache. .PARAMETER Scopes Specify scopes to the access request, can be used for consent flow in interactive mode. Type: Array Example: $scopes = @('Device.Read.All','User.Read.All','DeviceManagementManagedDevices.Read.All') .PARAMETER AddConsistencyLevelEventualHeader Switch: Specify to add consistencylevel eventual to the authentication header. .NOTES Author: Nickolaj Andersen & Jan Ketil Skanke Contact: @NickolajA @JankeSkanke Created: 2021-04-08 Updated: 2023-12-06 Version history: 1.0.0 - (2021-04-08) Script created 1.0.1 - (2021-05-05) Added delegated login using devicecode flow 1.0.2 - (2023-12-05) Added scopes parameter, added MS Graph Application as default app. Use -ClientID parameter to specify other app, added AddConsistencyLevelEventualHeader switch #> [CmdletBinding(DefaultParameterSetName = "Interactive")] param( [parameter(Mandatory = $true, ParameterSetName = "Interactive", HelpMessage = "Specify the tenant name or ID, e.g. tenant.onmicrosoft.com or <GUID>.")] [parameter(Mandatory = $true, ParameterSetName = "ClientSecret")] [parameter(Mandatory = $true, ParameterSetName = "ClientCertificate")] [parameter(Mandatory = $true, ParameterSetName = "DeviceCode")] [ValidateNotNullOrEmpty()] [string]$TenantID, [parameter(Mandatory = $false, ParameterSetName = "Interactive", HelpMessage = "Application ID (Client ID) for an Azure AD service principal. Uses by default the 'Microsoft Intune PowerShell' service principal Application ID.")] [parameter(Mandatory = $true, ParameterSetName = "ClientSecret")] [parameter(Mandatory = $true, ParameterSetName = "ClientCertificate")] [parameter(Mandatory = $false, ParameterSetName = "DeviceCode")] [ValidateNotNullOrEmpty()] [string]$ClientID = "14d82eec-204b-4c2f-b7e8-296a70dab67e", [parameter(Mandatory = $false, ParameterSetName = "ClientSecret", HelpMessage = "Specify the client secret for an Azure AD service principal.")] [ValidateNotNullOrEmpty()] [string]$ClientSecret, [parameter(Mandatory = $false, HelpMessage = "Add scopes to the access request, can be used for consent flow in interactive mode.")] [array]$Scopes, [Parameter(Mandatory=$false, HelpMessage = "Add consistencylevel eventual to the authentication header.")] [switch]$AddConsistencyLevelEventualHeader, [parameter(Mandatory = $true, ParameterSetName = "ClientCertificate", HelpMessage = "Specify the client certificate.")] [ValidateNotNullOrEmpty()] [System.Security.Cryptography.X509Certificates.X509Certificate2]$ClientCertificate, [parameter(Mandatory = $false, ParameterSetName = "Interactive", HelpMessage = "Specify the Redirect URI (also known as Reply URL) of the custom Azure AD service principal.")] [parameter(Mandatory = $false, ParameterSetName = "ClientSecret")] [parameter(Mandatory = $false, ParameterSetName = "DeviceCode")] [ValidateNotNullOrEmpty()] [string]$RedirectUri = [string]::Empty, [parameter(Mandatory = $false, ParameterSetName = "Interactive", HelpMessage = "Specify to force an interactive prompt for credentials.")] [switch]$Interactive, [parameter(Mandatory = $true, ParameterSetName = "DeviceCode", HelpMessage = "Specify to do delegated login using devicecode flow, you will be prompted to navigate to https://microsoft.com/devicelogin")] [switch]$DeviceCode, [parameter(Mandatory = $false, ParameterSetName = "Interactive", HelpMessage = "Specify to refresh an existing access token.")] [parameter(Mandatory = $false, ParameterSetName = "ClientSecret")] [parameter(Mandatory = $false, ParameterSetName = "ClientCertificate")] [parameter(Mandatory = $false, ParameterSetName = "DeviceCode")] [switch]$Refresh, [parameter(Mandatory = $false, ParameterSetName = "Interactive", HelpMessage = "Specify to clear existing access token from the local cache.")] [parameter(Mandatory = $false, ParameterSetName = "ClientSecret")] [parameter(Mandatory = $false, ParameterSetName = "DeviceCode")] [switch]$ClearCache ) Begin { # Determine the correct RedirectUri (also known as Reply URL) to use with MSAL.PS if ($ClientID -like "d1ddf0e4-d672-4dae-b554-9d5bdfd93547") { $RedirectUri = "urn:ietf:wg:oauth:2.0:oob" } else { if (-not([string]::IsNullOrEmpty($ClientID))) { Write-Verbose -Message "Using custom Azure AD service principal specified with Application ID: $($ClientID)" # Adjust RedirectUri parameter input in case non was passed on command line if ([string]::IsNullOrEmpty($RedirectUri)) { $RedirectUri = "http://localhost" <#switch -Wildcard ($PSVersionTable["PSVersion"]) { "5.*" { $RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient" } "7.*" { $RedirectUri = "http://localhost" } }#> } } } Write-Verbose -Message "Using RedirectUri with value: $($RedirectUri)" # Convert client secret to secure string if ($PSCmdlet.ParameterSetName -eq "ClientSecret") { $ClientSecretSecure = $ClientSecret | ConvertTo-SecureString -AsPlainText -Force } # Set default error action preference configuration $ErrorActionPreference = "Stop" } Process { Write-Verbose -Message "Using authentication flow: $($PSCmdlet.ParameterSetName)" # Clear existing access token from local cache if ($PSBoundParameters["ClearCache"]) { Clear-MsalTokenCache } try { # Construct table with common parameter input for Get-MsalToken cmdlet $AccessTokenArguments = @{ "TenantId" = $TenantID "ClientId" = $ClientID "RedirectUri" = $RedirectUri "ErrorAction" = "Stop" } # Dynamically add parameter input for Get-MsalToken based on parameter set name switch ($PSCmdlet.ParameterSetName) { "Interactive" { if ($PSBoundParameters["Refresh"]) { $AccessTokenArguments.Add("ForceRefresh", $true) $AccessTokenArguments.Add("Silent", $true) } } "DeviceCode" { if ($PSBoundParameters["Refresh"]) { $AccessTokenArguments.Add("ForceRefresh", $true) } } "ClientSecret" { if ($PSBoundParameters["Refresh"]) { $AccessTokenArguments.Add("ForceRefresh", $true) } } "ClientCertificate" { if ($PSBoundParameters["Refresh"]) { $AccessTokenArguments.Add("ForceRefresh", $true) } } } # Dynamically add parameter input for Get-MsalToken based on command line input if ($PSBoundParameters["Interactive"]) { $AccessTokenArguments.Add("Interactive", $true) } if ($PSBoundParameters["DeviceCode"]) { if (-not($PSBoundParameters["Refresh"])){ $AccessTokenArguments.Add("DeviceCode", $true) } } if ($PSBoundParameters["ClientSecret"]) { $AccessTokenArguments.Add("ClientSecret", $ClientSecretSecure) } if ($PSBoundParameters["ClientCertificate"]) { $AccessTokenArguments.Add("ClientCertificate", $ClientCertificate) } if ($PSBoundParameters["Scopes"]) { $AccessTokenArguments.Add("Scopes", $Scopes) } try { # Attempt to retrieve or refresh an access token $Global:AccessToken = Get-MsalToken @AccessTokenArguments Write-Verbose -Message "Successfully retrieved access token" try { # Construct the required authentication header $Global:AuthenticationHeader = New-AuthenticationHeader -AccessToken $Global:AccessToken if ($PSBoundParameters["AddConsistencyLevelEventualHeader"]) { Add-AuthenticationHeaderItem -Name "ConsistencyLevel" -Value "eventual" } Write-Verbose -Message "Successfully constructed authentication header" # Handle return value return $Global:AuthenticationHeader } catch [System.Exception] { Write-Warning -Message "An error occurred while attempting to construct authentication header. Error message: $($PSItem.Exception.Message)" } } catch [System.Exception] { Write-Warning -Message "An error occurred while attempting to retrieve or refresh access token. Error message: $($PSItem.Exception.Message)" } } catch [System.Exception] { Write-Warning -Message "An error occurred while constructing parameter input for access token retrieval. Error message: $($PSItem.Exception.Message)" } } } |