AadToken.psm1

#
# Short AAD Token-getter module. Currently only works with Azure Key Vault resource.
# John Cravener
# December 28, 2017
# V1.0
# December 30, 2017
# V1.1 Added default value to ResourceId param.
#
# December 30, 2017
# V1.2 v1.0 and v1.1 shipped with the wrong Microsoft.IdentityModel.Clients.ActiveDirectory.dll version. v1.2 corrects this problem.
#

Add-Type -Path "$($PSScriptRoot)\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"

function Get-AadToken
{
    param
    (
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
        [System.String]
        $ClientId = $null,

        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=1)]
        [System.String]
        $TenantId = $null,

        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=2)]
        [System.Security.SecureString]
        $ClientSecret = $null,

        [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=3)]
        [ValidateSet('https://vault.azure.net')]
        [System.String]
        $ResourceId = 'https://vault.azure.net'
    )

    begin
    {                        
        $login = 'https://login.microsoftonline.com'        
    }

    process
    {
        foreach($o in $PSBoundParameters)
        {
            $clientSecretPlain = ConvertFrom-AadTokenSecureString -SecureString $o['ClientSecret']

            $clientCredential = New-Object -TypeName Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential -ArgumentList $ClientId, $ClientSecretPlain

            $authContext = New-Object -TypeName Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext -ArgumentList "$($login)/$($TenantId)"
            
            $authenticationResult = $authContext.AcquireToken($ResourceId, $clientCredential)

            $authenticationResult
        }
    }

    end{}
}

function Get-AadTokenViaPrompt
{
    param
    (

        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
        [System.String]
        $TenantId = $null,

        [parameter(Mandatory=$false, ValueFromPipelineByPropertyName=$true, Position=1)]
        [ValidateSet('https://vault.azure.net')]
        [System.String]
        $ResourceId = 'https://vault.azure.net'
    )

    begin
    {                        
        
        $clientId = '1950a258-227b-4e31-a9cf-717495945fc2'  #--the "well known" client id
        $redirectUri = 'urn:ietf:wg:oauth:2.0:oob'  #--the "well known" redirect uri

        $login = 'https://login.microsoftonline.com'
        
        $promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
    }

    process
    {
        foreach($o in $PSBoundParameters)
        {
            $authContext = New-Object -TypeName Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext -ArgumentList "$($login)/$($TenantId)"
            
            $authenticationResult = $authContext.AcquireToken($ResourceId, $clientId, $redirectUri, $promptBehavior)

            $authenticationResult
        }
    }

    end{}
}

function ConvertFrom-AadTokenSecureString
{
    param
    (
        [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)]
        [System.Security.SecureString]
        $SecureString
    )

    begin{}

    process
    {
        foreach($ss in $SecureString)
        {
            if($ss -eq $null)
            {
                throw "Passed-in secure string was null."
            }

            try
            {
                $us = [runtime.interopservices.Marshal]::SecureStringToGlobalAllocUnicode($ss)

                return [runtime.interopservices.Marshal]::PtrToStringAuto($us)
            }
            finally
            {
                [runtime.interopservices.Marshal]::ZeroFreeGlobalAllocUnicode($us)
            }
        }
    }

    end{}
}