# SetupVodiaTeamsDirectRouting.ps1 # Vodia Teams Direct Routing Setup $ErrorActionPreference = "Stop" $script:GraphConnected = $false function Press-Continue { while ($true) { $r = (Read-Host "Press C to continue or Q to quit").ToUpper() switch ($r) { "C" { return } "Q" { exit } } } } function Ensure-NuGet { if (-not (Get-PackageProvider NuGet -ErrorAction SilentlyContinue)) { Write-Host "Installing NuGet provider..." -ForegroundColor Yellow Install-PackageProvider -Name NuGet -Force } } function Ensure-Module { param( [string]$Name ) if (-not (Get-Module -ListAvailable -Name $Name)) { Write-Host "" Write-Host "Installing module $Name..." -ForegroundColor Yellow Install-Module ` -Name $Name ` -Scope CurrentUser ` -Force ` -AllowClobber Write-Host "$Name installed." -ForegroundColor Green } } function Connect-TeamsServices { Ensure-NuGet try { Set-PSRepository ` -Name PSGallery ` -InstallationPolicy Trusted ` -ErrorAction SilentlyContinue } catch {} Ensure-Module MicrosoftTeams Import-Module MicrosoftTeams Write-Host "" Write-Host "Connecting to Microsoft Teams..." Write-Host "Complete MFA if prompted." Connect-MicrosoftTeams $tenant = Get-CsTenant Write-Host "" Write-Host "Connected to Teams." -ForegroundColor Green if ($tenant.DisplayName) { Write-Host "Tenant: $($tenant.DisplayName)" } } function Connect-GraphIfNeeded { if ($script:GraphConnected) { return } Ensure-Module Microsoft.Graph.Users Ensure-Module Microsoft.Graph.Identity.DirectoryManagement Import-Module Microsoft.Graph.Users Import-Module Microsoft.Graph.Identity.DirectoryManagement Write-Host "" Write-Host "Connecting to Microsoft Graph..." Write-Host "Complete MFA if prompted." Connect-MgGraph ` -Scopes ` "User.ReadWrite.All", ` "Directory.ReadWrite.All", ` "Organization.Read.All" $script:GraphConnected = $true Write-Host "Microsoft Graph connected." -ForegroundColor Green } function Get-GatewayName { while ($true) { Write-Host "" Write-Host "The DNS name must resolve." Write-Host "The resolved address should point to the Vodia PBX." $fqdn = Read-Host "Enter PSTN Gateway DNS Name" try { $dns = Resolve-DnsName ` -Name $fqdn ` -Type A ` -ErrorAction Stop Write-Host "" Write-Host "DNS Resolution Successful" -ForegroundColor Green foreach ($ip in $dns.IPAddress) { Write-Host "IP: $ip" } Press-Continue return $fqdn } catch { Write-Host "" Write-Host "DNS resolution failed." -ForegroundColor Red Press-Continue } } } function Ensure-Gateway { param( [string]$GatewayFqdn ) $existing = Get-CsOnlinePSTNGateway ` -Identity $GatewayFqdn ` -ErrorAction SilentlyContinue if ($existing) { Write-Host "" Write-Host "Gateway already exists." -ForegroundColor Yellow Write-Host "No changes will be made." return } try { Write-Host "" Write-Host "Creating PSTN Gateway..." New-CsOnlinePSTNGateway ` -Fqdn $GatewayFqdn ` -SipSignalingPort 5061 ` -Enabled $true ` -MediaBypass $false Write-Host "Gateway created." -ForegroundColor Green } catch { Write-Host "" Write-Host "Gateway creation failed." -ForegroundColor Red Write-Host $_.Exception.Message Press-Continue } } function Ensure-Usage { param( [string]$UsageName ) $usage = Get-CsOnlinePstnUsage if ($usage.Usage -contains $UsageName) { Write-Host "$UsageName already exists." -ForegroundColor Yellow return } Set-CsOnlinePstnUsage ` -Identity Global ` -Usage @{ Add = $UsageName } Write-Host "$UsageName created." -ForegroundColor Green } function Ensure-Route { param( [string]$RouteName, [string]$UsageName, [string]$GatewayFqdn ) $route = Get-CsOnlineVoiceRoute ` -Identity $RouteName ` -ErrorAction SilentlyContinue if ($route) { Write-Host "$RouteName already exists." -ForegroundColor Yellow Write-Host "No changes will be made." return } New-CsOnlineVoiceRoute ` -Identity $RouteName ` -NumberPattern ".*" ` -OnlinePstnUsages $UsageName ` -OnlinePstnGatewayList $GatewayFqdn Write-Host "$RouteName created." -ForegroundColor Green } function Ensure-Policy { param( [string]$PolicyName, [string]$UsageName ) $policy = Get-CsOnlineVoiceRoutingPolicy ` -Identity $PolicyName ` -ErrorAction SilentlyContinue if ($policy) { Write-Host "$PolicyName already exists." -ForegroundColor Yellow Write-Host "No changes will be made." return } New-CsOnlineVoiceRoutingPolicy ` -Identity $PolicyName ` -OnlinePstnUsages $UsageName Write-Host "$PolicyName created." -ForegroundColor Green } function Show-Users { Connect-GraphIfNeeded Get-MgUser -All | Select-Object DisplayName,UserPrincipalName | Sort-Object DisplayName | Format-Table -AutoSize } function Show-Licenses { Connect-GraphIfNeeded Get-MgSubscribedSku | Select-Object ` SkuPartNumber, ConsumedUnits, @{Name="Available";Expression={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}}, SkuId | Format-Table -AutoSize } function Assign-License { Connect-GraphIfNeeded $upn = Read-Host "Enter User UPN" $licenses = Get-MgSubscribedSku $licenses | Select-Object SkuPartNumber,SkuId | Format-Table -AutoSize $skuName = Read-Host "Enter SkuPartNumber" $sku = $licenses | Where-Object { $_.SkuPartNumber -eq $skuName } if (-not $sku) { Write-Host "SKU not found." -ForegroundColor Red return } Set-MgUserLicense ` -UserId $upn ` -AddLicenses @( @{ SkuId = $sku.SkuId } ) ` -RemoveLicenses @() Write-Host "License assigned." -ForegroundColor Green } function Assign-Policy { param( [string]$PolicyName ) $upn = Read-Host "Enter User UPN" Grant-CsOnlineVoiceRoutingPolicy ` -Identity $upn ` -PolicyName $PolicyName Write-Host "$PolicyName assigned." -ForegroundColor Green } # ===================================================== # MAIN # ===================================================== try { Write-Host "" Write-Host "Vodia Teams Direct Routing Setup" Write-Host "" Connect-TeamsServices $GatewayFqdn = Get-GatewayName $Prefix = $GatewayFqdn.Split(".")[0] $RouteName = "Route-$Prefix" $UsageName = "Usage-$Prefix" $PolicyName = "Policy-$Prefix" Write-Host "" Write-Host "Configuration Names" Write-Host "-------------------" Write-Host "Gateway : $GatewayFqdn" Write-Host "Route : $RouteName" Write-Host "Usage : $UsageName" Write-Host "Policy : $PolicyName" Ensure-Gateway ` -GatewayFqdn $GatewayFqdn Ensure-Usage ` -UsageName $UsageName Ensure-Route ` -RouteName $RouteName ` -UsageName $UsageName ` -GatewayFqdn $GatewayFqdn Ensure-Policy ` -PolicyName $PolicyName ` -UsageName $UsageName while ($true) { Write-Host "" Write-Host "====================================" Write-Host "1 - List Users" Write-Host "2 - List Licenses" Write-Host "3 - Assign License" Write-Host "4 - Assign Routing Policy" Write-Host "5 - Assign License and Policy" Write-Host "Q - Quit" Write-Host "====================================" Write-Host "" Write-Host "You may also assign licenses and routing" Write-Host "policies through the Teams Admin Center" Write-Host "or Microsoft 365 Admin Center." Write-Host "" $selection = (Read-Host "Selection").ToUpper() switch ($selection) { "1" { Show-Users } "2" { Show-Licenses } "3" { Assign-License } "4" { Assign-Policy -PolicyName $PolicyName } "5" { Assign-License Assign-Policy -PolicyName $PolicyName } "Q" { break } default { Write-Host "Invalid selection." } } } } finally { try { Disconnect-MicrosoftTeams } catch {} try { Disconnect-MgGraph } catch {} }