Like in my previous article, most likely you are visiting this page because you are installing and configuring Apps for SharePoint 2013 and you want to support AAM, or Host-Header configured farms. http://technet.microsoft.com/en-us/library/dn144963(v=office.15).aspx
Your farm has March 2013 Public Update, you enabled app functionality for such setups:
$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService $contentService.SupportMultipleAppDomains = $true $contentService.Update()
But when you try to configure multiple app domains for each of your Web Applications / Zones (especially if it’s not the Default zone), the New-SPWebApplicationAppDomain Cmdlet is throwing the “The IIS Web Site you have selected is in use by SharePoint. You must select another port or hostname.” exception.
New-SPWebApplicationAppDomain : The IIS Web Site you have selected is in use by SharePoint. You must select another
port or hostname.
At line:1 char:1
+ New-SPWebApplicationAppDomain -AppDomain XXX.XXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXX …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (Microsoft.Share…cationAppDomain:SPCmdletNewWebApplicationAppDomain) [New
-SPWebApplicationAppDomain], ArgumentException
+ FullyQualifiedErrorId : Microsoft.SharePoint.Administration.SPAppCmdlets.SPCmdletNewWebApplicationAppDomain
I know I can add that app domain binded to the port 443! I know for sure how IIS works and NO, there is no reason to get back “The IIS Web Site you have selected is in use by SharePoint. You must select another port or hostname.”
If we look into the ULS log entries we see:
Failed when trying to add app domain for Web Application XXXX://XXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXX.XX/. Exception: System.ArgumentException: The IIS Web Site you have selected is in use by SharePoint. You must select another port or hostname.
at Microsoft.SharePoint.Administration.SPAppDomainCollection.AddPortBindingIfNecessary(SPAppDomain appDomain)
at Microsoft.SharePoint.Administration.SPAppDomainCollection.Add(SPAppDomain appDomain)
OK, what’s the code behind AddPortBindingIfNecessary method?
// Microsoft.SharePoint.Administration.SPAppDomainCollection private bool AddPortBindingIfNecessary(SPAppDomain appDomain) { bool flag = true; SPIisSettings sPIisSettings = this.WebApplication.IisSettings[appDomain.UrlZone]; if (appDomain.IsSchemeSSL) { using (IEnumerator<SPSecureBinding> enumerator = sPIisSettings.SecureBindings.GetEnumerator()) { while (enumerator.MoveNext()) { SPSecureBinding current = enumerator.Current; if (current.Port == appDomain.Port && string.IsNullOrEmpty(current.HostHeader)) { flag = false; break; } } goto IL_BB; } } foreach (SPServerBinding current2 in sPIisSettings.ServerBindings) { if (current2.Port == appDomain.Port && string.IsNullOrEmpty(current2.HostHeader)) { flag = false; break; } } IL_BB: if (flag) { SPWebServiceCollection sPWebServiceCollection = new SPWebServiceCollection(this.WebApplication.Farm); foreach (SPWebService current3 in sPWebServiceCollection) { foreach (SPWebApplication current4 in current3.WebApplications) { foreach (SPIisSettings current5 in current4.IisSettings.Values) { foreach (SPServerBinding current6 in current5.ServerBindings) { if (current6.Port == appDomain.Port) { if (appDomain.IsSchemeSSL) { throw new ArgumentException(SPResource.GetString("IisBindingInUse", new object[0])); } if (string.IsNullOrEmpty(current6.HostHeader)) { throw new ArgumentException(SPResource.GetString("IisBindingInUse", new object[0])); } } } foreach (SPSecureBinding current7 in current5.SecureBindings) { if (current7.Port == appDomain.Port) { if (!appDomain.IsSchemeSSL) { throw new ArgumentException(SPResource.GetString("IisBindingInUse", new object[0])); } if (string.IsNullOrEmpty(current7.HostHeader)) { throw new ArgumentException(SPResource.GetString("IisBindingInUse", new object[0])); } } } } } } this.AddNewBinding(sPIisSettings, appDomain.Port, appDomain.IsSchemeSSL); } return flag; }
OK, got it! We are not discussing about the IIS settings from IIS Web Server. The exception is referring to the IIS settings SharePoint is keeping hosted inside its configuration database. For example those settings are applied every time when you add an additional Front-End Web Server to your farm (when SharePoint recreates automatically the IIS Web Sites – to make the configuration consistent across the servers). Anyway, we create the SharePoint Web Application using Central Administration, or PowerShell, but most of the time we manually adjust the IIS Web Server settings (bindings, SSL, …). So, again, the IIS settings the New-SPWebApplicationAppDomain is referring to, are those from the configuration database and have nothing to do with the existing IIS Web settings.
OK, the Microsoft developer who wrote the code applied somehow the “logic”, but it does not cover all the setups / scenarios the SharePoint on-premises admins apply. One thing is for sure – it’s not wrong to have a SharePoint farm who has multiple Web Applications, multiple AAMs configured, separate App Domains (configured for each zone, for each web application) and all the app domains to reuse ports like 80 or 443 binded to different IPs.
Let’s see those IIS settings SharePoint has stored inside its database who prevent us to reuse the 80 and 443.
[void][system.reflection.assembly]::loadwithpartialname("Microsoft.SharePoint"); [void][system.reflection.assembly]::loadwithpartialname("Microsoft.SharePoint.Administration"); [Microsoft.SharePoint.Administration.SPWebServiceCollection] $sPWebServiceCollection = [Microsoft.SharePoint.Administration.SPFarm]::Local; foreach($WebApplication in $sPWebServiceCollection.WebApplications) { Write-Host '========================================================' -ForegroundColor Yellow; if($WebApplication.IisSettings.Values.ServerBindings.Count -gt 0) { Write-Host 'Web Application: '('"'+($WebApplication.DisplayName)+'"')' has the following ServerBindings'; $WebApplication.IisSettings.Values.ServerBindings; } if($WebApplication.IisSettings.Values.SecureBindings.Count -gt 0) { Write-Host 'Web Application: '('"'+($WebApplication.DisplayName)+'"')' has the following SecureBindings'; $WebApplication.IisSettings.Values.SecureBindings; } Write-Host ''; }
So in my case the secure binding part of SP002_BI is using port 443. To make New-SPWebApplicationAppDomain work I have to adjust the port number using the SharePoint API.
The following commands are NOT modifying your existing IIS Web Server bindings! The following commands are modifying the bindings for the SharePoint Web Applications, but these new settings will apply to the IIS Web Server only when you will re-provision the web applications (usually when you perform a full SharePoint restore, or join a new Front-End Web server to the farm), case in which 99% of the time you manually add adjustments to your Web Server (bindings, SSL, …).
In my case:
(($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).IisSettings.Values.SecureBindings | where {$_.Port -eq 443}).Port = 93 ($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).IisSettings.Values.SecureBindings ($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).Update();
If you have to deal with a ServerBinding the code will look like:
(($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).IisSettings.Values.ServerBindings | where {$_.Port -eq 80}).Port = 91 ($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).IisSettings.Values.ServerBindings ($sPWebServiceCollection.WebApplications|where{$_.DisplayName -eq "SP002_BI"}).Update();
Execute again the New-SPWebApplicationAppDomain cmdlet and “The IIS Web Site you have selected is in use by SharePoint. You must select another port or hostname.” exception will not be thrown again.
Of course, the New-SPWebApplicationAppDomain cmdlet execution will add another IIS binding in its SharePoint config and also on the IIS Web Server. The last step will be to map properly the IP (IIS binding) and make sure the wildcard DNS entry points to that IP.
Thank you very much for compiling this detailed post. Your blog was the only site that correctly identified and resolved this issue. Much appreciated, and keep up the great work!
Excellent post ! I have a similar case here and I don’t want to change the port number. Did you know that removing host header value in IISsettings works too ?
$wa.IisSettings.Values.SecureBindings.HostHeader = “”
In think this is a better option considering platform evolution.
Thanks again !
Thanks a lot, excellent – solved my problem ?