Search code examples
iisazuredosappcmd

How to make startup tasks idempotent?


I have a number of startup tasks in batch files. In particular I call IIS's appcmd.exe to configure IIS. Startup tasks in Azure are supposed to idempotent (ie, able to be run repeatedly with the same results), in case the role is restarted for some reason. Unfortunately many of my IIS configuration commands will fail the second time around, eg because they delete a configuration node the first time which is then not present on subsequent runs.

My question is, how do I make these startup tasks idempotent? Is there a way to make appcmd.exe not throw errors? Is there a way to make the shell catch the errors? Is there a way to make the Azure framework ignore the errors?

Here's an example of my startup tasks. This is all contained in a command file, configiis.cmd.

@REM Enable IIS compression for application/json MIME type
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json',enabled='True']" /commit:apphost
%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/httpCompression /+"dynamicTypes.[mimeType='application/json; charset=utf-8',enabled='True']" /commit:apphost

@REM Set IIS to automatically start AppPools
%windir%\system32\inetsrv\appcmd.exe set config -section:applicationPools -applicationPoolDefaults.startMode:AlwaysRunning /commit:apphost

@REM Set IIS to not shut down idle AppPools
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00 /commit:apphost

@REM But don't automatically start the AppPools that we don't use, and do shut them down when idle
%windir%\system32\inetsrv\appcmd.exe set config  -section:system.applicationHost/applicationPools "/[name='Classic .NET AppPool'].startMode:OnDemand" "/[name='Classic .NET AppPool'].autoStart:False" "/[name='Classic .NET AppPool'].processModel.idleTimeout:00:01:00" /commit:apphost
%windir%\system32\inetsrv\appcmd.exe set config  -section:system.applicationHost/applicationPools "/[name='ASP.NET v4.0'].startMode:OnDemand" "/[name='ASP.NET v4.0'].autoStart:False" "/[name='ASP.NET v4.0'].processModel.idleTimeout:00:01:00" /commit:apphost
%windir%\system32\inetsrv\appcmd.exe set config  -section:system.applicationHost/applicationPools "/[name='ASP.NET v4.0 Classic'].startMode:OnDemand" "/[name='ASP.NET v4.0 Classic'].autoStart:False" "/[name='ASP.NET v4.0 Classic'].processModel.idleTimeout:00:01:00" /commit:apphost


@REM remove IIS response headers
%windir%\system32\inetsrv\appcmd.exe set config /section:httpProtocol /-customHeaders.[name='X-Powered-By']

Solution

  • Aside from @Syntaxc4's answer: Consider the use of a breadcrumb (file) locally. In your script, check for existence of a known file (that you create). If it doesn't exist, go through your startup script, also creating a breadcrumb file. Next time the vm starts up, it would again check for existence of the breadcrumb file and, if it exists, exit the cmd file. If the breadcrumb file disappears, this typically means your vm has been reconstituted somewhere else (either a new instance or a respawned instance maybe on different hardware) and IIS configuration would be needed.