Last active
April 15, 2025 10:26
-
-
Save mozziemozz/ce70f39f720bf17632f60a3d6b1be110 to your computer and use it in GitHub Desktop.
Remotely change the opt in status of a Teams Call Queue Agent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$false)][String]$UserId, # AAD User Object Id | |
[Parameter(Mandatory=$false)][String]$UserName, # AAD User Name | |
[Parameter(Mandatory=$false)][String]$TenantName, #your primary domain or *.onmicrosoft.com domain | |
[Parameter(Mandatory=$false)][String]$CallQueueId, # Call Queue Id | |
[Parameter(Mandatory=$false)][ValidateSet("OptIn","OptOut")][String]$Action, | |
[Parameter(Mandatory=$false)][Switch]$QueryStatusOnly, | |
[Parameter(Mandatory=$false)][Switch]$MFA | |
) | |
if (Test-Path ".\creds_$UserName.txt") { | |
$passwordHash = Get-Content -Path ".\creds_$UserName.txt" | |
$secureStringPassword = $passwordHash | ConvertTo-SecureString | |
$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStringPassword)) | |
} | |
else { | |
$secureStringPassword = Read-Host "Please enter the password you would like to encrypt." -AsSecureString | |
$passwordHash = $secureStringPassword | ConvertFrom-SecureString | |
Set-Content -Path ".\creds_$UserName.txt" -Value $passwordHash | |
$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStringPassword)) | |
} | |
if ($MFA) { | |
if (Test-Path ".\mfa_$UserName.txt") { | |
$passwordHash = Get-Content -Path ".\mfa_$UserName.txt" | |
$secureStringPassword = $passwordHash | ConvertTo-SecureString | |
$secret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStringPassword)) | |
} | |
else { | |
$secureStringPassword = Read-Host "Please enter the mfa secret you would like to encrypt." -AsSecureString | |
$passwordHash = $secureStringPassword | ConvertFrom-SecureString | |
Set-Content -Path ".\mfa_$UserName.txt" -Value $passwordHash | |
$secret = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStringPassword)) | |
} | |
} | |
try { | |
if (Test-Path ".\token_$UserName.txt") { | |
$AADBearerToken = Get-Content -Path ".\token_$UserName.txt" | |
$Headers = @{ | |
Authorization = $AADBearerToken | |
} | |
} | |
else { | |
$Headers = $null | |
} | |
Invoke-RestMethod -Uri "https://api.interfaces.records.teams.microsoft.com/Teams.VoiceApps/cq-agents/$userId" -Method Get -Headers $Headers -ContentType "application/json" -ErrorAction Stop > $null | |
Write-Host "Token is valid." -ForegroundColor Green | |
} | |
catch { | |
Write-Host "Token does not exist or is expired. Acquiring new one... Please log in with your account..." -ForegroundColor Yellow | |
$SendKeys = { | |
param( | |
[Parameter(Mandatory=$false)][String]$UserName, | |
[Parameter(Mandatory=$false)][String]$Password, | |
[Parameter(Mandatory=$false)][String]$secret | |
) | |
$wshell = New-Object -ComObject wscript.shell | |
$wshell.AppActivate('AAD User Login') | |
Start-Sleep 3 | |
$wshell.SendKeys("$username~") | |
Start-Sleep 3 | |
$wshell.SendKeys("$password~") | |
if ($secret) { | |
Start-Sleep 3 | |
$otpGenerationScript = (New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/mozziemozz/TOTPPowerShellModule/master/TOTP/totp.ps1").Replace("New-Alias -Name otp -Value Get-Otp","Get-Otp -SECRET $secret") | |
$otp = Invoke-Expression $otpGenerationScript | |
Start-Sleep 3 | |
$wshell.SendKeys("$otp~") | |
} | |
Start-Sleep 3 | |
$wshell.SendKeys("~") | |
} | |
Start-Job -ScriptBlock $SendKeys -ArgumentList $UserName, $Password, $secret | |
Add-Type -AssemblyName System.Web | |
$WebResource = "https://api.interfaces.records.teams.microsoft.com" | |
$redirectUrl = "https://teams.microsoft.com/go" | |
$client_id = "5e3ce6c0-2b1f-4285-8d4b-75ee78787346" | |
$scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239%2F.default%20openid%20profile" | |
$nonce = [guid]::NewGuid().GUID | |
$url = "https://login.microsoftonline.com/$TenantName/oauth2/authorize?response_type=token&scope=$scope&redirect_uri=" + | |
[System.Web.HttpUtility]::UrlEncode($redirectUrl) + | |
"&client_id=$client_id" + | |
"&prompt=login" + "&nonce=$nonce" + "&resource=" + [System.Web.HttpUtility]::UrlEncode($WebResource) + "&state=12345" #here | |
Add-Type -AssemblyName System.Windows.Forms | |
$form = New-Object -TypeName System.Windows.Forms.Form -Property @{ Width = 440; Height = 640 } | |
$web = New-Object -TypeName System.Windows.Forms.WebBrowser -Property @{ Width = 420; Height = 600; Url = ($url) } | |
$DocComp = { | |
$Global:uri = $web.Url.AbsoluteUri | |
if ($Global:Uri -match "error=[^&]*|access_token=[^&]*") { $form.Close() } | |
} | |
$web.ScriptErrorsSuppressed = $true | |
$web.Add_DocumentCompleted($DocComp) | |
$form.Controls.Add($web) | |
$form.Text = "AAD User Login" | |
$form.Add_Shown({ $form.Activate() }) | |
$form.ShowDialog() | Out-Null | |
$Script:Token = [Web.HttpUtility]::ParseQueryString(($web.Url -replace '^.*?(access_token.+)$','$1'))['access_token'] | |
$AADBearerToken = ('Bearer {0}' -f $Script:Token) | |
#$AADBearerToken | |
Set-Content -Path ".\token_$UserName.txt" -Value $AADBearerToken | |
$Headers = @{ | |
Authorization = $AADBearerToken | |
} | |
} | |
if ($QueryStatusOnly) { | |
# Get Opt In Status | |
$RequestGet = (Invoke-RestMethod -Uri "https://api.interfaces.records.teams.microsoft.com/Teams.VoiceApps/cq-agents/$userId" -Method Get -Headers $Headers -ContentType "application/json").AgentCallQueuesSettings | |
$RequestGet | Where-Object {$_.Id -eq $callQueueId} | |
} | |
else { | |
# Get Opt In Status | |
$RequestGet = (Invoke-RestMethod -Uri "https://api.interfaces.records.teams.microsoft.com/Teams.VoiceApps/cq-agents/$userId" -Method Get -Headers $Headers -ContentType "application/json").AgentCallQueuesSettings | |
$cqFriendlyName = ($RequestGet | Where-Object {$_.Id -eq $callQueueId}).Name | |
switch ($Action) { | |
OptIn { | |
$setAction = $true | |
$setActionFriendly = "opted in" | |
} | |
OptOut { | |
$setAction = $false | |
$setActionFriendly = "opted out" | |
} | |
Default {} | |
} | |
if (($RequestGet | Where-Object {$_.Id -eq $CallQueueId}).OptIn -eq $setAction) { | |
if ($setAction -eq $true) { | |
Write-Host "User already $setActionFriendly for $cqFriendlyName." -ForegroundColor Yellow | |
} | |
else { | |
Write-Host "User already $setActionFriendly for $cqFriendlyName." -ForegroundColor Yellow | |
} | |
} | |
else { | |
($RequestGet | Where-Object {$_.Id -eq $callQueueId}).OptIn = $setAction | |
$payload = $RequestGet | ConvertTo-Json | |
# Set Opt In Status | |
try { | |
Invoke-RestMethod -Uri "https://api.interfaces.records.teams.microsoft.com/Teams.VoiceApps/cq-agents/$userId" -Body $payload -Method Put -Headers $Headers -ContentType "application/json" | |
Write-Host "User successfully $setActionFriendly for $cqFriendlyName." -ForegroundColor Green | |
} | |
catch { | |
Write-Host "Error while changing user to $setActionFriendly for $cqFriendlyName." -ForegroundColor Red | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment