Trouble deploying multiple HTTPS sites to single host in TFS 2015 - iis

I'm trying to deploy multiple websites to a single host running IIS from TFS 2015. I'm trying to have all sites use the "Server Name Indication Required" option so that they all can run under the same IP address. (This setup works fine in IIS if I manually set everything up -- my question / problem comes from deploying from TFS 2015).
The FIRST site in the deploy chain works fine, but the any subsequent one seems to fail with the following error:
System.Exception: SSL Certificate add failed, Error: 183 Cannot create a file when that file already exists.
Each of the sites I'm deploying has a different SSL certificate and I've imported them all properly to the Local Machine\Personal store.
A screenshot of the release definition with the "IIS Web App Management" task highlighted is shown below.
Any suggestions on how to resolve this error within the release definition so that I can deploy cleanly without manual intervention?
I guess one thing I could try is to do ALL of the IIS management steps from PowerShell but was hoping to use the tools a little more fully rather than rolling new scripts to do what it seems that they SHOULD be able to do natively.
Any insight is appreciated.

The error message will appear if you try to bind the certificate to a port which is already binded to this or another certificate.
You can try to set different ports for the sites.
You can also try adding a step (Command line/Powershell step) to delete the existing binding before next deploy step if that does not affect the sites.
eg:
$> netsh http delete sslcert ipport:1.1.1.1:443
Reference below articles to delete the binding:
How to: Configure a Port with an SSL Certificate
Remove an SSL certificate from your server
How to remove SSL bindings using powershell

I got things working - but I had to basically eliminate the binding configuration from the WinRM - IIS App Management tasks. I kept everything the same but specified NO binding information at all in those tasks, then added a target machine power shell script that looked like this (thumbprints and site domains changed):
Import-Module WebAdministration
if ($null -eq (Get-WebBinding | Where-Object {$_.BindingInformation -eq "*:443:iddev.mydomain.com"}))
{
New-WebBinding -Name "Identity-B2B" -Port 443 -Protocol "https" -HostHeader "iddev.mydomain.com" -SslFlags 1
New-Item -Path "IIS:\SslBindings\!443!iddev.mydomain.com" -Thumbprint "88E811B7A9417DACAAAAAAAAAA1C36AA0BA238FF1E0F" -SSLFlags 1
}
if ($null -eq (Get-WebBinding | Where-Object {$_.BindingInformation -eq "*:443:iddev.myotherdomain.com"}))
{
New-WebBinding -Name "Identity-B2C" -Port 443 -Protocol "https" -HostHeader "iddev.myotherdomain.com" -SslFlags 1
New-Item -Path "IIS:\SslBindings\!443!iddev.myotherdomain.com" -Thumbprint "BE38195A2BBBBBBBBBBBBBBB1C2AB5762C9" -SSLFlags 1
}

Related

Automate setting up Passive FTP in IIS on Azure Windows Server?

Is there a way to automate setting up FTP site in IIS on Windows Server? I can manually do that following this document. But I want to do it using a script.
I'm using IIS 10 on Azure VM running Windows Server 2016.
To Set up FTP external Firewall IP address and data channel port range, you could apply this script:
#Set up data channel
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.ftpServer/firewallSupport" -name "lowDataChannelPort" -value 5000
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.ftpServer/firewallSupport" -name "highDataChannelPort" -value 6000
#Set external firewall support
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/ftpServer/firewallSupport" -name "externalIp4Address" -value "1.1.1.1"
There are tons of link about how to build up FTP site with powershell.
https://gallery.technet.microsoft.com/scriptcenter/Creating-FTP-in-IIS-and-014b8940
You could combine these scripts base on your requirement.

How can I update ASP.NET Core app over an existing/running site without stopping the web server?

