Depurar servicios con ayuda de PowerShell
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.
-
-
-
-
-
- param ( [switch] $Prepare,
- [switch] $Clean,
- [string] $ServiceName,
- [string] $ServiceExecutable )
-
- Set-PSDebug -Strict
-
-
-
- $debuggerPath = "vsjitdebugger.exe"
- $imageFileExecutionOptionsPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\" + $ServiceExecutable
- $serviceRegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\" + $ServiceName
- $servicesControlRegitryPath = "HKLM:\SYSTEM\CurrentControlSet\Control"
-
- 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()
- {
-
- if ( !(Test-Path $imageFileExecutionOptionsPath))
- {
- New-Item -path $imageFileExecutionOptionsPath | out-null
- }
-
- Set-ItemProperty -path $imageFileExecutionOptionsPath -name "debugger" -value $debuggerPath
-
-
- $serviceTypeValue = (Get-ItemProperty -path $serviceRegistryPath).Type
- $serviceTypeValue = $serviceTypeValue -bor 0x00000100
- Set-ItemProperty -path $serviceRegistryPath -name "Type" -value $serviceTypeValue
-
- Set-ItemProperty -path $serviceRegistryPath -name "Start" -value 3
-
-
- 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
- }