Hablaba hace unos días de algunos trucos para depurar servicios: Depurando servicios de Windows más facilmente. Los trucos comentados en mi anterior post, aun siendo útililes, tienen un problema. De una u otra manera alteran el servicio que queremeos depurar. El código que realmente se ejecuta no es exactamente el código que ejcutará nuestro servicio en su versión release.
Windows cuenta con un mecanismo que nos permite establecer un depurador para que se ejecute cuando se arranca un determinado ejecutable. El proceso, que es bastante tedioso, está sobradamente descrito en estos dos artículos: Debugging startup code of services and com servers y How to debug Windows services. He hecho un script de PowerShell que automatiza el proceso.
Os dejo el código de PowerShell, que además es un buen ejemplo sobre como trabajar con el registro y sobre como parsear parámetros de línea de comandos con PowerShell.
- #Script que automatiza el establecimiento de un depurador para que se inicie al inicia un servicio
- #El procedimiento está descrito en http://support.microsoft.com/kb/824344
-
- #Asegurarnos de que todas las variables son previamente declaradas
-
- param ( [switch] $Prepare,
- [switch] $Clean,
- [string] $ServiceName,
- [string] $ServiceExecutable )
-
- Set-PSDebug -Strict
-
- #Path al depurador que deseamos usar
- #Yo uso el depurado de VS pero podríamos usar windbg si el servicio fuese nativo y no .net
- $debuggerPath = «vsjitdebugger.exe»
- $imageFileExecutionOptionsPath = «HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionImage File Execution Options» + $ServiceExecutable
- $serviceRegistryPath = «HKLM:SYSTEMCurrentControlSetServices» + $ServiceName
- $servicesControlRegitryPath = «HKLM:SYSTEMCurrentControlSetControl»
-
- function Usage()
- {
- «Establece las claves del registro necesarias para que el depurador se adjunte automáticamente al proceso de un servicio cuando este se ejecuta.»
- «Puede ser necesario reiniciar la máquina para que este script tenga efecto.»
- «Basicamente este script automatiza el proceso descrito en http://support.microsoft.com/kb/824344.»
- «»
- «Usage: Debug-Service -Prepare | -Clear -ServiceName <string> -ServiceExecutable <string>»
- «»
- «Parameters:»
- «-Prepare: Prepara el servicio especificado para su depuración.»
- «-Clear: Vuelve el servicio a su estado normal.»
-
- exit
- }
-
- function Prepare()
- {
- #Configuramos en el registro el depurador a iniciar cuando se arranque el servicio
- if ( !(Test-Path $imageFileExecutionOptionsPath))
- {
- New-Item -path $imageFileExecutionOptionsPath | out-null
- }
-
- Set-ItemProperty -path $imageFileExecutionOptionsPath -name «debugger» -value $debuggerPath
-
- #Configuramos el servicio como interactivo para que se pueda mostrar la ventana del depurador
- $serviceTypeValue = (Get-ItemProperty -path $serviceRegistryPath).Type
- $serviceTypeValue = $serviceTypeValue -bor 0x00000100
- Set-ItemProperty -path $serviceRegistryPath -name «Type» -value $serviceTypeValue
- #Establecemos el arranque del servicio a manual
- Set-ItemProperty -path $serviceRegistryPath -name «Start» -value 3
-
- #Configuramos el tiempo de timeout para el arranque de los servicios en 24 horas para tener margen para depurar
- Set-ItemProperty -path $servicesControlRegitryPath -name «ServicesPipeTimeout» -value 86400000
- }
-
- function Clean()
- {
- if ( (Test-Path $imageFileExecutionOptionsPath))
- {
- Remove-Item -path $imageFileExecutionOptionsPath
- }
-
- Remove-ItemProperty -path $servicesControlRegitryPath -name «ServicesPipeTimeout»
- }
-
- if (!($Prepare -or $Clean) -or !($ServiceName -and $ServiceExecutable))
- {
- Usage
- }
-
- if ($Prepare -and $Clean)
- {
- Write-Warning «No se puede usar Prepare y Clean a la vez»
- exit
- }
-
- if ($Prepare)
- {
- Prepare
- }
-
- if ($Clean)
- {
- Clean
- }