How to configure IIS remotely using powershell? - iis

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

Related

Trouble deploying multiple HTTPS sites to single host in TFS 2015

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
}

How to RDP connect to an Azure VM

I would like to run some tests on some VM machines. The machines belong to different users with different MSDN accounts, which means private passwords.
What I did was so far is to create an Azure VM for each MSDN account and set a similar user name/password for the machine.
What I would like to do is to:
Connect to any of these VMs. My problem: I don't know the machine name. I tried to connect using the rdp file provided by Azure, and it's working, but the problem is that it's using an IP instead of a name.
I tried finding the machine name, but all documentation about this seems to be outdated. . I tried to connect to amam10x64.westeurope.cloudapp.azure.com but without success.
Copy a file to/from the VM. My hope is that I can use the following snippet:
$commandStr = [string]::Format("Copy-VMFile ""{0}"" -SourcePath ""{1}"" -
DestinationPath ""{2}"" -CreateFullPath -FileSource Host -Force", $VM,
$SessionPath, $RemoteFullPath)
$commandBlock = [scriptblock]::Create($commandStr)
Invoke-Command -Session $sess -ScriptBlock $commandBlock
Run a command on the VM. Hopefully, I can use same command from Pt. 2.
I tried to connect to amam10x64.westeurope.cloudapp.azure.com but
without success.
If you want to connect this VM with DNS, we should set FQDN for this VM, please refer to this link.
Copy a file to/from the VM. My hope is that I can use the following
snippet:
Maybe we can use winrm to do this.
About how to use winrm connect Azure VM, please refer to this answer.
Run a command on the VM. Hopefully, I can use same command from Pt. 2.
We can use this script to connect Azure VM via Winrm:
$username = 'jason'
$pass = ConvertTo-SecureString -string 'password' -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $pass
$s = New-PSSession -ConnectionUri 'http://23.99.82.2:5985' -Credential $cred -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck)
Invoke-Command -Session $s -ScriptBlock {Get-Process PowerShell}

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.

Office 365 migration practice with windows azure

I have been asked to "help" a client migrate their on premise AD/Exchange 2010 implementation to the cloud (office 365).
i have no idea where to start and although I have watched quite a few videos on the topic via technet I feel I need some practical experience.
As such I was wondering if anyone knew of some step-by-step guides on how to setup a mock environment on windows azure (setting up a new AD server with multiple users) and then migrating that environment into office 365?
I would certainly recommend setting up a lab environment on Azure IaaS so that you can walk through the process.
Here's the basic process I use...
Set up a new Virtual Network via the Portal
Create an affinity group to ensure that resources are co-located
Create a storage account to host your VHD's
Create a PowerShell script to set up an AD VM
Install AD DS on the AD VM and configure your domain
Create PowerShell scripts for other domain-joined VM's
If you want federated authentication, create an AD FS VM
Create a VM to host DirSync
Configure directory synchronisation in Office 365
Install DirSync from the Office 365 portal on your DirSync VM
Create a VM to act as a test client or configure point-to-site VM and add an existing machine to your lab domain
Here's an example script to create an AD VM...
Import-Module "C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\Azure\Azure.psd1"
Import-AzurePublishSettingsFile 'C:\Lab\credentials.publishsettings'
Set-AzureSubscription -SubscriptionName '{your Azure subscription}' -CurrentStorageAccount {your storage account name}
Select-AzureSubscription -SubscriptionName '{your Azure subscription}'
#Deploy the Domain Controller in a virtual network
#-------------------------------------------------
#Specify my DC's DNS IP (127.0.0.1)
$myDNS = New-AzureDNS -Name 'LabDNS' -IPAddress '127.0.0.1'
$vmname = 'LabDC'
# OS Image to Use
# Get the latest Windows Server 2008 R2 SP1 image
$family = "*Windows Server 2008 R2 SP1*"
$images = Get-AzureVMImage `
| where { $_.ImageFamily -like $family } `
| Sort-Object -Descending -Property PublishedDate
$image = $images[0].ImageName
Write-Host "Using image: " + $image
Read-Host "Continue or Ctrl-C to cancel"
$service = 'LabDomain'
$AG = 'LabAffinityGroup'
$vnet = 'LabNetwork'
$user = "LabAdmin"
$password = 'LabPassword123'
$subnet = 'Subnet-1'
#VM Configuration
$MyDC = New-AzureVMConfig -name $vmname -InstanceSize 'Small' -ImageName $image |
Add-AzureProvisioningConfig -Windows -AdminUsername $user -Password $password |
Set-AzureSubnet -SubnetNames $subnet
New-AzureVM -ServiceName $service -AffinityGroup $AG -VMs $MyDC -DnsSettings $myDNS -VNetName $vnet

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