Authentication.psm1

<#
.SYNOPSIS
    This function retrieves an access token from the Partner Center authentication servers.
.DESCRIPTION
    This function retrieves an access token from the Partner Center authentication servers.
    This access token is used in Partner Center REST API calls.
    Returns null if failed to retrieve the access token.
.PARAMETER username
    The username of the Partner Center admin account.
.PARAMETER password
    The password of the Partner Center admin account.
.PARAMETER applicationId
    The Partner Center Native App Application Id.
.PARAMETER endpoint
    The MSPComplete Endpoint containing the Partner Center admin credentials.
.EXAMPLE
    Get-PartnerCenterAccessToken -Endpoint $Endpoint
.EXAMPLE
    $Endpoint | Get-PartnerCenterAccessToken
.EXAMPLE
    Get-PartnerCenterAccessToken -Username $username -Password $password -ApplicationId $applicationId
#>

function Get-PartnerCenterAccessToken {
    param (
        # The username of the Partner Center admin account.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$username,

        # The password of the Partner Center admin account.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [SecureString]$password,

        # The Partner Center Native App Application Id.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [GUID]$applicationId,

        # The MSPComplete Endpoint containing the Partner Center admin credentials.
        [Parameter(Mandatory=$true, ParameterSetName="endpoint", ValueFromPipeline=$true)]
        $endpoint
    )

    # If given endpoint, retrieve username, password and application ID
    if ($PSCmdlet.ParameterSetName -eq "endpoint") {
        $partnerCenterCredential = $endpoint | Get-CredentialFromMSPCompleteEndpoint
        $username = $partnerCenterCredential.Username
        $password = $partnerCenterCredential.Password

        # Check if endpoint has application ID extended property
        if (!($endpoint.ExtendedProperties) -or !(Search-HashTable -HashTable $endpoint.ExtendedProperties -Key "ApplicationId")) {
            Write-Error "Endpoint provided does not have an 'ApplicationId' extended property."
            return $null
        }
        $applicationId = $endpoint.ExtendedProperties.ApplicationId
    }

    # Retrieve plaintext password
    $plainTextPassword = (New-Object System.Management.Automation.PSCredential("username", $password)).GetNetworkCredential().Password

    # Extract the domain from the username
    $domain = Get-EmailAddressDomain $username
    if ([String]::IsNullOrWhiteSpace($domain)) {
        Write-Error "Failed to extract domain from username '$($username)'."
        return $null
    }

    # Construct the REST call
    $url = "https://login.windows.net/$($domain)/oauth2/token"
    $body = "grant_type=password&resource=https://api.partnercenter.microsoft.com&" `
          + "client_id=$([System.Web.HttpUtility]::UrlEncode($applicationID))&" `
          + "username=$([System.Web.HttpUtility]::UrlEncode($username))&" `
          + "password=$([System.Web.HttpUtility]::UrlEncode($plainTextPassword))&" `
          + "scope=openid"

    # Create hash table for params
    $invokeRestMethodParams = @{
        Uri         = $url
        ContentType = "application/x-www-form-urlencoded"
        Body        = $body
        Method      = "POST"
    }

    # Try to invoke REST call
    try {
        $response = Invoke-RestMethod @invokeRestMethodParams
    }

    # Error while invoking REST call
    catch {
        Write-Error "Error while invoking REST call. `r`n$($_.Exception.Message)"
        return $null
    }

    # Verify the response
    if ($null -eq $response -or $response.expires_in -le 0 -or [String]::IsNullOrWhiteSpace($response.access_token)) {
        Write-Error "Failed to retrieve access token."
        return $null
    }

    # Return the access token
    return $response.access_token
}