Remediation/TeamsPhone/TEL-CALLING-SETTINGS.ps1
|
# UNTESTED: this script has never been run on a real tenant. Read it, try it on a test tenant first, and use it at your own risk. <# .SYNOPSIS Reproduces in the target the forwarding, unanswered handling and delegations of voice users (procedure TEL-CALLING-SETTINGS). .DESCRIPTION Comes after the cutover: an account is handled only if its number is assigned in the target according to the snapshot. Run again after TEL-NUMBERS and a new snapshot. Before that, the script only announces the users to warn. In an -Apply run, it reads the settings of the source again (Get-CsUserCallingSettings) and reproduces them. A target on an account of the source is converted through the matrix; a target with no match is not carried over and raises an alert. New-CsUserCallingDelegate also needs -PickUpHeldCalls and -JoinActiveCalls: the rights are carried over from the source. Limit: a call group aims at accounts of the source, the user redoes it in Teams. #> $c = Open-TcRemediation $targetAccounts = @{} foreach ($u in Get-TcRemediationTable 'Target' 'teamsUsers') { $targetAccounts[([string]$u['UPN']).ToLowerInvariant()] = [string]$u['UPN'] } $assignedNumbers = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) foreach ($n in Get-TcRemediationTable 'Target' 'phoneNumbers') { if ($n['Assigned to']) { [void]$assignedNumbers.Add([string]$n['Assigned to']) } } $Matrices = @{} $SettingRows = @{} function Get-SourceSetting { <# Settings of all the users of a source, read at once: each change of tenant opens a Teams session again. #> param([string]$Source, [string[]]$Accounts) if ($SettingRows[$Source]) { return $SettingRows[$Source] } $r = @{} foreach ($u in $Accounts) { $r[$u.ToLowerInvariant()] = Invoke-TcServiceCommand -Tenant $Source -Service Teams -Command 'Get-CsUserCallingSettings' -Parameters @{ Identity = $u } } $SettingRows[$Source] = $r return $r } function ConvertTo-TargetValue { <# Number: unchanged. Account of the source: its account in the target. Empty if nothing matches. #> param([string]$Target, [string]$Source) if (-not $Target) { return '' } if ($Target -notmatch '@') { return $Target } $upn = ($Target -replace '^sip:', '').ToLowerInvariant() $l = $Matrices[$Source][$upn] if ($l) { foreach ($u in (Get-TcMember $l 'Target UPN'), (Get-TcMember $l 'Temporary UPN')) { if ($u -and $targetAccounts[([string]$u).ToLowerInvariant()]) { return "sip:$u" } } } return '' } foreach ($t in $c.Tenants) { Write-TcRemediationTenant $t $matrix = @{} foreach ($l in @((Get-TcMember (Get-TcRemediationIdentity $t) 'rows'))) { $matrix[((Get-TcText $l 'Source UPN')).ToLowerInvariant()] = $l } $Matrices[$t] = $matrix $rows = @(Get-TcRemediationTable $t 'userCallingSettings' | Where-Object { $_['Forwarding'] -or $_['Unanswered'] -or $_['Delegates'] -or $_["Call group"] }) Write-TcRemediationNote ("{0} user(s) with forwarding, unanswered handling, delegation or a call group" -f $rows.Count) if (-not $rows.Count) { continue } $sourceAccounts = @($rows | ForEach-Object { [string]$_['UPN'] }) $ready = 0 foreach ($p in $rows) { $src = [string]$p['UPN'] $l = $matrix[$src.ToLowerInvariant()] $target = if ($l) { @((Get-TcMember $l 'Target UPN'), (Get-TcMember $l 'Temporary UPN') | Where-Object { $_ -and $targetAccounts[([string]$_).ToLowerInvariant()] }) | Select-Object -First 1 } if (-not $target -or -not $assignedNumbers.Contains([string]$target)) { continue } $ready++ Add-TcBlockAction -Tenant 'Target' -Service Teams -Object ([string]$target) -Description ("Reproduce the calling settings of {0}" -f $target) -Data @{ Source = $t; SourceAccount = $src; Target = [string]$target; Accounts = $sourceAccounts } ` -Test { param($a) $s = (Get-SourceSetting -Source $a.data.Source -Accounts $a.data.Accounts)[$a.data.SourceAccount.ToLowerInvariant()] $d = Invoke-TcServiceCommand -Tenant $a.tenant -Service Teams -Command 'Get-CsUserCallingSettings' -Parameters @{ Identity = $a.data.Target } $a.undo = @( @{ command = 'Set-CsUserCallingSettings'; parameters = @{ Identity = $a.data.Target; IsForwardingEnabled = [bool](Get-TcMember $d 'IsForwardingEnabled') } } @{ command = 'Set-CsUserCallingSettings'; parameters = @{ Identity = $a.data.Target; IsUnansweredEnabled = [bool](Get-TcMember $d 'IsUnansweredEnabled') } }) return ([bool](Get-TcMember $s 'IsForwardingEnabled') -eq [bool](Get-TcMember $d 'IsForwardingEnabled') -and [bool](Get-TcMember $s 'IsUnansweredEnabled') -eq [bool](Get-TcMember $d 'IsUnansweredEnabled') -and @((Get-TcMember $s 'Delegates')).Count -eq @((Get-TcMember $d 'Delegates')).Count) } ` -Block { param($a) $s = (Get-SourceSetting -Source $a.data.Source -Accounts $a.data.Accounts)[$a.data.SourceAccount.ToLowerInvariant()] $id = $a.data.Target if ((Get-TcMember $s 'IsForwardingEnabled')) { $p = @{ Identity = $id; IsForwardingEnabled = $true; ForwardingType = (Get-TcText $s 'ForwardingType'); ForwardingTargetType = (Get-TcText $s 'ForwardingTargetType') } $target = ConvertTo-TargetValue -Target ((Get-TcText $s 'ForwardingTarget')) -Source $a.data.Source if ((Get-TcMember $s 'ForwardingTarget') -and -not $target) { Write-TcRemediationAlert ("{0}: forwarding target {1} has no match in the target, forwarding not carried over" -f $id, (Get-TcMember $s 'ForwardingTarget')) } else { if ($target) { $p.ForwardingTarget = $target } Invoke-TcServiceCommand -Tenant $a.tenant -Service Teams -Command 'Set-CsUserCallingSettings' -Parameters $p | Out-Null } } if ((Get-TcMember $s 'IsUnansweredEnabled')) { $p = @{ Identity = $id; IsUnansweredEnabled = $true; UnansweredTargetType = (Get-TcText $s 'UnansweredTargetType'); UnansweredDelay = (Get-TcText $s 'UnansweredDelay') } $target = ConvertTo-TargetValue -Target ((Get-TcText $s 'UnansweredTarget')) -Source $a.data.Source if ((Get-TcMember $s 'UnansweredTarget') -and -not $target) { Write-TcRemediationAlert ("{0}: unanswered target {1} has no match in the target, setting not carried over" -f $id, (Get-TcMember $s 'UnansweredTarget')) } else { if ($target) { $p.UnansweredTarget = $target } Invoke-TcServiceCommand -Tenant $a.tenant -Service Teams -Command 'Set-CsUserCallingSettings' -Parameters $p | Out-Null } } foreach ($x in @((Get-TcMember $s 'Delegates'))) { $target = ConvertTo-TargetValue -Target ((Get-TcText $x 'Id')) -Source $a.data.Source if (-not $target) { Write-TcRemediationAlert ("{0}: delegate {1} has no match in the target, delegation not carried over" -f $id, (Get-TcMember $x 'Id')); continue } Invoke-TcServiceCommand -Tenant $a.tenant -Service Teams -Command 'New-CsUserCallingDelegate' -Parameters @{ Identity = $id; Delegate = $target; MakeCalls = [bool](Get-TcMember $x 'MakeCalls'); ReceiveCalls = [bool](Get-TcMember $x 'ReceiveCalls'); ManageSettings = [bool](Get-TcMember $x 'ManageSettings'); PickUpHeldCalls = [bool](Get-TcMember $x 'PickUpHeldCalls'); JoinActiveCalls = [bool](Get-TcMember $x 'JoinActiveCalls') } | Out-Null $a.undo = @($a.undo) + @(@{ command = 'Remove-CsUserCallingDelegate'; parameters = @{ Identity = $id; Delegate = $target } }) } if (@((Get-TcMember $s 'CallGroupTargets')).Count) { Write-TcRemediationAlert ("{0}: call group to be redone by the user in Teams" -f $id) } } } Write-TcRemediationNote ("{0} user(s) ready: account present in the target and number assigned" -f $ready) Add-TcManualAction -Tenant $t -Object "Calling settings" -Description ("Warn the {0} user(s) whose calling settings will be reproduced" -f $rows.Count) ` -Instruction @("These settings belong to the user: warn them before changing anything.", 'A target left on a number or an account of the source makes the forwarding fail.') } Invoke-TcRemediationPlan -Verify { param($t) $n = 0; $gaps = 0 foreach ($a in $script:TcRemediationRun['Actions'] | Where-Object { (Get-TcMember $_ 'type') -eq 'Block' -and (Get-TcMember (Get-TcMember $_ 'data') 'Source') -eq $t }) { $n++ $s = (Get-SourceSetting -Source $t -Accounts $a.data.Accounts)[$a.data.SourceAccount.ToLowerInvariant()] $d = Invoke-TcServiceCommand -Tenant 'Target' -Service Teams -Command 'Get-CsUserCallingSettings' -Parameters @{ Identity = $a.data.Target } if ([bool](Get-TcMember $s 'IsForwardingEnabled') -ne [bool](Get-TcMember $d 'IsForwardingEnabled') -or [bool](Get-TcMember $s 'IsUnansweredEnabled') -ne [bool](Get-TcMember $d 'IsUnansweredEnabled')) { $gaps++ } } if ($gaps) { New-TcRemediationResult Warning ("{0} user(s) out of {1} still differ from the source" -f $gaps, $n) } elseif ($n) { New-TcRemediationResult OK ("{0} user(s) match the source" -f $n) } } Close-TcRemediation |