We have an ASP.NET Core site running on our test server that we would like to auto-deploy by XCopy to our IIS web server as we do our current apps, where I already have the site running. I've added a publish profile that packages the site to a "publish-local" directory within the solution. Whenever I try to copy over the existing site, all DLLs are being used by another process, presumably Kestrel, so I am forced to deploy to a sibling directory and re-map IIS to look at the sibling. How does one update a running ASP.NET Core site without having to manually intervene and stop either the Kestrel or IIS web servers?
When running with IIS you can drop a file called app_offline.htm (case sensitive) to your application folder. IIS will stop your application and will serve the contents of the app_offline.html file. Now you can copy your application. Once finished remove the app_offline.htm and IIS will start your app. This is described in the docs and also in my post on running Asp.NET Core apps with IIS.
a little cheat we use is to rename the old files first (something like my.dll.old), then copy over the new dlls. Then you can either force or wait for an app pool restart.
Usually I take a backup of the existing version. Then I almost simultaneously recycle the app domain (if I'm using iis) and overwrite the entire contents of the root folder. This way the app restarts with the new version of the code. But it has to be super quick or else there can be issues. In case if anything fails backup can be used to restore to original state.
You can switch the physical path of your IIS site/application with PowerShell:
($curPath = Get-WebFilePath -PSPath "IIS:\Sites\www.example.com\MyApp")
if ($curPath -like "*Blue*") {
Copy-Item -Path "D:\inetpub\wwwroot\MyAppPath\Staging\*" -Destination "D:\inetpub\wwwroot\MyAppPath\Green" -Recurse -Force
Set-ItemProperty IIS:\Sites\www.example.com\MyApp -name physicalPath -value "D:\inetpub\wwwroot\MyAppPath\Green"
} else {
Copy-Item -Path "D:\inetpub\wwwroot\MyAppPath\Staging\*" -Destination "D:\inetpub\wwwroot\MyAppPath\Blue" -Recurse -Force
Set-ItemProperty IIS:\Sites\www.example.com\MyApp -name physicalPath -value "D:\inetpub\wwwroot\MyAppPath\Blue"
}
Use a staging folder to which you copy your new published files. Then, the above script switches between the green and blue folder. You don't have to stop or recycle your app.

Security Warning when running scripts - Unblock-File not unblocking file

I suddenly started to recceive this warning when running any script on my computer:
Run only scripts that you trust. While scripts from the internet can be useful, this script can potentially harm your computer...
Screenshot:
The files are not blocked.
I have
checked in File Explorer > Properties.
used the Unblock-File cmdlet to unblock as well.
checked streams using cmdlet: Get-Content -Path '\\Path\Script.ps1' -Stream Zone.Identifier. No Streams found.
used Streams.exe from Sysinternals: streams.exe -d \\Path\Script.ps1. No files with streams found.
Also tried to remove streams with Powershell:
Remove-Item -Path \\Path\Script.ps1 -Stream Zone.Identifier
Of course without success as there are no streams.
Execution policy is Unrestricted.
When I run Set-ExecutionPolicy Bypass it works without warning.
It should, however, also work when it's unrestricted.
I honestly don't know what's going on.
After searching i found someone with similar issues and it was explained that Classic UNC paths will work without prompting to unblock the file:
\\Servername\Path...
However FQDN paths are not seen as safe by default and will prompt:
\\Servername.foo.local\Path...
My own testing confirms this to be correct as removing the .foo.local from the path causes the Unblock-File prompts to stop.
LGPE > gpedit.msc
Computer Configuration > Administrative Templates, > Windows Components, > Internet Explorer>expand Internet Control Panel.
Security Page > Intranet Sites: Include all local (intranet) sites not listed in other zones, and then click Properties.
Click Enabled.
Turn on automatic detection of the intranet, and then click Properties.
Click Disabled, and then click OK.
or registry
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\"UNCAsIntranet" = "0"
The correct registry keys, name and value, to treat all local sites as part of the intranet zone, are:
Keys:
HKLM\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap
HKCU\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap
Name: IntranetName
Type: DWORD
Value: 1
You can set this via PowerShell for the local machine (in an elevated prompt) like this:
Set-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap" -Name "IntranetName" -Type DWord -Value 1
See Intranet Sites: Include all local (intranet) sites not listed in other zones for more information about the group policy.
PS doesnot allow Scripts to run on system ENV by default.
you need to set the policy to unrestricted or remote signed
Use:
Set-ExecutionPolicy Remotesigned
OR
Set-ExecutionPolicy Unrestricted
Open the PS console and type this and press enter and then try running your script.

How to configure IIS remotely using powershell?

I am trying to write a simple script that lets you remotely add an app pool, site, and app to IIS using powershell.
I figured out how to do this using APPCMD with a .bat on the local machine, but I need to do this remotely.
My bat file works and contains:
%systemroot%\system32\inetsrv\APPCMD add apppool /name:"WCF Integrated 4.0" /managedRuntimeVersion:"v4.0" /managedPipelineMode:Integrated /processModel.identityType:"NetworkService" /enable32BitAppOnWin64:True
%systemroot%\system32\inetsrv\APPCMD add site /name:"WCF Site" /bindings:"http/*:88:" /physicalPath:"D:\wcf"
%systemroot%\system32\inetsrv\APPCMD add app /site.name:"WCF Site" /path:/Service/Host /physicalPath:"D:\wcf\Service"
%systemroot%\system32\inetsrv\APPCMD set app /app.name:"WCF Site/Service/Host" /applicationPool:"WCF Integrated 4.0"
You didn't specify which version of IIS. If you are on 7.x, you can use the web administration module. Your script would resemble this:
$Session = New-PSSession -ComputerName '<ComputerName>'
$block = {
import-module 'webAdministration'
# Call IIS cmdlets here for adding app pools, creating web site and so on
}
Invoke-Command -Session $Session -ScriptBlock $block

How to assign a SSL Certificate to IIS7 Site from Command Prompt

Can you advise me whether it is possible or not to assign a SSL Certificate to a website in IIS7 using the APPCMD application?
I am familiar with the command to set the HTTPS Binding
appcmd set site /site.name:"A Site" /+bindings.[protocol='https',bindingInformation='*:443:www.mysite.com']
and how to obtain current mappings
%windir%\system32\inetsrv\Appcmd
but can not seem to find any way to map a site to a certificate (say the certificates hash for example)
The answer is to use NETSH.
For example
netsh http add sslcert ipport=0.0.0.0:443 certhash='baf9926b466e8565217b5e6287c97973dcd54874' appid='{ab3c58f7-8316-42e3-bc6e-771d4ce4b201}'
This helped me a lot: a simple guide, by Sukesh Ashok Kumar, to setting up SSL for IIS from the command line. Includes importing/generating the certificate with certutil / makecert.
http://www.awesomeideas.net/post/How-to-configure-SSL-on-IIS7-under-Windows-2008-Server-Core.aspx
EDIT: if the original URL is down, it's still available through the Wayback Machine.
With PowerShell and the WebAdministration module, you can do the following to assign an SSL certificate to an IIS site:
# ensure you have the IIS module imported
Import-Module WebAdministration
cd IIS:\SslBindings
Get-Item cert:\LocalMachine\My\7ABF581E134280162AFFFC81E62011787B3B19B5 | New-Item 0.0.0.0!443
Things to note... the value, "7ABF581E134280162AFFFC81E62011787B3B19B5" is the thumbprint for the certificate you want to import. So it needs to be imported into the certificate store first. The New-Item cmdlet takes in the IP address (0.0.0.0 for all IPs) and the port.
See http://learn.iis.net/page.aspx/491/powershell-snap-in-configuring-ssl-with-the-iis-powershell-snap-in/ for more details.
I've tested this in Windows Server 2008 R2 as well as Windows Server 2012 pre-release.
#David and #orip have it right.
However, I did want to mention that the ipport parameter specified in the example (0.0.0.0:443) is what the MSDN calls the "unspecified address (IPv4: 0.0.0.0 or IPv6: [::])".
I went looking it up, so I figured I'd document here to save someone else the time. This article focuses on SQL Server, but the information is still relevant:
http://msdn.microsoft.com/en-us/library/ms186362.aspx
Using the answers from this post, I created a single script that did the trick for me. It starts from the pfx file, but you could skip that step.
Here it is:
cd C:\Windows\System32\inetsrv
certutil -f -p "pa$$word" -importpfx "C:\temp\mycert.pfx"
REM The thumbprint is gained by installing the certificate, going to cert manager > personal, clicking on it, then getting the Thumbprint.
REM Be careful copying the thumbprint. It can add hidden characters, esp at the front.
REM appid can be any valid guid
netsh http add sslcert ipport=0.0.0.0:443 certhash=5de934dc39cme0234098234098dd111111111115 appid={75B2A5EC-5FD8-4B89-A29F-E5D038D5E289}
REM bind to all ip's with no domain. There are plenty of examples with domain binding on the web
appcmd set site "Default Web Site" /+bindings.[protocol='https',bindingInformation='*:443:']
If you're trying to perform IIS Administration without using the MMC snap-in GUI, you should use the powershell WebAdministration module.
The other answers on this blog don't work on later versions of Windows Server (2012)
Using PowerShell + netsh:
$certificateName = 'example.com'
$thumbprint = Get-ChildItem -path cert:\LocalMachine\My | where { $_.Subject.StartsWith("CN=$certificateName") } | Select-Object -Expand Thumbprint
$guid = [guid]::NewGuid().ToString("B")
netsh http add sslcert ipport="0.0.0.0:443" certhash=$thumbprint certstorename=MY appid="$guid"
If you need a named binding, replace netsh call with this:
netsh http add sslcert hostnameport="$certificateName:443" certhash=$thumbprint certstorename=MY appid="$guid"
With IISAdministration 1.1.0.0 (https://www.powershellgallery.com/packages/IISAdministration/1.1.0.0) you can use the following code to add a new HTTPS binding to a specific site:
$thumbPrint = (gci Cert:\localmachine\My | Where-Object { $_.Subject -Like "certSubject*" }).Thumbprint
New-IISSiteBinding -Name "Site Name" -BindingInformation "*:443:" -CertificateThumbPrint $thumbPrint -CertStoreLocation My -Protocol https
View existing bindings with
Get-IISSiteBinding -Name "Site Name"
Remove an existing binding with
Remove-IISSiteBinding -Name "Site Name" -BindingInformation "*:443:" -Protocol https -Confirm:$False

Resources