How to Manage Services with PowerShell on Windows Server 2012 R2
Windows services are long-running executable programs that perform specific system or application functions. Every major server role — IIS, SQL Server, Active Directory, DNS, DHCP, and dozens of others — relies on one or more Windows services. Effective service management is fundamental to server administration: knowing how to start, stop, and restart services; configure startup types; monitor for unexpected service stops; and manage service account credentials are all routine tasks that PowerShell handles far more efficiently than the Services MMC or sc.exe command.
Windows Server 2012 R2 provides service management through multiple PowerShell approaches: the ServiceController cmdlets (Get-Service, Start-Service, etc.), WMI via Get-WmiObject Win32_Service, and the ScheduledTask pattern for services that need to be monitored and auto-restarted. This guide covers the complete service management lifecycle using PowerShell, including advanced scenarios like service recovery configuration, service dependencies, and bulk service operations across multiple servers.
Prerequisites
– Windows Server 2012 R2 with PowerShell 4.0
– Administrative credentials for service management
– For remote management: WinRM enabled on target servers
Step 1: View and Filter Services
# List all services with basic information
Get-Service | Select-Object Name, DisplayName, Status, StartType | Sort-Object DisplayName
# Filter by status
Get-Service | Where-Object Status -eq "Running" | Select-Object Name, DisplayName | Sort-Object Name
Get-Service | Where-Object Status -eq "Stopped" | Select-Object Name, DisplayName | Sort-Object Name
# Find stopped automatic-start services (unexpected stops)
Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName, Status, StartType
# Get detailed service information via WMI
Get-WmiObject Win32_Service | Select-Object Name, DisplayName, State, StartMode, StartName, PathName |
Sort-Object DisplayName | Format-List
# Find services running as a specific account
Get-WmiObject Win32_Service -Filter "StartName='DOMAIN\svc-webserver'" |
Select-Object Name, DisplayName, State, StartMode
Step 2: Start, Stop, and Restart Services
# Stop a service
Stop-Service -Name "W3SVC" -Force
# -Force stops dependent services as well
# Start a service
Start-Service -Name "W3SVC"
# Restart a service (stop then start)
Restart-Service -Name "W3SVC" -Force
# Suspend (pause) a service if it supports pausing
Suspend-Service -Name "MSSQLSERVER"
# Resume a paused service
Resume-Service -Name "MSSQLSERVER"
# Wait for service to reach desired state with timeout
$timeoutSeconds = 30
$startTime = Get-Date
Start-Service "W3SVC"
while ((Get-Service "W3SVC").Status -ne "Running") {
if (((Get-Date) - $startTime).TotalSeconds -gt $timeoutSeconds) {
throw "Service W3SVC did not start within $timeoutSeconds seconds"
}
Start-Sleep -Seconds 2
}
Write-Host "W3SVC is now Running"
Step 3: Configure Service Startup Types
# Change service startup type
Set-Service -Name "Spooler" -StartupType Automatic
Set-Service -Name "Spooler" -StartupType Manual
Set-Service -Name "Spooler" -StartupType Disabled
# Startup type options: Automatic, Manual, Disabled
# Note: "Automatic (Delayed Start)" requires WMI:
$svc = Get-WmiObject Win32_Service -Filter "Name='MyService'"
$svc.ChangeStartMode("Automatic") | Out-Null
# Set delayed auto-start via registry:
Set-ItemProperty -Path "HKLM:SYSTEMCurrentControlSetServicesMyService" `
-Name "DelayedAutoStart" -Value 1 -Type DWord
# Disable a list of unnecessary services for security hardening
$servicesToDisable = @(
"Browser", # Computer Browser (disable in pure Active Directory environments)
"RemoteRegistry", # Remote Registry (disable if not needed)
"Telnet", # Telnet service (rarely needed)
"TFTP", # TFTP service
"SSDPSRV", # SSDP Discovery (UPnP)
"upnphost" # UPnP Device Host
)
foreach ($svc in $servicesToDisable) {
if (Get-Service $svc -ErrorAction SilentlyContinue) {
Stop-Service $svc -Force -ErrorAction SilentlyContinue
Set-Service $svc -StartupType Disabled
Write-Host "Disabled: $svc"
}
}
Step 4: Configure Service Recovery Actions
Windows services can be configured to automatically restart when they crash. This is configured through sc.exe since PowerShell cmdlets don’t expose recovery action settings:
# Configure recovery actions using sc.exe
# Actions: restart, run (run a program), reboot
# Failure count resets after: 86400 seconds (1 day)
# Wait before restart: 5000 ms (5 seconds)
sc.exe failure "W3SVC" reset= 86400 actions= restart/5000/restart/5000/restart/10000
# Configure with a notification command on third failure
sc.exe failure "MyApp" reset= 86400 `
actions= restart/5000/restart/5000/""/0 `
command= "powershell.exe -File C:ScriptsServiceCrashAlert.ps1 -ServiceName MyApp"
# Verify failure configuration
sc.exe qfailure "W3SVC"
# Using WMI to check current failure configuration
(Get-WmiObject Win32_Service -Filter "Name='W3SVC'").FailureActions
Step 5: Change Service Account Credentials
# Change the account a service runs under
$svc = Get-WmiObject Win32_Service -Filter "Name='MyApplicationService'"
$result = $svc.Change($null,$null,$null,$null,$null,$null,"DOMAINsvc-myapp","NewP@ssword123!",$null,$null,$null)
if ($result.ReturnValue -eq 0) {
Write-Host "Service account updated successfully"
} else {
Write-Host "Error updating service account. Return value: $($result.ReturnValue)"
}
# Restart service to apply new credentials
Restart-Service "MyApplicationService"
# Verify new account
(Get-WmiObject Win32_Service -Filter "Name='MyApplicationService'").StartName
# Update service password only (same account, new password)
$svc = Get-WmiObject Win32_Service -Filter "Name='MyApplicationService'"
$svc.Change($null,$null,$null,$null,$null,$null,$null,"UpdatedP@ssword456!") | Out-Null
Step 6: Monitor Services Across Multiple Servers
# Get service status from multiple servers simultaneously
$servers = @("WebServer01","AppServer01","DBServer01","FileServer01")
$criticalServices = @("W3SVC","MSSQLSERVER","DNS","NTDS","BITS","WinRM")
$serviceReport = Invoke-Command -ComputerName $servers -ScriptBlock {
param($services)
foreach ($svcName in $services) {
$svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
[PSCustomObject]@{
Server = $env:COMPUTERNAME
ServiceName = $svcName
Status = if ($svc) { $svc.Status } else { "Not Installed" }
StartType = if ($svc) { $svc.StartType } else { "N/A" }
}
}
} -ArgumentList @(,$criticalServices)
# Show services that are NOT running
$serviceReport | Where-Object { $_.Status -ne "Running" } |
Sort-Object Server, ServiceName |
Format-Table -AutoSize
Step 7: Set Up Service Watchdog with Scheduled Task
Create a scheduled task that monitors critical services and restarts them if they stop:
# Create a service watchdog script
$watchdogScript = @'
$criticalServices = @("W3SVC","MSSQLSERVER","AppPool01")
$logFile = "C:LogsServiceWatchdog_$(Get-Date -Format yyyyMMdd).log"
foreach ($svcName in $criticalServices) {
$svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
if ($svc -and $svc.Status -ne "Running" -and $svc.StartType -ne "Disabled") {
$msg = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $svcName was stopped. Attempting restart..."
Add-Content $logFile $msg
Write-EventLog -LogName Application -Source "ServiceWatchdog" -EventId 9001 -EntryType Warning -Message $msg
try {
Start-Service $svcName -ErrorAction Stop
Add-Content $logFile "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $svcName restarted successfully"
} catch {
Add-Content $logFile "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - FAILED to restart $svcName: $_"
Write-EventLog -LogName Application -Source "ServiceWatchdog" -EventId 9002 -EntryType Error -Message "Failed to restart $svcName: $_"
}
}
}
'@
$watchdogScript | Out-File "C:ScriptsServiceWatchdog.ps1" -Encoding UTF8
# Register the event source
if (-not [System.Diagnostics.EventLog]::SourceExists("ServiceWatchdog")) {
New-EventLog -LogName Application -Source "ServiceWatchdog"
}
# Create the scheduled task
Register-ScheduledTask `
-TaskName "ServiceWatchdog" `
-TaskPath "Monitoring" `
-Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NonInteractive -NoProfile -File C:ScriptsServiceWatchdog.ps1") `
-Trigger (New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 5) -Once -At "12:00AM") `
-Principal (New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest) `
-Settings (New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2))
Step 8: View Service Dependencies
# View services that depend on a specific service
(Get-Service W3SVC).DependentServices | Select-Object Name, DisplayName, Status
# View services that a specific service depends on
(Get-Service W3SVC).ServicesDependedOn | Select-Object Name, DisplayName, Status
# Build a full dependency tree
function Get-ServiceDependencyTree {
param([string]$ServiceName, [int]$Depth = 0)
$svc = Get-Service $ServiceName -ErrorAction SilentlyContinue
if (-not $svc) { return }
$indent = " " * $Depth
Write-Host "$indent$($svc.Name) ($($svc.Status))"
foreach ($dep in $svc.ServicesDependedOn) {
Get-ServiceDependencyTree -ServiceName $dep.Name -Depth ($Depth + 1)
}
}
Get-ServiceDependencyTree "W3SVC"
Step 9: Create a New Windows Service
# Register a new service (for custom applications)
New-Service -Name "MyCustomApp" `
-DisplayName "My Custom Application Service" `
-Description "Custom application service for data processing" `
-BinaryPathName "C:AppsMyAppservice.exe --mode service" `
-StartupType Automatic `
-Credential (Get-Credential "DOMAINsvc-myapp")
# Start the new service
Start-Service MyCustomApp
# Verify service registration
Get-WmiObject Win32_Service -Filter "Name='MyCustomApp'" |
Select-Object Name, DisplayName, State, StartMode, PathName, StartName
Step 10: Remove a Service
# Stop the service before removal
Stop-Service "MyCustomApp" -Force
# Remove via sc.exe (no native PowerShell cmdlet for service removal in PS 4.0)
sc.exe delete "MyCustomApp"
# Verify removal
Get-Service "MyCustomApp" -ErrorAction SilentlyContinue
# In PowerShell 5+ (WS2016+), you can use Remove-Service:
# Remove-Service -Name "MyCustomApp"
# Clean up any related registry entries
Remove-Item "HKLM:SYSTEMCurrentControlSetServicesMyCustomApp" -Recurse -Force -ErrorAction SilentlyContinue
Summary
PowerShell provides comprehensive service management capabilities on Windows Server 2012 R2, from basic start/stop operations through advanced scenarios like bulk service auditing across server farms, automatic service watchdog monitoring, and service recovery configuration. The combination of native ServiceController cmdlets for simple operations and WMI-based Win32_Service queries for detailed information and modifications creates a complete service management toolkit. Establishing automated monitoring — scheduled scripts that check for stopped critical services and restart them while logging the event — significantly improves server reliability and reduces the time between a service failure and recovery.