Using PnP-PowerShell with multiple authentication providers configured for host named site collection in SharePoint
For the current project I’m working on I decided to use the PnP-PowerShell library to do all SharePoint provisioning tasks, such as creating lists, uploading html/css/js resources and modifying web part pages. It seems to be quite a powerful library of PowerShell cmdlets based on the SharePoint .NET CSOM API. The typical usage pattern of these cmdlets is like that:
$spWebUrl = “https://sp13dev1.company.com";
$spUserName = “domain\sp_admin”;
$cred = Get-Credential -UserName $spUserName -Message “Enter SharePoint credentials”;
Write-Output “Connecting to SharePoint web $spWebUrl …”;
Connect-PnPOnline -Url $spWebUrl -Credentials $cred;
Write-Output “Successfully connected to SharePoint! Starting provisioning…”;
New-SPOList -Title “Demo list” -Template GenericList -Url “lists/demo”;
Write-Output “Disconnecting from SharePoint …”;
The crucial part here is the call to the Connect-PnOnline cmdlet, which establishes the connection to the SharePoint and initializes the internal Context object which will be used for all subsequent API calls. However, when I ran this script against a test SP2013 farm, I got a somewhat obscure error message “Connect-PnPOnline : The remote server returned an error: (403) Forbidden.” I spent little time guessing the reason for this error as I’d seen this exact error before when I had been doing SharePoint provisioning against the same test farm from C# code with CSOM. In both cases, as it appeared, the problem was caused by these circumstances:
· I was using Windows credentials for authentication in my code.
· Multiple authentication providers, Windows auth and ADFS/SAML in my case, were configured for the default zone of the HNSC (Host Named Site Collection) web application. Users connecting to the SharePoint first landed on a “Sign In” page which prompted them to choose the authentication method. The actual authentication process (NTLM/Kerberos or ADFS) started only after this selection had been made.
· The default SharePoint Context initialization algorithm did not work with the above configuration and the connection could not be established.
The solution for the C# CSOM scenario is well known and described on this page. It basically requires the calling application to insert an additional HTTP header “X-FORMS_BASED_AUTH_ACCEPTED” in each web request to SharePoint to tell it to use Windows authentication. But unfortunately, I found no feasible way to force Connect-PnOnline to insert this “X-FORMS_BASED_AUTH_ACCEPTED” header, short of patching and recompiling the source C# code for the PnP-PowerShell library. However, as I thought more about that, an idea came to me. While it is the recommendation of Microsoft to enable multiple authentication providers on the default zone when there is a requirement for multiple auth methods, it is possible to:
· Add an alternate URL to the root HNSC site collection of the web application
· Extend the web application with the goal of getting a brand new IIS web site separate from the existing default IIS web site. This new IIS site will have different authentication settings from the default one, that is, will only have one authentication method (Windows NTLM/Kerberos) enabled.
Quick search in the Internet yielded this excellent blog post by Brian Farnhill, describing in details just this kind of setup. I implemented all the steps in this article and successfully connected to the SharePoint farm with Connect-PnPOnline cmdlet via an alternate URL. So now using this technique I can perform provisioning/admin scripting via the alternate URL while happy users can continue to work with the SharePoint at the unchanged default URL.
Below is the detailed sequence of steps I took to make this config work:
1. Run a couple of commands in the SharePoint admin mode PowerShell on a SharePoint server:
$spSite = Get-SPSite ‘https://sp13dev1.company.com';
Set-SPSiteUrl $spSite -Url ‘https://winauth.sp13dev1.company.com' -Zone Intranet;
This will add a new URL for the ‘Intranet’ zone to the root HNSC site collection. The access to SharePoint at this moment will still go through the existing default IIS web site with * host header binding with the same auth settings as for the default site collection URL.
2. Create a new A DNS record winauth.sp13dev1.company.com pointing to a NEW IP address.
3. Set this new IP address as a secondary in the NIC settings on your SharePoint WFE server (or update the load balancer config accordingly).
4. Extend the existing SP HNSC web application to a new fresh IIS web site using ANY host header value, but NOT the new URL for the Intranet zone you’ve configured in the first step (for example winauthtemp.sp13dev1.company.com). I selected “Intranet” zone in the Central Admin web site wizard when extended the web application(the same zone as in the Set-SPSiteUrl cmdlet in step 1, but I’m not sure it’s that important).
5. Extending the web app in the previous step will give you one more IIS web site, and now you have to modify its bindings:
a. get rid of this winauthtemp.sp13dev1.company.com host header configured by SharePoint;
b. bind this web site to the new IP address from steps 2 and 3 with empty host header and appropriate port (443 in my case as I use SSL).
c. make sure the default IIS web site for the web application is listening on the concrete IP address registered for primary default DNS name of this web application.
6. If SSL is used, then either add an additional SAN with the new DNS name ‘winauth.sp13dev1.company.com' to the single SP web app cert listing all possible SharePoint URLs or create a new cert with only this new DNS name listed as SAN. I chose to create a new cert with just this new DNS name ‘winauth.sp13dev1.company.com'. Modify the SSL binding of the new IIS web site to use this new cert.