Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
This script will set up sites in IIS, pointing them at their respective directories on your machine.
By convention, the site name, host name and application pool name are all the same. For example,
It will also update the hosts file to point host names to (localhost)
- IIS is already installed, including ASP.Net 4.5
- Out-File : The process cannot access the file 'C:\Windows\System32\drivers\etc\hosts' because it is being used by another process
- Try to re-run the script several times. Try to end the explorer.exe task and re-run the script. If nothing works, reboot and try again.
Example Websites config:
Directory = "StackOverflow\StackOverflow";
Site = "";
Aliases = "";
Databases = "StackExchange.Meta", "Area51.Meta";
Directory = "StackOverflow\StackExchange.Website";
Site = "";
Databases = "StackExchange";
Directory = "StackOverflow\StackAuth";
Site = "";
Databases = "Sites";
Directory = "StackOverflow\StackOverflow.Api.V2";
Site = "";
Directory = "Area51\StackOverflow.Proposals";
Site = "";
Databases = "Area51";
function Register-Websites {
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] $Websites
Write-Host "Registering IIS Websites..." -ForegroundColor "Magenta"
# Grab the web admin and HOSTS module
Import-Module WebAdministration
# DLL blocking on Windows, yay fun!
Get-ChildItem "$PSScriptRoot\Includes\PsHosts" | Unblock-File
Import-Module "$PSScriptRoot\Includes\PsHosts"
# Unlock the serverRuntime section of system.webServer.
Set-WebConfiguration "//system.WebServer/serverRuntime" "machine/webroot/apphost" -Metadata overrideMode -Value Allow
# Set some common variables
Set-WebConfigurationProperty "/system.webServer/httpCompression/scheme[@name='gzip']" -PSPath IIS:\ -name dynamicCompressionLevel -value 4
# Remove default website and application pool - we don't want it for any setups
Get-Website -Name "Default Web Site" | Remove-Website
# Remove DefaultAppPool app pool
if (Test-Path "IIS:\AppPools\DefaultAppPool")
Remove-WebAppPool -Name "DefaultAppPool"
# First, check for existence of all folders
$missing = $false
foreach ($website in $Websites) {
$webPath = Join-Path $Env:CODEROOT $website.Directory
if (!(Test-Path $webPath))
$missing = $true
Write-Error "Could not find folder $webPath"
Write-Error ""
# Let's not fail partially; go get everything
if ($missing -eq $true) {
Write-Warning "Go back and run the repos step."
Write-Warning ""
$iis_iusrs = New-Object System.Security.Principal.NTAccount BUILTIN\IIS_IUSRS
$acl_iis_iusrs = Get-AccessRule $iis_iusrs
# Remove & create sites in IIS
foreach ($website in $Websites) {
$baseHost = $website.Site
Write-Host "Creating IIS Website & AppPool for $baseHost..." -ForegroundColor "Magenta"
# Host name, site name and app pool name are identical by convention
$rootPath = Join-Path $env:CODEROOT $website.Directory
Write-Host " Website directory: $rootPath"
$acl = Get-Acl $rootPath
if (!(Find-AccessRule $acl $iis_iusrs)) {
Write-Host " Granting access to $rootPath for IIS_IUSRS"
Set-Acl $rootPath $acl
# Remove Existing site and pool
Get-Website -Name $baseHost | Remove-Website
if (Test-Path "IIS:\AppPools\$baseHost")
Remove-WebAppPool -Name $baseHost
Write-Host " Creating AppPool for $baseHost"
$appPool = New-WebAppPool -Name $baseHost
$appPool | Set-ItemProperty -Name ProcessModel.loadUserProfile -Value false
$appPool | Set-ItemProperty -Name managedRuntimeVersion -Value v4.0
# Create new site
Write-Host " Creating Website for $baseHost"
$iisWebsite = New-WebSite -Name $baseHost -ApplicationPool $baseHost -PhysicalPath $rootPath -HostHeader $baseHost
# Add hosts file entry
Write-Host " Creating HOSTS entry for $baseHost to"
Get-HostEntry | Where { $_.Name -eq $baseHost } | Remove-HostEntry
Add-HostEntry -Name $baseHost -Address -Comment "auto-generated by dev-local-setup" | Out-Null
# If requested, SSL self-signed certs
if ($website.Certificate)
New-IISSelfSignedCertificate $baseHost $baseHost
foreach ($hostAlias in $website.Aliases) {
Write-Host " Alias: Creating HOSTS entry for $hostAlias to"
Get-HostEntry | Where { $_.Name -eq $hostAlias } | Remove-HostEntry
Add-HostEntry -Name $hostAlias -Address -Comment "auto-generated by dev-local-setup" | Out-Null
Write-Host " Alias: Adding website binding for $hostAlias"
New-WebBinding -Name $baseHost -IPAddress "*" -Port 80 -HostHeader $hostAlias
if ($website.Certificate)
# Need to add a cert for each...
New-IISSelfSignedCertificate $baseHost $hostAlias
# Print
Write-Host "IIS Website & AppPool for $baseHost created." -ForegroundColor "Green"
Write-Host "IIS Websites registered." -ForegroundColor "Green"
function Find-AccessRule ($acl, $account) {
foreach ($item in $acl.Access) {
if ($item.IdentityReference -eq $account) {
return $item
function Get-AccessRule ($account) {
New-Object System.Security.AccessControl.FileSystemAccessRule ($account,
([System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit),
function New-IISSelfSignedCertificate ($baseHost, $host) {
Write-Host " SSL Certificate requested. Creating self-signed cert for $host."
# Recreate self-signed SSL cert
Push-Location cert:\LocalMachine\My
Get-ChildItem -DnsName $host | Remove-Item
$cert = New-SelfSignedCertificate -DnsName $host
# Re-add it to the Root store (needed for the green padlock)
Push-Location cert:\LocalMachine\Root
Get-ChildItem -DnsName $host | Remove-Item
$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList Root, LocalMachine
Write-Host " SSL Certificate added to local root store."
Write-Host " Removing any existing WebBindings for $host..." -NoNewline
Get-WebBinding -Name $baseHost -Protocol 'https' -Port 443 -HostHeader $host | Remove-WebBinding
Write-Host "removed."
# Recreate SSL bindings
Write-Host " Adding a new WebBinding for $host..." -NoNewline
New-WebBinding -Name $baseHost -Protocol 'https' -Port 443 -HostHeader $host -SslFlags 1 # SNI enabled w/o IIS Central Cert Store
Write-Host "added."
# Required for SNI
$existsCheck = netsh http show sslcert hostnameport=$host:443
if ($existsCheck -Like "*$host:443*") {
Write-Host " Existing netsh sslcert found for $host, removing..." -NoNewline
netsh http delete sslcert hostnameport=$($host):443
Write-Host " Adding netsh sslcert binding..." -NoNewline
netsh http add sslcert hostnameport=$($host):443 certhash=$($cert.Thumbprint) appid='{00000000-0000-0000-0000-000000000000}' certstorename=MY
Write-Host " SNI thumbprint added."
Write-Host " SSL Certificate setup complete."
Write-Host ""

This comment has been minimized.

Copy link

@xt0rted xt0rted commented May 31, 2018

Half my host entries were giving me:

Add-HostEntry : The process cannot access the file 'C:\Windows\system32\drivers\etc\hosts' because it is being used by
another process.

I ended up simplifying those two spots to use Set-HostEntry and the issue seems to have gone away.

# Lines 123-124
Set-HostEntry -Name $baseHost -Loopback -Comment "auto-generated by dev-local-setup" -Force

# Lines 134-135
Set-HostEntry -Name $hostAlias -Loopback -Comment "auto-generated by dev-local-setup" -Force
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment