functions/Invoke-PsLaConsent.AzAccount.ps1


<#
    .SYNOPSIS
        Start the consent flow for an ApiConnection object
         
    .DESCRIPTION
        Some of the ApiConnection objects needs an user account to consent / authenticate, before it works
         
        This cmdlet helps starting, running and completing the consent flow an ApiConnection object
         
        Uses the current connected Az.Account session to pull the details from the azure portal
         
    .PARAMETER Id
        The (resource) id of the ApiConnection object that you want to work against, your current Az.Account powershell session either needs to be "connected" to the subscription/resource group or at least have permissions to work against the subscription/resource group, where the ApiConnection object is located
         
    .EXAMPLE
        PS C:\> Invoke-PsLaConsent.AzAccount -Id "/subscriptions/b466443d-6eac-4513-a7f0-3579502929f00/providers/Microsoft.Web/locations/westeurope/managedApis/servicebus"
         
        This will start the consent flow for the ApiConnection object
        It will prompt the user to fill in an account / credential
        It will confirm the consent directly to the ApiConnection object
         
    .EXAMPLE
        PS C:\> Get-PsLaManagedApiConnection.AzAccount -ResourceGroup "TestRg" -FilterError Unauthenticated | Invoke-PsLaConsent.AzAccount
         
        This will fetch all ApiConnection objects from the "TestRg" Resource Group
        Filters the list to show only the ones with error of the type Unauthenticated
        Will pipe the objects to Invoke-PsLaConsent.AzAccount
        This will start the consent flow for the ApiConnection object
        It will prompt the user to fill in an account / credential
        It will confirm the consent directly to the ApiConnection object
         
    .NOTES
        This is highly inspired by the previous work of other smart people:
        https://github.com/logicappsio/LogicAppConnectionAuth/blob/master/LogicAppConnectionAuth.ps1
        https://github.com/OfficeDev/microsoft-teams-apps-requestateam/blob/master/Deployment/Scripts/deploy.ps1
         
        Author: Mötz Jensen (@Splaxi)
         
#>

function Invoke-PsLaConsent.AzAccount {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias("ResourceId")]
        [string] $Id
    )
    
    begin {
        $listParms = @{
            "parameters" = , @{
                "parameterName" = "token";
                "redirectUrl"   = "http://localhost"
            }
        }
    }

    process {
        if (-not ($Id -match "/Microsoft.Web/connections/(.*)")) {
            $messageString = "The resource id supplied didn't match the expected structure. Please make sure the resource id is a <c='em'>Microsoft.Web/connections</c>."
            Write-PSFMessage -Level Host -Message $messageString
            Stop-PSFFunction -Message "Stopping because the resource id did match." -Exception $([System.Exception]::new($($messageString -replace '<[^>]+>', '')))
            return
        }

        Write-PSFMessage -Level Host -Message "You will be prompted to consent the ApiConnection object: <c='em'>$($Matches[1])</c>. You might need to supplied credentials that <c='em'>are different</c> from your personal account / credentials."

        # Get the links needed for consent
        $consentResponse = Invoke-AzResourceAction -Action "listConsentLinks" -ResourceId $Id -Parameters $listParms -Force

        # Show sign-in prompt window and grab the code after authentication
        $resUrl = Show-OAuthConsentWindow -URL $consentResponse.Value.Link

        if ([System.String]::IsNullOrEmpty($resUrl)) {
            $messageString = "It seems that either the consent failed or you exited the consent flow before it completed. Please make sure to complete the consent flow all the way through for this to work."
            Write-PSFMessage -Level Host -Message $messageString
            Stop-PSFFunction -Message "Stopping because result from the consent flow was empty." -Exception $([System.Exception]::new($($messageString -replace '<[^>]+>', '')))
            return
        }

        $regex = '(code=)(.*)$'
        $code = ($resUrl | Select-string -pattern $regex).Matches[0].Groups[2].Value

        if ($code) {
            $confirmParms = @{ }
            $confirmParms.Add("code", $code)
        
            # NOTE: errors ignored as this appears to error due to a null response
            Invoke-AzResourceAction -Action "confirmConsentCode" -ResourceId $Id -Parameters $confirmParms -Force -ErrorAction Ignore
        }
    }
}