How to create a Windows Service with PowerShell: step by step
Creating a Windows Service with PowerShell lets you run scripts or applications in the background as services managed by the Service Control Manager. This process is useful to automate tasks that must run whenever the system boots or to have better control over start/stop, restart and dependencies.
Prerequisites
- Windows 10/11 or Windows Server with administrator permissions.
- PowerShell 5.1 or PowerShell 7+ (to create and manage files and services).
- A PowerShell script or a simple executable to run as a service (e.g.: script.ps1).
Step 1: Prepare a simple PowerShell wrapper
Windows Services expect an executable. The simple approach is to use a small wrapper that runs your script in a loop and responds to stop signals. Let’s create a file named ServiceWrapper.ps1 that handles start/stop and logs basic events.
# ServiceWrapper.ps1
param(
[string]$ScriptToRun = "C:\path\to\script.ps1",
[int]$IntervalSeconds = 60
)
$stopRequested = $false
# Capturar Ctrl+C/Stop
Register-ObjectEvent -InputObject $Host -EventName 'CancelKeyPress' -Action { $global:stopRequested = $true } | Out-Null
Write-EventLog -LogName Application -Source "MyPowerShellService" -EntryType Information -EventId 1000 -Message "Service starting"
while (-not $stopRequested) {
try {
& powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File $ScriptToRun
}
catch {
Write-EventLog -LogName Application -Source "MyPowerShellService" -EntryType Error -EventId 1001 -Message "Script error: $_"
}
Start-Sleep -Seconds $IntervalSeconds
}
Write-EventLog -LogName Application -Source "MyPowerShellService" -EntryType Information -EventId 1002 -Message "Service stopping"
Step 2: Create an executable launcher with PowerShell
To register a service it’s more practical to have a small launcher exe. We can use the sc.exe utility to point to an instance of cmd.exe that invokes PowerShell. This avoids external tools. Here we create the service to run cmd.exe /c powershell -File ServiceWrapper.ps1.
# Abrir PowerShell como Administrador e correr:
$serviceName = "MyPowerShellService"
$displayName = "My PowerShell Service"
$wrapperPath = 'C:\services\ServiceWrapper.ps1' # caminho absoluto
$cmd = "C:\Windows\System32\cmd.exe /c powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File `"$wrapperPath`""
sc.exe create $serviceName binPath= "$cmd" start= auto DisplayName= "$displayName"
# Conceder permissão de escrever no Event Log (opcional, se usar Write-EventLog)
New-EventLog -LogName Application -Source "MyPowerShellService" -ErrorAction SilentlyContinue
Step 3: Configure service account and dependencies
By default the service runs as LocalSystem. If the script needs network access or a specific account, change the account with sc.exe config. You can also add dependencies with the depend= tag.
# Exemplo: configurar para usar uma conta de domínio
sc.exe config MyPowerShellService obj= "DOMAIN\ServiceUser" password= "P@ssw0rd"
# Exemplo: adicionar dependência no serviço de rede
sc.exe config MyPowerShellService depend= Tcpip/WinSock
Step 4: Control the service (start, stop, restart)
Use simple commands to manage the service. In case of issues, check the Event Viewer and your script’s log files.
# Iniciar o serviço
Start-Service -Name MyPowerShellService
# Verificar estado
Get-Service -Name MyPowerShellService | Format-List Name,Status,ServiceType
# Parar o serviço
Stop-Service -Name MyPowerShellService -Force
# Reiniciar
Restart-Service -Name MyPowerShellService
Verify the result
Confirm that the service appears and runs as expected: Get-Service shows Status = Running. Check the Event Viewer (Application) for entries with Source = MyPowerShellService and EventId 1000/1002. If your script writes log files, confirm they are updated according to IntervalSeconds.
Conclusion
You now have a basic Windows Service that runs a PowerShell script in the background and responds to start/stop. Next steps: protect credentials with the Windows Credential Manager, create more robust logs or package the wrapper as an EXE with tools like PS2EXE for greater control. Tip: always test the wrapper manually before registering the service to avoid unwanted loops.