Public/Start-CheckIDPasswordAgentListener.ps1

<#
.DESCRIPTION
    Starts the CheckIDPasswordAgent listener. The listener continuously checks for password reset requests and processes them.

.SYNOPSIS
    Starts the CheckIDPasswordAgent listener.

.EXAMPLE
    Start-CheckIDPasswordAgentListener -Sleep 5
#>

function Start-CheckIDPasswordAgentListener {
    [CmdletBinding()]
    Param(
        # Sleep interval in seconds between checks for new requests
        [Parameter(Mandatory = $false)]
        [ValidateRange(1, 10)]
        [int] $Sleep = 5
    )

    process {
        if(!(get-command Set-ADAccountPassword* | ? Name -eq Set-ADAccountPassword)) {
            Write-Error -Message "Set-ADAccountPassword cmdlet is not available. Please ensure the Active Directory module is installed and imported."
            Write-EventLog -LogName "Application" -Source "CheckIDPasswordAgent" -EventId 1210 -EntryType Error -Message "Set-ADAccountPassword cmdlet is not available. Please ensure the Active Directory module is installed and imported." -ErrorAction Continue
            return
        }

        Write-Verbose "Starting CheckIDPasswordAgent listener with a sleep interval of $Sleep seconds"
        Write-EventLog -LogName "Application" -Source "CheckIDPasswordAgent" -EventId 1006 -EntryType Information -Message "Starting CheckIDPasswordAgent listener with a sleep interval of $Sleep seconds" -ErrorAction Continue

        while ($true) {
            $requests = Receive-CheckIDPasswordAgentRequests

            if ($requests) {
                $requests | ForEach-Object {
                    try {
                        if(!$_.onPremisesSecurityIdentifier) {
                            Write-Warning "No onPremisesSecurityIdentifier found for user $($_.userPrincipalName) (Cloud only probably, so we are not doing anything)"
                        } else {
                            Write-Verbose "Setting password for user $($_.userPrincipalName) / $($_.onPremisesSecurityIdentifier)"
                            Write-EventLog -LogName "Application" -Source "CheckIDPasswordAgent" -EventId 1008 -EntryType Information -Message "Setting password for user $($_.userPrincipalName) / $($_.onPremisesSecurityIdentifier) with ID: $($_.id)" -ErrorAction Continue
                            Set-ADAccountPassword -Identity $_.onPremisesSecurityIdentifier -NewPassword (ConvertTo-SecureString -String $_.password -AsPlainText -Force) -Reset
                        }

                        $_ | Confirm-CheckIDPasswordAgentRequest -Status "Success"
                    }
                    catch {
                        Write-Error -Message "Failed to set password for user $($_.userPrincipalName): $_"
                        Write-EventLog -LogName "Application" -Source "CheckIDPasswordAgent" -EventId 1201 -EntryType Error -Message "Failed to set password for user $($_.userPrincipalName) with ID $($_.id) - $_" -ErrorAction Continue
                        
                        $_ | Confirm-CheckIDPasswordAgentRequest -Status "Error" -Message $_.Exception.Message
                    }
                }
            }
            else {
                Write-Verbose "No requests found, sleeping for $Sleep seconds"
                # Too verbose, no need to inform for every API GET request interval. Fills up Windows event log
                # Write-EventLog -LogName "Application" -Source "CheckIDPasswordAgent" -EventId 1007 -EntryType Information -Message "No requests found, sleeping for $Sleep seconds" -ErrorAction Continue
                Start-Sleep -Seconds $Sleep
            }
        }
        
    }
}