Following up on my previous post about copying some CRM Plugin DLLs after a build ( http://arkesystems.com/blog/post/2009/02/Recycling-IIS-app-pools.aspx ):
It turns out that the error checking in post-build events isn't reliable (it only checks errorlevel at the end of the script), and apppools don't stop instantly even when told to stop instead of recycle.
So if my xcopy encounters a "sharing violation" (errorlevel 4) then the post-build event isn't smart enough to notice by default.
Luckily, it's just a bat file, so we can add some checking ourselves. This is getting more complicated than I would like, but at least I build reliably now.
"sleep" isn't necessary, but it's a useful command to have around. It comes with Windows 2003 Server Resource Kit: http://www.microsoft.com/downloads/details.aspx?FamilyID=9d467a69-57ff-4ae7-96ee-b18c4790cffd&DisplayLang=en ; restart visual studio after installing the kit.
A note on checking return codes in batch files: Equality checks are actually 'greater than or equal', so you will see people checking if errorlevel eq 1 often. However, this only catches >= 1 error levels, and the occassional program that returns negative error codes will slip past. Accordingly, always check "neq 0" instead of "eq 1". Also, using "SETLOCAL ENABLEDELAYEDEXPANSION" and !ERORRLEVEL! is not strictly necessary in this script, but it's good practice to just always use delayed expansion when checking return values in batch files so that you don't screw up one day when you write an error check inside a loop.
So, hopefully my final iteration of a post-build script that needs to update some IIS dlls:
SETLOCAL ENABLEDELAYEDEXPANSION
net pause KeepAliveService
cscript /nologo "$(ProjectDir)\iis_stop_app_pool.vbs" "CRMAppPool"
if !ERRORLEVEL! NEQ 0 GOTO FAIL
set CRMDIR=C:\Program Files\Microsoft Dynamics CRM
set loop=0
:TRYCOPY
set /a loop=%loop%+1
xcopy "$(TargetPath)" "%CRMDIR%\Server\bin\assembly" /i /d /y
if !ERRORLEVEL! NEQ 0 GOTO COPYFAIL
xcopy "$(TargetDir)$(TargetName).pdb" "%CRMDIR%\Server\bin\assembly" /i /d /y
if !ERRORLEVEL! NEQ 0 GOTO COPYFAIL
cscript /nologo "$(ProjectDir)\iis_start_app_pool.vbs" "CRMAppPool"
if !ERRORLEVEL! NEQ 0 GOTO FAIL
net continue KeepAliveService
GOTO OK
:COPYFAIL
if %LOOP% LEQ 10 GOTO TRYCOPYSLEEP
goto FAIL
:TRYCOPYSLEEP
sleep 1
goto TRYCOPY
:FAIL
echo "Failed with errorlevel !ERRORLEVEL!"
exit 1
:OK
echo "OK"
Edit 3/30/2010: For a 64 bit system, you can get silently redirected to SysWOW64 when a 32 bit process is trying to run something in system32.This causes iisapp.vbs to fail when run as a post build event. In Visual Studio, it shows as an exited with code 1 error. If you manually go to the [windows]\SysWOW64 folder and run iisapp.vbs, you can get an error like:Could not create an instance of the CmdLib object.Please register the Microsoft.CmdLib component.
One solution is to copy the necessary files to the SysWOW64 folder and reregister the dlls:
cd c:\windows\SysWOW64
copy ..\system32\iisapp.vbs .
copy ..\system32\IIsScHlp.wsc .
copy ..\system32\cmdlib.wsc .
regsvr32 cmdlib.wsc
regsvr32 IIsScHlp.wsc