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-MSIntuneAuthToken -TenantName domain.onmicrsoft.com -ClientID "<GUID>"
 
        # Retrieve a PSCredential object with username and password to acquire an authentication token:
        $Credential = Get-Credential
        Get-MSIntuneAuthToken -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-MSIntuneAuthToken -TenantName domain.onmicrsoft.com -ClientID "<GUID>" -Credential $Credential
 
    .NOTES
    Author: Nickolaj Andersen
    Contact: @NickolajA
    Created: 2017-09-27
    Updated: 2018-01-28
 
    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
    1.0.6 - (2018-01-22) Enhanced the AzureAD module detection logic
 
    #>

    [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",

        [parameter(Mandatory=$false, ParameterSetName="AuthPrompt", HelpMessage="Grant admin consent for delegated admin permissions.")]
        [switch]$AdminConsent
    )

    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-Module -Name "AzureAD" -ListAvailable -ErrorAction Stop -Verbose:$false | Select-Object -ExpandProperty ModuleBase
            }

            # 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
                        if ($AdminConsent -eq $true) {
                            $UserIdentifier = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($Credential.UserName, "")
                            $AuthenticationResult = ($AuthenticationContext.AcquireTokenAsync($ResourceRecipient, $ClientID, $RedirectUri, $PlatformParams, "prompt=admin_consent")).Result
                        }
                        else {
                            $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
    }
}

function Set-MSIntuneAdminConsent {
    <#
    .SYNOPSIS
        Grant admin consent for delegated admin permissions.
        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
        Specify a Global Admin user principal name.
 
    .EXAMPLE
        # Grant admin consent for delegated admin permissions for an Intune tenant:
        Set-MSIntuneAdminConsent -TenantName domain.onmicrsoft.com -UserPrincipalName "globaladmin@domain.onmicrosoft.com"
 
    .NOTES
    Author: Nickolaj Andersen
    Contact: @NickolajA
    Created: 2018-01-28
    Updated: 2018-01-28
 
    Version history:
    1.0.0 - (2018-01-28) Function created
    1.0.1 - (2018-01-28) Added static prompt behavior parameter with value of Auto
 
    #>

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

        [parameter(Mandatory=$true, HelpMessage="Specify a Global Admin user principal name.")]
        [ValidateNotNullOrEmpty()]
        [string]$UserPrincipalName
    )

    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-Module -Name "AzureAD" -ListAvailable -ErrorAction Stop -Verbose:$false | Select-Object -ExpandProperty ModuleBase
            }

            # 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 {
                # Set static variables
                $Authority = "https://login.microsoftonline.com/$($TenantName)/oauth2/token"
                $ResourceRecipient = "https://graph.microsoft.com"
                $RedirectUri = "urn:ietf:wg:oauth:2.0:oob"
                $ClientID = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547" # Default Microsoft Intune PowerShell enterprise application

                # 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 "Auto" -ErrorAction Stop

                # Construct user identifier
                $UserIdentifier = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($UserPrincipalName, "OptionalDisplayableId")

                # Acquire authentication token and invoke admin consent
                $AuthenticationResult = ($AuthenticationContext.AcquireTokenAsync($ResourceRecipient, $ClientID, $RedirectUri, $PlatformParams, $UserIdentifier, "prompt=admin_consent")).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
    }    
}