PSIntuneAuth.psm1

function Get-MSIntuneAuthToken {
    <#
    .SYNOPSIS
        Get an authentication token required for interacting with Microsoft Intune using Microsoft Graph API
        NOTE: This function requires that AzureAD module is installed. Use 'Install-Module -Name AzureAD' to install it.
 
    .PARAMETER TenantName
        A tenant name should be provided in the following format: tenantname.onmicrosoft.com.
 
    .PARAMETER ClientID
        Application ID for an Azure AD application.
 
    .PARAMETER Credential
        Specify a PSCredential object containing username and password.
 
    .PARAMETER RedirectUri
        Redirect URI for Azure AD application. Leave empty to leverage Azure PowerShell well known redirect URI.
 
    .PARAMETER PromptBehavior
        Set the prompt behavior when acquiring a token.
 
    .EXAMPLE
        # Manually specify username and password to acquire an authentication token:
        Get-MSGraphAuthenticationToken -TenantName domain.onmicrsoft.com -ClientID "<GUID>"
 
        # Retrieve a PSCredential object with username and password to acquire an authentication token:
        $Credential = Get-Credential
        Get-MSGraphAuthenticationToken -TenantName domain.onmicrsoft.com -ClientID "<GUID>" -Credential $Credential
 
        # Retrieve a PSCredential object for usage with Azure Automation containing the username and password to acquire an authentication token:
        $Credential = Get-AutomationPSCredential -Name "<CredentialName>"
        Get-MSGraphAuthenticationToken -TenantName domain.onmicrsoft.com -ClientID "<GUID>" -Credential $Credential
 
    .NOTES
    Author: Nickolaj Andersen
    Contact: @NickolajA
    Created: 2017-09-27
    Updated: 2018-01-22
 
    Version history:
    1.0.0 - (2017-09-27) Script created
    1.0.1 - (2017-09-28) N/A - module manifest update
    1.0.2 - (2017-10-08) Added ExpiresOn property
    1.0.3 - (2018-01-22) Added support for specifying PSCredential object for silently retrieving an authentication token without being prompted
    1.0.4 - (2018-01-22) Fixed an issue with prompt behavior parameter not being used
    1.0.5 - (2018-01-22) Fixed an issue when detecting the AzureAD module presence
 
    #>

    [CmdletBinding()]
    param(
        [parameter(Mandatory=$true, ParameterSetName="AuthPrompt", HelpMessage="A tenant name should be provided in the following format: tenantname.onmicrosoft.com.")]
        [parameter(Mandatory=$true, ParameterSetName="AuthCredential")]
        [ValidateNotNullOrEmpty()]
        [string]$TenantName,

        [parameter(Mandatory=$true, ParameterSetName="AuthPrompt", HelpMessage="Application ID for an Azure AD application.")]
        [parameter(Mandatory=$true, ParameterSetName="AuthCredential")]
        [ValidateNotNullOrEmpty()]
        [string]$ClientID,

        [parameter(Mandatory=$true, ParameterSetName="AuthCredential", HelpMessage="Specify a PSCredential object containing username and password.")]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential,

        [parameter(Mandatory=$false, ParameterSetName="AuthPrompt", HelpMessage="Redirect URI for Azure AD application. Leave empty to leverage Azure PowerShell well known redirect URI.")]
        [parameter(Mandatory=$false, ParameterSetName="AuthCredential")]
        [ValidateNotNullOrEmpty()]
        [string]$RedirectUri = "urn:ietf:wg:oauth:2.0:oob",

        [parameter(Mandatory=$false, ParameterSetName="AuthPrompt", HelpMessage="Set the prompt behavior when acquiring a token.")]
        [parameter(Mandatory=$false, ParameterSetName="AuthCredential")]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("Auto", "Always", "Never", "RefreshSession")]
        [string]$PromptBehavior = "Auto"
    )

    try {
        # Get installed Azure AD modules
        $AzureADModules = Get-Module -Name "AzureAD" -ListAvailable -ErrorAction Stop -Verbose:$false

        if ($AzureADModules -ne $null) {
            # Check if multiple modules exist and determine the module path for the most current version
            if (($AzureADModules | Measure-Object).Count -gt 1) {
                $LatestAzureADModule = ($AzureADModules | Select-Object -Property Version | Sort-Object)[-1]
                $AzureADModulePath = $AzureADModules | Where-Object { $_.Version -like $LatestAzureADModule.Version } | Select-Object -ExpandProperty ModuleBase
            }
            else {
                $AzureADModulePath = Get-InstalledModule -Name "AzureAD" | Select-Object -ExpandProperty InstalledLocation
            }

            # Construct array for required assemblies from Azure AD module
            $Assemblies = @(
                (Join-Path -Path $AzureADModulePath -ChildPath "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"),
                (Join-Path -Path $AzureADModulePath -ChildPath "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll")
            )
            Add-Type -Path $Assemblies -ErrorAction Stop

            try {
                $Authority = "https://login.microsoftonline.com/$($TenantName)/oauth2/token"
                $ResourceRecipient = "https://graph.microsoft.com"

                # Construct new authentication context
                $AuthenticationContext = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $Authority -ErrorAction Stop

                # Construct platform parameters
                $PlatformParams = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList $PromptBehavior -ErrorAction Stop

                # Determine parameters when acquiring token
                switch ($PSCmdlet.ParameterSetName) {
                    "AuthPrompt" {
                        # Acquire access token
                        $AuthenticationResult = ($AuthenticationContext.AcquireTokenAsync($ResourceRecipient, $ClientID, $RedirectUri, $PlatformParams)).Result
                    }
                    "AuthCredential" {
                        # Construct required identity model credential
                        $UserPasswordCredential = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential" -ArgumentList ($Credential.UserName, $Credential.Password) -ErrorAction Stop

                        # Acquire access token
                        $AuthenticationResult = ([Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContextIntegratedAuthExtensions]::AcquireTokenAsync($AuthenticationContext, $ResourceRecipient, $ClientID, $UserPasswordCredential)).Result
                    }
                }
                
                # Check if access token was acquired
                if ($AuthenticationResult.AccessToken -ne $null) {
                    # Construct authentication hash table for holding access token and header information
                    $Authentication = @{
                        "Content-Type" = "application/json"
                        "Authorization" = -join("Bearer ", $AuthenticationResult.AccessToken)
                        "ExpiresOn" = $AuthenticationResult.ExpiresOn
                    }

                    # Return the authentication token
                    return $Authentication                    
                }
                else {
                    Write-Warning -Message "Failure to acquire access token. Response with access token was null" ; break
                }
            }
            catch [System.Exception] {
                Write-Warning -Message "An error occurred when constructing an authentication token: $($_.Exception.Message)" ; break
            }
        }
        else {
            Write-Warning -Message "Azure AD PowerShell module is not present on this system, please install before you continue" ; break
        }
    }
    catch [System.Exception] {
        Write-Warning -Message "Unable to load required assemblies (Azure AD PowerShell module) to construct an authentication token. Error: $($_.Exception.Message)" ; break
    }
}