Private/Get-MechanismAnswer.ps1

function Get-MechanismAnswer {
    <#
    .SYNOPSIS
    Allows a user to answer an MFA chalenge Mechanism

    .DESCRIPTION
    MFA Challenges include User Password, Security Questions, SMS, OATH, Email, OTP, Phone Call & QR Code.
    Password is supplied automatically from provided credential object.
    Users are able to provide input to answer OATH, SMS or Security Questions.
    Out of Band factors (Phone Call, QR Code App Push & Email validation Link) are polled for until satisfied.
    U2F and DUO are not currenlty supported via this code.

    .PARAMETER Mechanism
    The mechanism to answer

    .PARAMETER Credential
    Credential obejct containing username & password for Identity tenant authentication

    .EXAMPLE
    $Answer = Get-MechanismAnswer -Mechanism $Mechanism -Credential $Credential

    Prompts the user to answer the challenge mechanism and saves the response to the $answer variable for use to advance the authentication.

    .NOTES
    Pete Maan 2023
    #>


    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Actual legitimate use of Write-Host')]
    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory = $true,
            ValueFromPipeline = $true
        )]
        [ValidateNotNullOrEmpty()]
        [psobject]$Mechanism,

        #User Creds
        [Parameter(
            Mandatory = $true,
            ValueFromPipelinebyPropertyName = $false
        )]
        [ValidateNotNullOrEmpty()]
        [PSCredential]$Credential
    )

    Begin {}

    Process {

        switch ($Mechanism.Name) {

            'UP' {

                #User Password already provided via Credential
                $Answer = $Credential.Password

                break

            }

            'SQ' {

                #Create Key/Value pairs for each question Uuid/Answer
                $Answer = @{}

                foreach ($MechanismPart in $($Mechanism.MultipartMechanism.MechanismParts)) {

                    $Answer[$MechanismPart.Uuid] = Read-Host -Prompt $($MechanismPart.PromptMechChosen) -AsSecureString

                }

                break

            }

            { $PSItem -match 'EMAIL|OTP|PF|QR' } {

                #App Push, Email Validation link, QR or Phone + PIN
                #todo APP/EMAIL also support specify OTP as answer
                #todo user should be able to choose push or answer

                #Output instructions to console
                Write-Host $($Mechanism.PromptMechChosen)

                if ($PSItem -eq 'QR') {

                    Write-Host 'Displaying QR in Browser...'
                    $Mechanism | Out-QRImage | Invoke-Item

                }

                break

            }

            { $PSItem -match 'SMS|OATH' } {

                #Prompt for TOTP/SMS code input
                $Answer = Read-Host -Prompt $($Mechanism.PromptMechChosen) -AsSecureString
                break

            }

            'RESET' {

                #Expired Password: prompt for new value & confirmation
                $attempt = 0

                do {

                    If ($attempt -ge 1) {

                        Write-Warning 'Passwords did not match, please try again.'

                    }

                    Write-Host "$($Mechanism.PasswordComplexityHint)"

                    $Answer = Read-Host -Prompt 'Password' -AsSecureString
                    $Confirm = Read-Host -Prompt 'Confirm Password' -AsSecureString
                    $attempt++

                }
                while (-not(Compare-SecureString -SecureString1 $Answer -SecureString2 $Confirm))

                break

            }

            default {

                #Unsupported Mechanism [U2F|DUO]
                throw "Support for $PSItem mechanism not yet implemented in the module"
                break

            }

        }

    }

    End {
        $Answer
    }

}