IIS Express /protocol:https

IIS Express is awesome, a great upgrade from Cassini.  It supports https, Windows Authentication, persistent sites even if Visual Studio is closed, command-line launching, it’s great.  However combining them sometimes doesn’t work too well.

In Cassini (Visual Web Developer) I could launch it like this:

WebDev.WebServer40.EXE /port:1234 /path:C:pathtosite

This works wonderfully in IIS Express as well:

iisexpress.exe /port:1234 /path:C:pathtosite

This gets awkward when moving to https.  This doesn’t work:

iisexpress.exe /port:1234 /path:C:pathtosite /protocol:https

Why doesn’t it work?  Because iisexpress has no /protocol switch.  Bummer.  I flung a request for this and got a great response from Robert McMurray.

A Step Back Robert McMurray summarizes the two modes of IIS Express nicely as “Personal Web Server Mode” (e.g. “IIS Lite”) and “Application Server Mode” (e.g. “just launch this”).

“Personal Web Server Mode” is a durable version of (almost all of) IIS launched in the user’s context.  There’s a great system tray icon that centralizes all the running sites, and the applicationHost.config file is identical to regular IIS.  One can rig Windows Authentication, HTTPS, tracing, classic ASP, the works.  (Why “almost”?  Because there’s no tooling for configuration.  There are a few settings in Visual Studio, but nothing of consequence.  The perfect solution would be a way to point IIS Manager at it.  Unfortunately, typically the easiest way to configure IIS Express is to configure IIS proper, then diff their config files.  But I digress.)

“Application Server Mode” is much like Cassini was.  When you launch it, you specify /port: and /path:.  The unfortunate part of this mode is it presumes http.  To their credit, this mode is likely solely for backwards compatibility with Cassini, and Cassini didn’t support https at all.

Now What? My goal is to run IIS Express in “just do it” mode, pass in a

/port: and /path:, and test my https site.  All else being equal, a /protocol: parameter to iisexpress.exe would be easiest.  In its absence, let’s go hacking.  Back to Robert McMurray.  He proposes a batch file that uses appcmd.exe to rig adjustments to a cloned applicationHost.config, passing in IIS Express 8’s new /apphostconfig: flag, which specifies the config to modify.  It’s a bit of a long way around, but ok.  In theory it’s easier than brute-forcing some XPath.

A bit of tinkering, a lot of elbow grease, and an extra quarter or two into the command-line meter, and I have a batch file that allows me to launch IIS Express like this:

iisexpress.bat /port:1234 /path:C:pathtosite /protocol:https

The batch file takes care of shimming the difference between me using it like “Application Server Mode” and it running in “Personal Web Server Mode” (with a temporary config).  Thanks to Robert McMurray for pointing me in the right direction.

For compatibility’s sake, it has a PowerShell XPath mechanism for users of IIS Express 7.x, though for those with IIS Express 8, flip over into appcmd and you’re golden.

The Batch File

@echo off
setlocal enabledelayedexpansion

pushd "%~dp0"

REM because we're shifting this off the grid soon
set script_name=%0

if '%1'==" GOTO help

set site_port=8080
set site_protocol=http

if '%1'==" GOTO :args_done

set arg="%1″
set argv=%arg:/path:=%
if "%argv%"=="%arg%" goto not_path

set site_path=%argv:"=%
goto get_args


set argv=%arg:/port:=%
if "%argv%"=="%arg%" goto not_port

set site_port=%argv:"=%
goto get_args


set argv=%arg:/protocol:=%
if "%argv%"=="%arg%" goto not_https

set site_protocol=%argv:"=%
goto get_args


if '%1'=='/?' GOTO help
if '%1'=='/h' GOTO help
if '%1'=='-?' GOTO help
if '%1'=='-h' GOTO help

echo Invalid parameter: %1
goto help


if "%site_path%"=="" GOTO no_path
if "%site_port%"=="" GOTO no_port
if not exist "%site_path%" GOTO invalid_path


set sitename=%TIME::=.%-%RANDOM%
set tempdir=%TEMP%iisexpress-temp%sitename%
if exist "%tempdir%" GOTO :get_tempdir
mkdir "%tempdir%"


if "%PROGRAMFILES(x86)%"=="" goto x86
set iis_dir=%PROGRAMFILES(x86)%IIS Express
goto iis_done
set iis_dir=%PROGRAMFILES%IIS Express
if not exist "%iis_dir%iisexpress.exe" GOTO iis_missing


copy "%iis_dir%AppServerapplicationHost.config" "%tempdir%"

REM Mangle 'Development Web Site' to match what we're after

REM These need IIS Express 8:
REM "%iis_dir%appcmd.exe" set config -section:system.applicationHost/sites /"[name='Development Web Site'].[path='/'].[path='/'].physicalPath:%site_path%" /commit:apphost /apphostconfig:%tempdir%applicationHost.config
REM "%iis_dir%appcmd.exe" set config -section:system.applicationHost/sites /~"[name='Development Web Site'].bindings" /commit:apphost /apphostconfig:%tempdir%applicationHost.config
REM "%iis_dir%appcmd.exe" set config -section:system.applicationHost/sites /+"[name='Development Web Site'].bindings.[protocol='%site_protocol%',bindingInformation='']" /commit:apphost /apphostconfig:%tempdir%applicationHost.config
REM This doesn't
Powershell.exe -Command "& {$a=New-Object System.Xml.XmlDocument;$a.Load("%tempdir%applicationHost.config");$b=$a.SelectSingleNode("//sites/site[@id='1′]//virtualDirectory");$b.physicalPath="%site_path%";$c=$a.SelectSingleNode("//sites/site[@id='1′]//binding");$c.protocol="%site_protocol%";$c.bindingInformation=":%site_port%:localhost";$a.Save("%tempdir%applicationHost.config")}"


echo Running IIS Express: /port:%site_port% /protocol:%site_protocol% /path:%site_path%, temp-config: %tempdir%applicationHost.config
"%iis_dir%iisexpress.exe" /config:%tempdir%applicationHost.config /siteid:1 /systray:false

rd /q /s %tempdir%

goto exit

echo /port not specified
goto help

echo /path not specified
goto help

echo /path doesn't exist: %site_path%
exit /b 2

echo can't find iisexpress.exe in %iis_dir%
exit /b 3


echo %script_name% [/port:1234] [/protocol:https] "/path:C:pathtositedir"
echo default: /port:8080 /protocol:http
exit /b 1

GOTO exit



exit /b

Here’s hoping this solution works as well for you as it does for me.  Enjoy!