Public/Start-ChangeEmailAgentActiveDirectoryListener.ps1
<# .DESCRIPTION Starts the ChangeEmailAgent listener. The listener continuously checks for password reset requests and processes them. .SYNOPSIS Starts the ChangeEmailAgent listener. .EXAMPLE Start-ChangeEmailAgentActiveDirectoryListener -Sleep 5 #> function Start-ChangeEmailAgentActiveDirectoryListener { [CmdletBinding()] Param( # Sleep interval in seconds between checks for new requests [Parameter(Mandatory = $false)] [ValidateRange(1, 3600)] [int] $Sleep = 10, # Max number of loops to run. Default is infinite. [Parameter(Mandatory = $false)] [ValidateRange(1, 2147483647)] [int] $MaxNumberOfRRuns = 2147483647, [Parameter(Mandatory = $false)] [scriptblock] $RunBlockAfterChange = $null ) process { if (!(get-command Set-ADUser* | ? Name -eq Set-ADUser)) { Write-Error -Message "Set-ADUser cmdlet is not available. Please ensure the Active Directory module is installed and imported." Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1210 -EntryType Error -Message "Set-ADUser cmdlet is not available. Please ensure the Active Directory module is installed and imported." -ErrorAction Continue return } Write-Verbose "Starting ChangeEmailAgent $($PSCmdlet.MyInvocation.MyCommand.ScriptBlock.Module.Version?.ToString()) listener with a sleep interval of $Sleep seconds" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1006 -EntryType Information -Message "Starting ChangeEmailAgent $($PSCmdlet.MyInvocation.MyCommand.ScriptBlock.Module.Version?.ToString()) listener with a sleep interval of $Sleep seconds" -ErrorAction Continue while ($true) { $MaxNumberOfRRuns -= 1 if ($MaxNumberOfRRuns -lt 0) { Write-Verbose "MaxNumberOfRRuns reached, exiting listener" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1011 -EntryType Information -Message "MaxNumberOfRRuns reached, exiting listener" -ErrorAction Continue break } $requests = Receive-ChangeEmailAgentRequests if ($requests) { foreach ($request in $requests) { Write-Verbose "Processing request: $($request | ConvertTo-Json -Depth 5)" if (!$request.onPremisesImmutableId) { Write-Warning "Request does not contain onPremisesImmutableId: $($request | ConvertTo-Json -Depth 5)" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1008 -EntryType Warning -Message "Request does not contain onPremisesImmutableId: $($request | ConvertTo-Json -Depth 5)" -ErrorAction Continue $request | Complete-ChangeEmailAgentRequest -Status "Failed" -ErrorMessage "Request does not contain onPremisesImmutableId" continue } $immutableid = [System.Convert]::FromBase64String($request.onPremisesImmutableId) $matchingusers = Get-ADUser -Filter { ms-Ds-ConsistencyGuid -eq $immutableid } -Properties mail, proxyAddresses, userPrincipalName if (!$matchingusers) { Write-Warning "No matching user found in Active Directory for request $($request | ConvertTo-Json -Depth 5)" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1009 -EntryType Warning -Message "No matching user found in Active Directory for request $($request | ConvertTo-Json -Depth 5)" -ErrorAction Continue $request | Complete-ChangeEmailAgentRequest -Status "Failed" -ErrorMessage "No matching user found in Active Directory" continue } if ($matchingusers.Count -gt 1) { Write-Warning "Multiple matching users found in Active Directory for request $($request | ConvertTo-Json -Depth 5)" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1010 -EntryType Warning -Message "Multiple matching users found in Active Directory for request $($request | ConvertTo-Json -Depth 5)" -ErrorAction Continue $request | Complete-ChangeEmailAgentRequest -Status "Failed" -ErrorMessage "Multiple matching users found in Active Directory" continue } $user = $matchingusers | Select-Object -First 1 $proxyaddresses = @( "SMTP:$($request.emailAddress)" ) if ($user.proxyAddresses) { $user.proxyAddresses | Where-Object { $_ -like "smtp:*" } | Where-Object { $_ -notin $proxyaddresses } | ForEach-Object { $proxyaddresses += "{0}" -f ($_ -replace "^SMTP", "smtp") } $user.proxyAddresses | Where-Object { $_ -notlike "smtp:*" } | Where-Object { $_ -notin $proxyaddresses } | ForEach-Object { $proxyaddresses += "{0}" -f $_ } } $_UpdatingUserMessage = @( "Updating user $($user.SamAccountName):" " - userPrincipalName: $($user.UserPrincipalName) -> $($request.emailAddress)" " - mail: $($user.mail) -> $($request.emailAddress)" " - proxyAddresses:" ) $user.proxyAddresses | Where-Object { $_ -cnotin $proxyaddresses } | ForEach-Object { $_UpdatingUserMessage += " - $_ (removed)" } $proxyAddresses | Where-Object { $_ -cnotin $user.proxyaddresses } | ForEach-Object { $_UpdatingUserMessage += " + $_ (added)" } $user.proxyAddresses | Where-Object { $_ -cin $proxyaddresses } | ForEach-Object { $_UpdatingUserMessage += " ~ $_ (no change)" } $UpdatingUserMessage = $_UpdatingUserMessage -join "`n" Write-Verbose $UpdatingUserMessage Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1012 -EntryType Information -Message $UpdatingUserMessage -ErrorAction Continue try { $user | Set-ADUser -UserPrincipalName $request.emailAddress -EmailAddress $request.emailAddress -Replace @{ proxyAddresses = $proxyaddresses } } catch { Write-Error "Failed to update user $($user.SamAccountName): $_" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1013 -EntryType Error -Message "Failed to update user $($user.SamAccountName): $_" -ErrorAction Continue $request | Complete-ChangeEmailAgentRequest -Status "Failed" -ErrorMessage "$_" continue } $request | Complete-ChangeEmailAgentRequest } if ($RunBlockAfterChange) { Write-Verbose "Running custom script block after processing changes" & $RunBlockAfterChange } } else { Write-Verbose "No requests found, sleeping for $Sleep seconds" Write-EventLog -LogName "Application" -Source "ChangeEmailAgent" -EventId 1007 -EntryType Information -Message "No requests found, sleeping for $Sleep seconds" -ErrorAction Continue } Start-Sleep -Seconds $Sleep } } } |