PowerShell: Ensure services are always on
Elias Hensman
CEO of ChitChat | Cloud Engineer | AI-Powered Language Learning Enthusiast
...to the best of our ability given the limitation that sometimes the issue is a problem code can't fix.
High-Level Overview:
cls ?
?
# Call program desired frequency using task scheduler
?
# Service you'd like to monitor...
$ServiceName = "spooler"
$ServiceObj = Get-Service -Name $ServiceName
$StatusMessage = "Service status:", $ServiceObj.status ?
?
?
?
if ($ServiceObj.Status -ne 'Running')
{ ???????????
???Restart-Service $ServiceName
???for ($i = 70; $i -le 100; $i++ ) {
???????Write-Progress -Activity "$StatusMessage. Attempting to restart.." -Status "$i% Complete:" -PercentComplete $i
???????Start-Sleep -Seconds 1
???}
??Write-Progress -Completed -Activity "Completed"
??Start-Sleep -Seconds 1
?
???$ServiceObj.Refresh() ?
?????????
???if ($ServiceObj.Status -eq 'Running') ???
???{
???????Clear-Host
???????Write-Host "The $ServiceName service is running."
???} ??
???else {
???????Clear-Host
???????for ($i = 70; $i -le 100; $i++ ) {
???????Write-Progress -Activity "$StatusMessage. Waiting.." -Status "$i% Complete:" -PercentComplete $i
???????Start-Sleep -Seconds 1
???}
??Write-Progress -Completed -Activity "Completed"
??Start-Sleep -Seconds 1
?
???$ServiceObj.Refresh()
?
???if ($ServiceObj.Status -eq 'Running') ???
???????{
???????????Clear-Host
???????????Write-Host "The $ServiceName service is running."
???????} ??
???????else {
??????????for ($i = 70; $i -le 100; $i++ ) {
??????? ???????Write-Progress -Activity "Service still not running. Attempting to kill and restart it.." -Status "$i% Complete:" -PercentComplete $i
??????? ???????Start-Sleep -Seconds 1
??? ????????}
??????????Write-Progress -Completed -Activity "Completed"
??????????Start-Sleep -Seconds 1
?
???????????$service = Get-CimInstance -class win32_service | Where-Object name -eq $ServiceName | select name, processid
???????????$process = Get-Process | Where-Object ID -EQ $service.processid
?
???????????taskkill /f /pid $process.Id
???????????Restart-Service $ServiceName
???????????for ($i = 70; $i -le 100; $i++ ) {
??????? ???????Write-Progress -Activity "Waiting for results.." -Status "$i% Complete:" -PercentComplete $i
??????? ???????Start-Sleep -Seconds 1
??? ????????}
??????????Write-Progress -Completed -Activity "Completed"
??????????Start-Sleep -Seconds 1
?
???????????????if ($ServiceObj.Status -eq 'Running') ???
???????????????{
???????????????????Clear-Host
???????????????????Write-Host "The $ServiceName service is running."
???????????????}
???????????????else {
??????????????????$StatusMessage = "Service status:", $ServiceObj.status
?
???????????????????Clear-Host
??????????????????Write-Host ""
??????????????????Write-Host "$StatusMessage"
??????????????????Write-Host ""
???????????????????Write-Host 'Recommended actions:
????- Run "sfc /scannow"
????- Run "chkdsk /r"
????- Restart the computer
?
???????????????????'
??????????????????Write-Host "Event Log entry made."
??????????????????Write-EventLog -LogName "Application" -Source "EnsureServicesOn" -EventID 3001 -EntryType Error -Message 'Despite killing the $ServiceName service, restarting it, and giving it some time to start running again, it would not enter a running state. Recommended next steps: Try "sfc /scannow", "chkdsk /r" and then restarting the computer. '
?
?
???????????????}
?
???????????}
???????}
?
???}
Deep-dive:
First, we're clearing the console with "cls" because I like to be neat. Then I'm defining variables we'll use later on throughout the code (text that starts with a $). $ServiceObj is used for us to get information about the service we specified earlier. $StatusMessage is so that I can write less later on.
cls ?
?
# Call program desired frequency using task scheduler
?
# Service you'd like to monitor...
$ServiceName = "spooler"
$ServiceObj = Get-Service -Name $ServiceName
$StatusMessage = "Service status:", $ServiceObj.status ?
The if statement checks if the service is not equal to "Running". If so, we restart the service. The next bit of logic after "for" is to create a pretty GUI progress bar that appears to the user. I have it set to run for thirty seconds and display a message informing the user of what the service state was and that we're attempting to restart it. After those thirty seconds the "Write-Progress -Completed" line makes the progress bar go away. Otherwise you'll have a completed progress bar doing nothing other than taking up space on your console. "Start-Sleep" is used to make the program pause for a second. I put it there because otherwise it'll go immediately to the next visual element which I found to make the user experience choppy.
if ($ServiceObj.Status -ne 'Running')
{ ???????????
???Restart-Service $ServiceName
???for ($i = 70; $i -le 100; $i++ ) {
???????Write-Progress -Activity "$StatusMessage. Attempting to restart.." -Status "$i% Complete:" -PercentComplete $i
???????Start-Sleep -Seconds 1
???}
??Write-Progress -Completed -Activity "Completed"
??Start-Sleep -Seconds 1
"$ServiceObj.Refresh()"; "$ServiceObj" is our variable from before and ".Refresh()" is called a method which in this case allows us to retrieve the service's state again to ensure we're dealing with current data. The rest of the code you should be familiar with. We're waiting another thirty seconds to see if the service has started running.
领英推荐
$ServiceObj.Refresh() ?
?????????
???if ($ServiceObj.Status -eq 'Running') ???
???{
???????Clear-Host
???????Write-Host "The $ServiceName service is running."
???} ??
???else {
???????Clear-Host
???????for ($i = 70; $i -le 100; $i++ ) {
???????Write-Progress -Activity "$StatusMessage. Waiting.." -Status "$i% Complete:" -PercentComplete $i
???????Start-Sleep -Seconds 1
???}
??Write-Progress -Completed -Activity "Completed"
??Start-Sleep -Seconds 1
?
???$ServiceObj.Refresh()
Nothing is new here. Since it has been found that the specified service wasn't running the two times we checked it earlier, we're going to try and kill it instead of just restart it. Sometimes the service will respond to a kill command as opposed to a "Restart-Service" or "Stop-Service" command. The reason for this is because when you stop a service, the operating system is told to pause the service's main functions, allow for back-end things to occur like the application to write log files or save data etc. and then terminate the service. With a kill command, the OS immediately terminates everything to do with that service. This bit of code prepares us for actually doing what I've described in the next section.
if ($ServiceObj.Status -eq 'Running') ???
???????{
???????????Clear-Host
???????????Write-Host "The $ServiceName service is running."
???????} ??
???????else {
??????????for ($i = 70; $i -le 100; $i++ ) {
??????? ???????Write-Progress -Activity "Service still not running. Attempting to kill and restart it.." -Status "$i% Complete:" -PercentComplete $i
??????? ???????Start-Sleep -Seconds 1
??? ????????}
??????????Write-Progress -Completed -Activity "Completed"
??????????Start-Sleep -Seconds 1
In the very beginning we wrote "Get-Process" to get access to some information that came along with the service. Unfortunately it doesn't have the information we need here- the process ID. We need the process ID because later on there's a command we'll use that requires it. "$service" and "$process" in conjunction get us that information (in reality they get us more than just that information that's why I used pipes ["|"] to parse through the array of data found). "taskkill" is the kill command we spoke about earlier with "/f" relaying that we want to "forcefully end" the service.
$service = Get-CimInstance -class win32_service | Where-Object name -eq $ServiceName | select name, processid
???????????$process = Get-Process | Where-Object ID -EQ $service.processid
?
???????????taskkill /f /pid $process.Id
???????????Restart-Service $ServiceName
???????????for ($i = 70; $i -le 100; $i++ ) {
??????? ???????Write-Progress -Activity "Waiting for results.." -Status "$i% Complete:" -PercentComplete $i
??????? ???????Start-Sleep -Seconds 1
??? ????????}
??????????Write-Progress -Completed -Activity "Completed"
??????????Start-Sleep -Seconds 1
You've seen the beginning portion a dozen times now. Although, the group of "Write-Host" commands is noteworthy. I'm writing a message to the user that the service in this case has still not been successful and recommending them to run those commands into a PowerShell or cmd prompt. "sfc /scannow" replaces corrupted system files (can happen overtime without foul play- hackers etc.) with a cached copy. "Chkdsk /r" attempts to repair corrupted portions of your hard drive. Lastly, "Write-EventLog". I'm going to assume that you know what event logs are. I'm creating one with that line that contains custom information, including the event ID number. All of it there was chosen because I thought it was logical and aesthetically pleasing. You can ask me about it if you're curious.
}
??????????Write-Progress -Completed -Activity "Completed"
??????????Start-Sleep -Seconds 1
?
???????????????if ($ServiceObj.Status -eq 'Running') ???
???????????????{
???????????????????Clear-Host
???????????????????Write-Host "The $ServiceName service is running."
???????????????}
???????????????else {
??????????????????$StatusMessage = "Service status:", $ServiceObj.status
?
???????????????????Clear-Host
??????????????????Write-Host ""
??????????????????Write-Host "$StatusMessage"
??????????????????Write-Host ""
???????????????????Write-Host 'Recommended actions:
????- Run "sfc /scannow"
????- Run "chkdsk /r"
????- Restart the computer
?
???????????????????'
??????????????????Write-Host "Event Log entry made."
??????????????????Write-EventLog -LogName "Application" -Source "EnsureServicesOn" -EventID 3001 -EntryType Error -Message 'Despite killing the $ServiceName service, restarting it, and giving it some time to start running again, it would not enter a running state. Recommended next steps: Try "sfc /scannow", "chkdsk /r" and then restarting the computer. '
?
?
???????????????}
?
???????????}
???????}
?
???}
That's it! Thanks for reading!! Let me know if you have any issues and I'd be happy to help or I'm always open to feedback. Take care!
Improvements that could be made: