Skype for Business Server 2019 control panel authentication script
Following are the authentication related helper scripts for Modern Admin Control Panel (MACP).
Configure MACP authentication with Microsoft 365 or Office 365
This script should be run after installing Skype for Business Server 2019 Cumulative Update 1 or later, as part of the set-up for the new Control Panel.
Note
Azure AD Powershell is planned for deprecation on March 30, 2024. To learn more, read the deprecation update.
We recommend migrating to Microsoft Graph PowerShell to interact with Microsoft Entra ID (formerly Azure AD). Microsoft Graph PowerShell allows access to all Microsoft Graph APIs and is available on PowerShell 7. For answers to common migration queries, see the Migration FAQ.
<#
.SYNOPSIS
Helper script to configure SFB 2019 control panel authentication with Office 365 via OAuth protocol. This script will create an Azure AD Application on Azure. This will help in signing into Microsoft 365 or Office 365 using OAuth in the new Control Panel.
.DESCRIPTION
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.EXAMPLE
Creates a native client application on azure active directory with name "MACP"
#>
Write-Host "Getting external FQDN of SFB pools"
$externalFqdns = (Get-CsService -WebServer).ExternalFqdn
Write-Host "Getting internal FQDN of SFB pools"
$internalFqdns = (Get-csService -WebServer).poolfqdn
$replyUrls = New-Object System.Collections.Generic.List[string]
Write-Host "Generating Redirect URIs for modern admin control panel"
#Generating replyUrls using external fqdns
foreach ($externalFqdn in $externalFqdns) {
if ($externalFqdn -ne $null) {
$replyUrls.Add('https://' + $externalFqdn + '/macp/iframe.html');
}
}
#Generating replyUrls using internal fqdns
foreach($internalFqdn in $internalFqdns) {
if ($internalFqdn -ne $null) {
$replyUrls.Add('https://' + $internalFqdn + '/macp/iframe.html');
}
}
$simplifiedUrl = Read-Host -Prompt "Enter Admin Control Panel application's simplified URL eg. https://admin.contoso.com. Press Enter to skip "
if (![string]::IsNullOrWhiteSpace($simplifiedUrl))
{
if ($simplifiedUrl.StartsWith('http://'))
{
$simplifiedUrl = $simplifiedUrl.Replace('http://', '')
}
if (!$simplifiedUrl.StartsWith('https://'))
{
$simplifiedUrl = "https://" + $simplifiedUrl
}
$simplifiedUrl = $simplifiedUrl.TrimEnd('/')
$replyUrls.Add($simplifiedUrl + '/macp/iframe.html')
}
if (Get-Module -ListAvailable -Name "AzureAd") {
Write-Host "AzureAD module exists"
}
else {
Write-Host "Installing AzureAD module";
Install-Module -name AzureAD
}
$uniqueReplyUrls = $replyUrls | sort -Unique
#Importing AzureAd module
Write-Host "Importing AzureAD module";
Import-module AzureAD
Write-Host "Connect to Azure AD using your azure tenant admin credentials"
Connect-azureAd
# Resource: https://api.interfaces.records.teams.microsoft.com/user_impersonation
$requiredResourceAccess1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$requiredResourceAccess1.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "e60370c1-e451-437e-aa6e-d76df38e5f15","Scope"
$requiredResourceAccess1.ResourceAppId = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239"
# Resource: https://graph.microsoft.com/User.Read
$requiredResourceAccess2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$requiredResourceAccess2.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "e1fe6dd8-ba31-4d61-89e7-88639da4683d","Scope"
$requiredResourceAccess2.ResourceAppId = "00000003-0000-0000-c000-000000000000"
$requiredResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess]
$requiredResourceAccess.Add($requiredResourceAccess1)
$requiredResourceAccess.Add($requiredResourceAccess2)
$azureADApplication = Get-AzureADApplication -Filter "DisplayName eq 'MACP'"
if ($azureADApplication -eq $null) {
Write-Host "Creating Azure AD application for modern admin control panel (MACP)"
$azureADApplication = New-AzureADApplication -DisplayName "MACP" -PublicClient $true -Oauth2AllowImplicitFlow $true -ReplyUrls $uniqueReplyUrls -RequiredResourceAccess $requiredResourceAccess
}
else {
Write-Host "Azure ad application for modern admin control panel (MACP) already exists with displayName: " $azureADApplication.DisplayName ". Updating the properties"
Write-Host $uniqueReplyUrls
Set-AzureADApplication -ObjectId $azureADApplication.ObjectId -PublicClient $true -Oauth2AllowImplicitFlow $true -ReplyUrls $uniqueReplyUrls -RequiredResourceAccess $requiredResourceAccess
}
Write-Host "Updating the AzureAD application Id in CMS"
Set-CsHybridConfiguration -ClientId $azureADApplication.AppId
Configure MACP application in ADFS Farm
This script should be run after installing Skype for Business Server 2019 latest Cumulative Update, as part of the set-up for the new Control Panel.
<#
.SYNOPSIS
Helper script to configure MACP Application in ADFS Farm.
.DESCRIPTION
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.EXAMPLE
Creates an application in ADFS Farm with name "MACPApp"
#>
$confirmation = Read-Host -Prompt "Are you running this script on an ADFS Farm server. Confirm[y/n]"
if ($confirmation -match '[^yY]')
{
if ($confirmation -match '[nN]')
{
Write-Host "`n`rPlease run this script only on ADFS Farm servers." -ForeGroundColor Red
}
else
{
Write-Host "`n`rInvalid Input." -ForeGroundColor Red
}
Write-Host "`n`rAborting Process." -ForeGroundColor Red
return
}
Write-Host "ADFS application group and native client application for Admin Control Panel can be setup only on ADFS Farm servers running on Windows Server 2016 or above. Checking the current server version ..."
$version = [System.Environment]::OSVersion.Version.Major
# Version reference for Windows Server here:
# https://learn.microsoft.com/windows/win32/sysinfo/operating-system-version
if ($version -lt 10)
{
Write-Host "`n`rInvalid Window Server version. Please run this script on ADFS farm servers running on Windows Server 2016 or above." -ForeGroundColor Red
return
}
Write-Host "Valid Windows Server Version." -ForeGroundColor Green
Write-Host "`n`rCreating an ADFS application group and native client application for Admin Control Panel in the ADFS Farm."
# Creating ApplicationGroup.
$groupName = Read-Host -Prompt "Enter ADFS Application Group Name for Admin Control Panel. Press enter to use default name as 'MACP' "
if([string]::IsNullOrWhiteSpace($groupName))
{
$groupName = "MACP"
}
try
{
New-AdfsApplicationGroup -Name $groupName
}
catch
{
Write-Error "`nError in creating Application Group $groupName. Please ensure that you have enabled and configured WindowsFeature ADFS-Federation for this server. Aborting Process."
throw
exit
}
# Creating a new native MACP App under above Application Group.
$appName = Read-Host -Prompt "Enter Admin Control Panel Application Name. Press ENTER to use default name as 'MACPApp' "
if([string]::IsNullOrWhiteSpace($appName))
{
$appName = "MACPApp"
}
$clientIdentifier = [guid]::NewGuid()
$computerDetails = Get-WmiObject win32_computersystem
if (($computerDetails -eq $null) -OR
($computerDetails.DNSHostName -eq $null) -OR
($computerDetails.Domain -eq $null))
{
# Unable to find computer details.
# We will return false in that case.
Write-Error "`nUnable to find host and domain details. Aborting process."
return
}
$defaultDomain = $computerDetails.Domain
$domain = Read-Host -Prompt "Enter Admin Control Panel application's domain name e.g. contoso.com. Press ENTER to keep $defaultDomain"
if([string]::IsNullOrWhiteSpace($domain))
{
$domain = $defaultDomain
}
$extDomain = Read-Host -Prompt "Enter Admin Control Panel application's external domain name if its different from $domain or else ADFS OAuth wouldn't work for external website for Admin Control Panel "
[string[]] $poolList= @()
$poolList = (Read-Host -Prompt "Enter all the front end pool names in a comma separated manner without the domain name e.g. pool0,pool1,pool2 etc")
$poolList = $poolList.Split(',').Split(' ')
if($poolList.Count -eq 0)
{
Write-Error "`nAt least 1 pool machine name is mandatory. Please run the script again once you are ready with the names. Deleting $groupName."
Remove-AdfsApplicationGroup -TargetApplicationGroupIdentifier $groupName
exit
}
foreach($poolName in $poolList)
{
if ($poolName -match "^(\w+).$domain$" -or `
(![string]::IsNullOrWhiteSpace($extDomain) -and `
$poolName -match "^(\w+).$extDomain$"))
{
Write-Error "Enter pool name $poolName without domain name."
Remove-AdfsApplicationGroup -TargetApplicationGroupIdentifier $groupName
exit
}
}
[string[]] $redirectUrls = @()
foreach ($poolName in $poolList)
{
$redirectUrls += "https://" + $poolName + "." + $domain + "/macp/login"
$redirectUrls += "https://" + $poolName + "." + $domain + "/macp/logout"
$redirectUrls += "https://" + $poolName + "." + $domain + "/macp/portal_oauth_iframe.html"
if (![string]::IsNullOrWhiteSpace($extDomain))
{
$redirectUrls += "https://" + $poolName + "." + $extDomain + "/macp/login"
$redirectUrls += "https://" + $poolName + "." + $extDomain + "/macp/logout"
$redirectUrls += "https://" + $poolName + "." + $extDomain + "/macp/portal_oauth_iframe.html"
}
}
# Handling entry for simplifiedUrl.
$simplifiedUrl = Read-Host -Prompt "Enter Admin Control Panel application's simplified URL eg. https://admin.contoso.com. Press ENTER to skip "
if (![string]::IsNullOrWhiteSpace($simplifiedUrl))
{
if ($simplifiedUrl.StartsWith('http://'))
{
$simplifiedUrl = $simplifiedUrl.Replace('http://', '')
}
if (!$simplifiedUrl.StartsWith('https://'))
{
$simplifiedUrl = "https://" + $simplifiedUrl
}
$simplifiedUrl = $simplifiedUrl.TrimEnd('/')
$redirectUrls += $simplifiedUrl + "/login"
$redirectUrls += $simplifiedUrl + "/logout"
$redirectUrls += $simplifiedUrl + "/macp/portal_oauth_iframe.html"
}
try
{
Add-AdfsNativeClientApplication -ApplicationGroupIdentifier $groupName -Name $appName -Identifier $clientIdentifier -RedirectUri $redirectUrls
}
catch
{
Write-Error "`nUnable to create Admin Control Panel Native Client App. Deleting $groupName. Aborting process."
Remove-AdfsApplicationGroup -TargetApplicationGroupIdentifier $groupName
throw
exit
}
Write-Host "`nAdmin Control panel Native App created successfully with client Id: $clientIdentifier." -ForeGroundColor Green
Write-Host "`nDetails of the App are:`n"
Get-AdfsNativeClientApplication -Identifier $clientIdentifier
Configure OAuth for MACP
This script should be run after installing Skype for Business Server 2019 latest Cumulative Update, as part of the set-up for the new Control Panel.
<#
.SYNOPSIS
Helper script to configure SFB 2019 control panel with ADFS OAuth.
.DESCRIPTION
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE IS MADE AVAILABLE AS IS, WITHOUT WARRANTY OF ANY KIND. THE ENTIRE RISK
OF THE USE OR THE RESULTS FROM THE USE OF THIS CODE REMAINS WITH THE USER.
.PARAMETER AdfsClientId
Specify the client identifier application created for the admin control panel in the ADFS.
.PARAMETER AdfsMetadataPublicUri
OAuth metadata public URI for the admin control panel in the ADFS.
.PARAMETER AdfsIssuerName
Issuer Name for the admin control panel in the ADFS.
.PARAMETER AdfsOAuthInstance
ADFS farm instance (FQDN) where the admin control panel is registered for ADFS OAuth.
.PARAMETER SimplifiedUrlPrefix
The Simple URL prefix .
.PARAMETER Pools
List of pool names in which ADFS OAuth is to be setup for the admin control panel in a comma separated format. By default OAuth will setup for all FE pools deployed with Skype for Business 2019.
#>
function GetCurrentPoolName($computerDetails)
{
$computerDnsHostName = $computerDetails.DNSHostName
$domainName = $computerDetails.Domain
$computerFqdn = $computerDnsHostName + "." + $domainName
$poolName = (Get-CsComputer -Identity $computerFqdn).Pool
return $poolName
}
function GetAllSfBW17Pools()
{
$allFEPools = Get-csservice -Registrar | Where-Object {$_.Version -gt 7}
$poolNamesArray = @()
foreach ($pool in $allFEPools)
{
$poolNamesArray += ($pool.PoolFqdn)
}
return $poolNamesArray
}
function GeneratePoolNameArray($pools, $computerDetails)
{
$poolNames = $pools.Split(',')
$poolNamesArray = @()
$domainName = $computerDetails.Domain
foreach ($poolName in $poolNames)
{
if ($poolName -match "^(\w+.)$domainName$")
{
$poolNamesArray += ($poolName)
}
else
{
$poolNamesArray += ($poolName + "." + $domainName)
}
}
return $poolNamesArray
}
function VerifyRoleAndVersionOfSelectedPools($poolArrays)
{
foreach ($poolName in $poolArrays)
{
$services = Get-CsService -PoolFqdn $poolName
if ($services -eq $null)
{
# Unable to find services for this pool.
# We will mark it as not a Front-End machine.
Write-Error "Didn't find any Services on Pool : $poolName"
return $false
}
$found = $false
foreach ($service in $services)
{
# Performing a case insensitive search here.
if ($service.Role.ToLower().Equals("registrar") -AND
$service.Version -gt 7)
{
# Found the Registrar role for the pool.
# Hence, a Front-End machine.
$found = $true
break
}
}
if ($found -eq $false)
{
Write-Error "Pool : $poolName is not Front End pool. Aborting process."
return $false
}
}
return $true
}
function VerifyMacpVersionOnFrontEndPools($cred, $pools, $macpRegistryPath, $minVersion)
{
$returnVal = $true
foreach ($poolName in $pools)
{
$computers = (Get-CsComputer -Pool $poolName).Identity
$versionString = $null
foreach ($computer in $computers)
{
$psSession = New-PSSession -computerName $computer -credential $cred
$currentVersionStr = Invoke-Command -Session $psSession -ArgumentList $macpRegistryPath -ScriptBlock {
param($macpRegistryPath)
Get-ItemPropertyValue -Path $macpRegistryPath -Name "Version"
}
if ($psSession)
{
Remove-PSSession -Session $psSession
}
if (!$currentVersionStr)
{
Write-Error "Could not fetch current version of Admin Control Panel on $computer. Please check your connection or the credentials provided. Aborting process."
$returnVal = $false;
}
else
{
Write-Host "`n`rInstalled version of Admin Control Panel on $computer : $currentVersionStr"
if ($versionString -eq $null)
{
$versionString = $currentVersionStr
}
else
{
if ($currentVersionStr -ne $versionString)
{
Write-Error "Product version doesn't match across servers in Front-End pool: $poolName"
$returnVal = $false
}
}
if (([System.Version]$currentVersionStr -lt [System.Version]$minVersion) -OR
([System.Version]$currentVersionStr -eq [System.Version]$minVersion))
{
Write-Error "Install updates on Server: $computer in Front-End pool : $poolName to active ADFS OAuth Support for Admin Control Panel."
$returnVal = $false
}
}
if ($returnVal -eq $false)
{
break
}
}
}
return $returnVal
}
function GetEditedFileContentForWebConfig($disableAdfsOAuth, $relativePath, $macpRegistryPath, $adfsClientId, $adfsMetadataPublicUri, $adfsIssuerName, $adfsOAuthInstance)
{
$installDir = Get-ItemPropertyValue -Path $macpRegistryPath -Name "InstallDir"
$filePath = Join-Path -Path $installDir -ChildPath $relativePath
$fileContent = Get-Content -Path $filePath
# We handle the case of replace the vdirAuth for web.config.
# If the search string is not found or more than one instance is found we simply skip.
$webConfigVdirSearchStr = $fileContent -match "<vdirAuth authType(.*)"
if ($webConfigVdirSearchStr.Length -eq 1)
{
$searchVal = $webConfigVdirSearchStr[0]
$searchedStrTrimmed = $searchVal.Trim()
$adfsOAuthLineMatch = $fileContent -match "<adfsOAuth (.*)"
if ($adfsOAuthLineMatch.Length -eq 1)
{
$adfsOAuthStr = $adfsOAuthLineMatch[0]
$fileContent = $fileContent.Replace($adfsOAuthStr, '')
}
if ($disableAdfsOAuth -ne $true)
{
# Falling from WebTicket -> ADFSOnPrem,
# Also adding the tokenized adfsOAuth settings entry.
$countOfWhiteSpacesNeeded = $searchVal.Length - $searchedStrTrimmed.Length + 2
$replaceStr = "<vdirAuth authType=`"ADFSOnPrem`">"
$replaceStr = $replaceStr + "`r`n" + $(" " * $countOfWhiteSpacesNeeded) + `
"<adfsOAuth adfsMetadataPublicUri=`"$adfsMetadataPublicUri`" adfsClientId=`"$adfsClientId`" adfsIssuerName=`"$adfsIssuerName`" />"
}
else
{
# Falling back from ADFSOnPrem -> WebTicket,
# Removing the adfsOAuth settings entry.
$replaceStr = "<vdirAuth authType=`"WebTicket`">"
}
$fileContent = $fileContent.Replace($searchedStrTrimmed, $replaceStr)
}
# Removing all empty lines
$fileContent = $fileContent.Where({$_ -ne ''})
return $fileContent
}
function GetEditedFileContentForIndexAspx($disableAdfsOAuth, $relativePath, $macpRegistryPath, $adfsClientId, $adfsOAuthInstance, $simplifiedUrlPrefix)
{
$installDir = Get-ItemPropertyValue -Path $macpRegistryPath -Name "InstallDir"
$filePath = Join-Path -Path $installDir -ChildPath $relativePath
$fileContent = Get-Content -Path $filePath
$patternString = '${{{0}}}'
# Handling replacements back to tokens in index.aspx file
$searchedStr = $fileContent -match "`"instance`": (.*)"
if ($searchedStr.Length -gt 0)
{
foreach ($searchVal in $searchedStr)
{
$matchVal = $searchVal.ToLower().Contains("microsoftonline")
if ($matchVal -eq $false)
{
$newReplacementValue = $patternString -f "AdfsOAuthInstance"
$newStr = "`"instance`": `"$newReplacementValue`","
$fileContent = $fileContent.Replace($searchVal.Trim(), $newStr)
break
}
}
}
$searchedStr = $fileContent -match "`"clientId`": (.*)"
if ($searchedStr.Length -eq 1)
{
$newReplacementValue = $patternString -f "AdfsClientId"
$newStr = "`"clientId`": `"$newReplacementValue`","
$fileContent = $fileContent.Replace($searchedStr[0].Trim(), $newStr)
}
$searchedStr = $fileContent -match "`"adfsOAuthEnabled`": (.*)"
if ($searchedStr.Length -eq 1)
{
$newReplacementValue = $patternString -f "AdfsOAuthEnabled"
$newStr = "`"adfsOAuthEnabled`": `"$newReplacementValue`","
$fileContent = $fileContent.Replace($searchedStr[0].Trim(), $newStr)
}
$searchedStr = $fileContent -match "`"simplifiedUrlPrefix`": (.*)"
if ($searchedStr.Length -eq 1)
{
$newReplacementValue = $patternString -f "SimplifiedUrlPrefix"
$newStr = "`"simplifiedUrlPrefix`": `"$newReplacementValue`","
$fileContent = $fileContent.Replace($searchedStr[0].Trim(), $newStr)
}
$adfsOAuthEnabled = $false
if ($disableAdfsOAuth -ne $true)
{
$fileContent = $fileContent.Replace($patternString -f "AdfsClientId", $adfsClientId)
$fileContent = $fileContent.Replace($patternString -f "AdfsOAuthInstance", $adfsOAuthInstance)
$fileContent = $fileContent.Replace($patternString -f "SimplifiedUrlPrefix", $simplifiedUrlPrefix)
$adfsOAuthEnabled = $true
}
$fileContent = $fileContent.Replace($patternString -f "AdfsOAuthEnabled", $adfsOAuthEnabled)
# Removing all empty lines
$fileContent = $fileContent.Where({$_ -ne ''})
return $fileContent
}
function GenerateHttpsPrefix($inputVal)
{
if ($inputVal.StartsWith('http://'))
{
$inputVal = $inputVal.Replace('http://', '')
}
if (!$inputVal.StartsWith('https://'))
{
$inputVal = "https://" + $inputVal
}
return $inputVal
}
function SetupOAuthOnFrontEndPools($cred, $pools, $macpRegistryPath, $disableAdfsOAuth, $relativePathToContentMap, $adfsClientId, $adfsMetadataPublicUri, $adfsIssuerName, $adfsOAuthInstance)
{
foreach ($poolName in $pools)
{
$computers = (Get-CsComputer -Pool $poolName).Identity
foreach ($computer in $computers)
{
$psSession = New-PSSession -computerName $computer -credential $cred
Invoke-Command -Session $psSession `
-ArgumentList $macpRegistryPath, $disableAdfsOAuth, $relativePathToContentMap, $adfsClientId, `
$adfsMetadataPublicUri, $adfsIssuerName, $adfsOAuthInstance `
-ScriptBlock {
param($macpRegistryPath, $disableAdfsOAuth, $relativePathToContentMap, $adfsClientId, $adfsMetadataPublicUri, $adfsIssuerName, $adfsOAuthInstance)
$installDir = Get-ItemPropertyValue -Path $macpRegistryPath -Name "InstallDir"
foreach ($val in $relativePathToContentMap.GetEnumerator())
{
$relativePath = $($val.Name)
$fileContent = $($val.Value)
$filePath = Join-Path -Path $installDir -ChildPath $relativePath
Set-Content -Path $filePath -Value $fileContent
}
$adfsOAuthEnabled = $true
if ($disableAdfsOAuth -eq $true)
{
$adfsOAuthEnabled = $false
}
Set-ItemProperty -Path $macpRegistryPath -Name "AdfsOAuthEnabled" -Value $adfsOAuthEnabled
Set-ItemProperty -Path $macpRegistryPath -Name "AdfsClientId" -Value $adfsClientId
Set-ItemProperty -Path $macpRegistryPath -Name "AdfsMetadataPublicUri" -Value $adfsMetadataPublicUri
Set-ItemProperty -Path $macpRegistryPath -Name "AdfsIssuerName" -Value $adfsIssuerName
Set-ItemProperty -Path $macpRegistryPath -Name "AdfsOAuthInstance" -Value $adfsOAuthInstance
# Changing the application pool of Macp app to make it same as that of Skype for Business Server Web Site. This is needed for URL rewrite to work in case of Simple URL.
# This is important to note that this change is required only for the Simple URL feature. However, we chose to make this change whenever ADFS is configured.
# This change may not be reverted when we fall back to WebTicket. And that is alright.
Import-Module WebAdministration
Set-ItemProperty -Path 'IIS:\Sites\Skype for Business Server Internal Web Site\Macp' -Name applicationPool -Value LyncIntFeature
Set-ItemProperty -Path 'IIS:\Sites\Skype for Business Server External Web Site\Macp' -Name applicationPool -Value LyncExtFeature
iisreset
}
Remove-PSSession -Session $psSession
}
}
}
# Script execution start
$disableAdfsOAuth = $null
$adfsOAuthInstance = $null
$adfsClientId = $null
$adfsMetadataPublicUri = $null
$adfsIssuerName = $null
$simplifiedUrlPrefix = $null
$pools = $null
$mode = Read-Host -Prompt "Do you want to Enable [e] or Disable [d] ADFS OAuth for Admin Control Panel. Confirm[e/d]"
if([string]::IsNullOrWhiteSpace($mode))
{
$mode = 'e'
}
if ($mode -match '^[eE]$')
{
$disableAdfsOAuth = $false
Write-Host "`n`rStarting script to enable ADFS OAuth." -ForeGroundColor Green
$adfsOAuthInstance = Read-Host -Prompt "Enter the ADFS farm instance (FQDN) where the Admin Control Panel is registered for ADFS OAuth"
$adfsOAuthInstance = GenerateHttpsPrefix -input $adfsOAuthInstance
# Make sure that instance name has a trailing slash
$adfsOAuthInstance = $adfsOAuthInstance.TrimEnd('/') + '/'
$defaultAdfsMetadataPublicUri = $adfsOAuthInstance + 'FederationMetadata/2007-06/FederationMetadata.xml'
$adfsMetadataPublicUri = Read-Host -Prompt "Enter OAuth Metadata Public URI for the Admin Control Panel in the ADFS. Press ENTER to use default $defaultAdfsMetadataPublicUri "
if([string]::IsNullOrWhiteSpace($adfsMetadataPublicUri))
{
$adfsMetadataPublicUri = $defaultAdfsMetadataPublicUri
}
else
{
$adfsMetadataPublicUri = GenerateHttpsPrefix -input $adfsMetadataPublicUri
}
$adfsIssuerNameDefault = $adfsOAuthInstance.TrimEnd('/') + '/adfs'
$adfsIssuerName = Read-Host -Prompt "Enter Issuer Name for the Admin Control Panel in the ADFS. Press ENTER to use default $adfsIssuerNameDefault"
if([string]::IsNullOrWhiteSpace($adfsIssuerName))
{
$adfsIssuerName = $adfsIssuerNameDefault
}
$adfsClientId = Read-Host -Prompt "Enter Client Identifier of the application created for the Admin Control Panel in the ADFS"
if([string]::IsNullOrWhiteSpace($adfsClientId))
{
Write-Host "`n`rClient identifier cannot be empty" -ForeGroundColor Red
Write-Host "`n`rAborting Process." -ForeGroundColor Red
return
}
$simplifiedUrlPrefix = Read-Host -Prompt "Enter the Simple URL prefix for the Admin Control Panel (if configured). Press ENTER to use default 'admin.' "
if([string]::IsNullOrWhiteSpace($simplifiedUrlPrefix))
{
$simplifiedUrlPrefix = 'admin.'
}
}
elseif ($mode -match '^[dD]$')
{
$disableAdfsOAuth = $true
Write-Host "`n`rStarting script to disable ADFS OAuth."-ForeGroundColor Green
}
else
{
Write-Host "`n`rInvalid Input." -ForeGroundColor Red
Write-Host "`n`rAborting Process." -ForeGroundColor Red
return
}
$pool = Read-Host -Prompt "Enter pool names in which ADFS OAuth is to be setup for the admin control panel in a comma separated format. Press ENTER to setup OAuth for all FE pools deployed with Skype for Business 2019"
# This is the registry path for Admin Control Panel for SfB 2019 machines.
$macpRegPath = "HKLM:\SOFTWARE\Microsoft\Real-Time Communications\{D00E3324-D7F8-4735-B4CF-206FE63FD577}"
# This is the min version string above which ADFS OAuth is enabled for Admin Control Panel.
$cu3VersionStr = "7.0.2046.216"
$poolArray=@()
$computerDetails = Get-WmiObject win32_computersystem
if (($computerDetails -eq $null) -OR
($computerDetails.DNSHostName -eq $null) -OR
($computerDetails.Domain -eq $null))
{
# Unable to find computer details.
# We will return false in that case.
Write-Error "Unable to find host and domain details. Aborting process."
return
}
if ($pools -eq $null)
{
$poolName = GetAllSfBW17Pools
if ($poolName.length -eq 0)
{
Write-Error "Error generating list of FE pool FQDN. Aborting process."
return
}
$poolArray += ($poolName)
}
else
{
$poolArray = GeneratePoolNameArray -pools $pools -computerDetails $computerDetails
if ($poolArray.length -eq 0)
{
Write-Error "Error parsing pool names."
return
}
}
$status = VerifyRoleAndVersionOfSelectedPools -poolArray $poolArray
if ($status -eq $false)
{
Write-Error "Not all the pools mentioned are Front end pool or deployed with SfB 2019. Aborting process."
return
}
Write-Host "`n`rStarting modification to all the servers in Skype for Business 2019 FE pools (or Pools mentioned using -Pools parameter). Please provide Administrator credentials."
$cred = Get-Credential
if ($cred -eq $null)
{
Write-Error "Credential is not defined. Aborting process."
return
}
if ($disableAdfsOAuth.Equals($false))
{
$adfsOAuthInstance = GenerateHttpsPrefix -input $adfsOAuthInstance
$adfsMetadataPublicUri = GenerateHttpsPrefix -input $adfsMetadataPublicUri
$adfsIssuerName = GenerateHttpsPrefix -input $adfsIssuerName
# Removing any trailing slash from the issuer name
$adfsIssuerName = $adfsIssuerName.TrimEnd('/')
# Make sure that instance name has a trailing slash
$adfsOAuthInstance = $adfsOAuthInstance.TrimEnd('/') + '/'
}
$status = VerifyMacpVersionOnFrontEndPools -cred $cred -pools $poolArray -macpRegistryPath $macpRegPath -minVersion $cu3VersionStr
if ($status -eq $false)
{
Write-Error "Not all the pools have the required CU installed for MacpWebComponents. Please update to the latest version. Aborting process."
return
}
$internalOcsPswsPath = "Web Components\OcsPsws\Int\"
$externalOcsPswsPath = "Web Components\OcsPsws\Ext\"
$internalMacpPath = "Web Components\Macp\Int\"
$externalMacpPath = "Web Components\Macp\Ext\"
$ocsPswsInternalWebConfigPath = Join-Path -Path $internalOcsPswsPath -ChildPath "web.config"
$ocsPswsExternalWebConfigPath = Join-Path -Path $externalOcsPswsPath -ChildPath "web.config"
$macpInternalIndexAspxPath = Join-Path -Path $internalMacpPath -ChildPath "index.aspx"
$macpExternalIndexAspxPath = Join-Path -Path $externalMacpPath -ChildPath "index.aspx"
$internalOcsPswsWebConfigContent = GetEditedFileContentForWebConfig -disableAdfsOAuth $disableAdfsOAuth -relativePath $ocsPswsInternalWebConfigPath `
-macpRegistryPath $macpRegPath -adfsClientId $adfsClientId -adfsMetadataPublicUri $adfsMetadataPublicUri -adfsIssuerName $adfsIssuerName -adfsOAuthInstance $adfsOAuthInstance
$externalOcsPswsWebConfigContent = GetEditedFileContentForWebConfig -disableAdfsOAuth $disableAdfsOAuth -relativePath $ocsPswsExternalWebConfigPath `
-macpRegistryPath $macpRegPath -adfsClientId $adfsClientId -adfsMetadataPublicUri $adfsMetadataPublicUri -adfsIssuerName $adfsIssuerName -adfsOAuthInstance $adfsOAuthInstance
$internalIndexAspxContent = GetEditedFileContentForIndexAspx -disableAdfsOAuth $disableAdfsOAuth -relativePath $macpInternalIndexAspxPath `
-macpRegistryPath $macpRegPath -adfsClientId $adfsClientId -adfsOAuthInstance $adfsOAuthInstance -simplifiedUrlPrefix $simplifiedUrlPrefix
$externalIndexAspxContent = GetEditedFileContentForIndexAspx -disableAdfsOAuth $disableAdfsOAuth -relativePath $macpExternalIndexAspxPath `
-macpRegistryPath $macpRegPath -adfsClientId $adfsClientId -adfsOAuthInstance $adfsOAuthInstance -simplifiedUrlPrefix $simplifiedUrlPrefix
$finalRelativePathToContentMap = @{}
$key = Join-Path -Path $internalOcsPswsPath -ChildPath "web.config"
$finalRelativePathToContentMap[$key] = $internalOcsPswsWebConfigContent
$key = Join-Path -Path $externalOcsPswsPath -ChildPath "web.config"
$finalRelativePathToContentMap[$key] = $externalOcsPswsWebConfigContent
$key = Join-Path -Path $internalMacpPath -ChildPath "index.aspx"
$finalRelativePathToContentMap[$key] = $internalIndexAspxContent
$key = Join-Path -Path $externalMacpPath -ChildPath "index.aspx"
$finalRelativePathToContentMap[$key] = $externalIndexAspxContent
SetupOAuthOnFrontEndPools -cred $cred -pools $poolArray -macpRegistryPath $macpRegPath `
-disableAdfsOAuth $disableAdfsOAuth -relativePathToContentMap $finalRelativePathToContentMap -adfsClientId $adfsClientId `
-adfsMetadataPublicUri $adfsMetadataPublicUri -adfsIssuerName $adfsIssuerName -adfsOAuthInstance $adfsOAuthInstance
if ($disableAdfsOAuth -eq $true)
{
Write-Host "`n`rADFS OAuth has been disabled for the admin control panel." -ForeGroundColor Green
}
else
{
Write-Host "`n`rADFS OAuth has been enabled for the admin control panel." -ForeGroundColor Green
}