Powershell to restart a service running longer than - powershell

I'm trying to write a powershell script that will:
Restart a service if it has been running more than 1 hour
Leave it alone if less than 1 hour
Start it if it's in the stopped state.
I currently have the following below but when it comes to adding extra variables and if statements I'm terrible. This script works very well, but I can't get it to restart, only start/stop seem to work.
Get-Service "Print Spooler" |
Where StartTime -lt (Get-Date).AddMinutes(-60) |
Stop-Service

I'd suggest a variable for this:
# for debugging
$PSDefaultParameterValues['*Service:Verbose'] = $true
$svc = Get-Service -Name Spooler
if ($svc.Status -eq 'stopped') {
$svc | Start-Service
} elseif ($svc.StartTime -lt (Get-Date).AddHours(-1)) {
$svc | Stop-Service -PassThru | Start-Service
} else {
'Print Spooler is running and StartTime is within the past hour!'
}
# other logic goes here

StartTime doesn't appear to be a property of the ServiceController class that Get-Service returns on my system. Neither is the service's process ID, absurdly enough. That's infuriatingly poor design, but so it goes. So, I'd use CIM/WMI to get the process ID to determine when the service started.
$Service = Get-Service "Print Spooler"
$ServiceStartTime = (Get-CimInstance -ClassName Win32_Service -Filter "Name = '$($Service.Name)'" -Property ProcessId | ForEach-Object { Get-Process -Id $_.ProcessId }).StartTime
# If services has been running for an hour, stop it
if (($Service.Status -eq 'Running') -and ($ServiceStartTime -lt (Get-Date).AddHours(-1))) {
Stop-Service $Service
}
# If service isn't running, start it
if ($Service.Status -eq 'Stopped') {
Start-Service $Service
}

Related

Is There a function to bypass dependent services when stoping a service in Powershell?

I have some issues with my Powershell code
I need to stop and disable some services with this script BUT there are some issues, here it is:
Get-Content -path $PWD\servicestop1.txt | ForEach-Object
{
$service = $_
(Set-Service -Name $service -Status Stopped -StartupType Disabled -PassThru )
}
1 - I encounter some dependencies issue when I want to stop some services
2 - I can't get to disable and stop them in the same script
Do you have any idea?
Thanks a lot!
PS: I tried to use the parameter "-force" but it didn't work
Without knowing the servicestop1.txt actually holds valid service names, You may try this:
Get-Content -Path "$PWD\servicestop1.txt" | ForEach-Object {
$service = Get-Service -Name $_ -ErrorAction SilentlyContinue
if ($service) {
if ($service.Status -eq 'Running') {
# stop the service and wait for it
$service | Stop-Service -Force
}
if ($service.StartType -ne 'Disabled') {
$service | Set-Service -StartupType Disabled
}
}
else {
Write-Warning "Could not find service with name '$_'"
}
}

How to filter the output of get-service so it won't show stopped services

I'm very sure this is something easy but since I am new in powershell I couldn't figure out a way to do it. The following command:
Get-Service | Sort-Object -Property status -Descending
displays services on the PC, sorts them by status so it shows running processes in the beginning of the list. Stopped services come right after started services Can I do any filter so it won't show stopped services?
Please get in the habit of not using abbreviations when posting codes on online forum for this post and all other posts.
Thank You!
Get-Service |
Where-Object { $Psitem.Status -ne 'Stopped' } |
Sort-Object -Property status -Descending
This effectively filters by status.
Depending on the PowerShell version ($PSVersionTable.PSVersion)
You can run two commands:
PS Version 2.0 get-service | where {$_.status -eq 'running'}
PS Version 3.0 or greater get-service | where status -eq 'running'
PS Version 3.0 or greater get-service | ? status -eq 'running'
The big differance between the two versions are the {Curly brackets} and you can also use Alias Get-Alias
The following function will allow you to select only one service that you want to stop. After time of your choice currently 5 minutes. The service will start again. The GUI option does allow you to start and stop when you choose.
Stop a Service
Function ManageService{
$Service=Get-Service | where {$_.status -eq 'running'} | Out-GridView -OutputMode Single
$GUI = new-object -comobject wscript.shell
if ($Service.Status -eq "Running"){
$ServiceName=$Service.DisplayName
$Yes_Cancle = $GUI.popup("Do you want to turn stop $ServiceName ?", `
0,"Manage Service",3)
If ($Yes_Cancle -eq 6) {
Stop-Service $ServiceName
$GUI.popup("$ServiceName service has been STOPPED and will START again in 5 minutes, soon as you hit OK")
start-Sleep -s 300
$GUI.popup("Time is up! $ServiceName service will now start as soon as you hit OK")
Start-Service $ServiceName
cls
}
else {
$GUI.popup("You decided to cancel. $ServiceName will not be stopped")
cls
}}}
cls
ManageService
Kill a Process
Function ManageProcess{
$Process=Get-Process | Out-GridView -OutputMode Single
$GUI = new-object -comobject wscript.shell
if ($Process.processname -ne "$False"){
$ProcessName=$Process.processname
$Yes_Cancle = $GUI.popup("Do you want to turn kill $ProcessName ?", `
0,"Manage Process",3)
If ($Yes_Cancle -eq 6) {
Stop-Process -processname $ProcessName
$GUI.popup("$ProcessName has been killed as soon as you hit OK")
cls
}
else {
$GUI.popup("You decided to cancel. $ProcessName will not be killed")
cls
}}}
cls
ManageProcess

Powershell script to check if service is started, if not then start it

I have built a small powershell script to check if a service is started. If it is not started, try to start it then wait one minute and check again. Keep repeating this process until the service start successfully. I have found the loop does not behave the way I expected in that I seem to have to re-assign the service variable within the loop in order to get the updated status. Here is my code:
$ServiceName = 'Serenade'
$arrService = Get-Service -Name $ServiceName
if ($arrService.Status -ne 'Running'){
$ServiceStarted = $false}
Else{$ServiceStarted = $true}
while ($ServiceStarted -ne $true){
Start-Service $ServiceName
write-host $arrService.status
write-host 'Service started'
Start-Sleep -seconds 60
$arrService = Get-Service -Name $ServiceName #Why is this line needed?
if ($arrService.Status -eq 'Running'){
$ServiceStarted = $true}
}
If I run the code without the third last line (the one with the comment), I get the following output. I can check in the Windows service manager and the service was clearly started after the first loop. Why is that third last line required?
Given this behavior, is there a better way to write this code?
Thank you
I think you may have over-complicated your code: If you are just checking to see if a service is running and, if not, run it and then stop re-evaluating, the following should suffice:
Good point on the refresh.
$ServiceName = 'Serenade'
$arrService = Get-Service -Name $ServiceName
while ($arrService.Status -ne 'Running')
{
Start-Service $ServiceName
write-host $arrService.status
write-host 'Service starting'
Start-Sleep -seconds 60
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host 'Service is now Running'
}
}
A potentially simpler solution:
get-service "servicename*" | Where {$_.Status -neq 'Running'} | start-service
Given $arrService = Get-Service -Name $ServiceName, $arrService.Status is a static property, corresponding to the value at the time of the call. Use $arrService.Refresh() when needed to renew the properties to current values.
MSDN ~ ServiceController.Refresh()
Refreshes property values by resetting the properties to their current values.
Combining Alaa Akoum and Nick Eagle's solutions allowed me to loop through a series of windows services and stop them if they're running.
# stop the following Windows services in the specified order:
[Array] $Services = 'Service1','Service2','Service3','Service4','Service5';
# loop through each service, if its running, stop it
foreach($ServiceName in $Services)
{
$arrService = Get-Service -Name $ServiceName
write-host $ServiceName
while ($arrService.Status -eq 'Running')
{
Stop-Service $ServiceName
write-host $arrService.status
write-host 'Service stopping'
Start-Sleep -seconds 60
$arrService.Refresh()
if ($arrService.Status -eq 'Stopped')
{
Write-Host 'Service is now Stopped'
}
}
}
The same can be done to start a series of service if they are not running:
# start the following Windows services in the specified order:
[Array] $Services = 'Service1','Service2','Service3','Service4','Service5';
# loop through each service, if its not running, start it
foreach($ServiceName in $Services)
{
$arrService = Get-Service -Name $ServiceName
write-host $ServiceName
while ($arrService.Status -ne 'Running')
{
Start-Service $ServiceName
write-host $arrService.status
write-host 'Service starting'
Start-Sleep -seconds 60
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host 'Service is now Running'
}
}
}
The below is a compact script that will check if "running" and attempt start service until the service returns as running.
$Service = 'ServiceName'
If ((Get-Service $Service).Status -ne 'Running') {
do {
Start-Service $Service -ErrorAction SilentlyContinue
Start-Sleep 10
} until ((Get-Service $Service).Status -eq 'Running')
} Return "$($Service) has STARTED"
$ServiceName = 'Serenade'
$arrService = Get-Service -Name $ServiceName
while ($arrService.Status -ne 'Running')
{
Start-Service $ServiceName
write-host $arrService.status
write-host 'Service starting'
Start-Sleep -seconds 60
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host 'Service is now Running'
}
}
Can we use the same script for multiple services and send a single email if services are down.
[Array] $servers = "Server1","server2";
$service='YOUR SERVICE'
foreach($server in $servers)
{
$srvc = Get-WmiObject -query "SELECT * FROM win32_service WHERE name LIKE '$service' " -computername $server ;
$res=Write-Output $srvc | Format-Table -AutoSize $server, $fmtMode, $fmtState, $fmtStatus ;
$srvc.startservice()
$res
}
Trying to do things as smooth as possible - I here suggest modifying GuyWhoLikesPowershell's suggestion slightly.
I replaced the if and until with one while - and I check for "Stopped", since I don't want to start if status is "starting" or " Stopping".
$Service = 'ServiceName'
while ((Get-Service $Service).Status -eq 'Stopped')
{
Start-Service $Service -ErrorAction SilentlyContinue
Start-Sleep 10
}
Return "$($Service) has STARTED"
In the spirit of Enterprise FizzBuzz, I wrote a version with extensive logging and handling for errors and Pending service states. It's likely over-engineered for most use cases. Please note this version is specifically intended be invoked by a Windows Scheduled Task on an interval. It runs for a specified number of tries on each run before stopping.
<#
.SYNOPSIS
This script attempts to Start the specified Windows service if the service is stopped and logs its attempts to a file.
It's intended to be deployed as a Windows Scheduled Task that runs every few minutes.
Please ensure the Scheduled Task interval is longer than (($secondsBeforeRetry + 10s) * $maxTries) to avoid concurrent running script instances.
The script first checks the existence of the log file and if not found creates a new one.
It then checks the status of the specified Windows service.
If it's not Stopped (implicitly Running), no actions occur and the script completes without logging anything.
If it's Stopped, the script attempts to Start it and logs success or failure.
If the service is still Stopped, the script will try to Start it again up to $maxTries times.
If the service is in a Starting (StartPending) or Stopping (StopPending) state, the script will recheck its status for
up to three $secondsBeforeRetry intervals to see if it changes.
If the service is still Pending after three checks, the process is likely hung and the script will attempt to force taskkill it.
References:
List of ServiceControllerStatus states: https://learn.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicecontrollerstatus?view=dotnet-plat-ext-6.0
The script does not handle the Paused, PausedPending, or ContinuePending service states.
#>
param (
# Specifies the service name
[Parameter(Mandatory = $true)]
[string]$serviceName,
# Specifies the directory for the log file
[Parameter(Mandatory = $false)]
[string]$logPath = 'C:\Scripts\Logs',
# Specifies the max number of service Start attempts per run
[Parameter(Mandatory = $false)]
[int]$maxTries = 3,
# Specifies the number of seconds to wait before trying again after a failed start attempt or before rechecking a Pending status
[Parameter(Mandatory = $false)]
[int]$secondsBeforeRetry = 30
)
$service = Get-Service $serviceName
$logName = $serviceName + 'AutoRestartLog.txt'
$logFullPath = Join-Path -Path $logPath -ChildPath $logName
if(!(Test-Path -Path $logFullPath)) {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
New-Item -Path $logPath -Name $logName -ItemType "file" -Value "## Log file for $serviceName auto-start script ##`n## Created [$timestamp] ##`n" -Force
Start-Sleep -s 1
}
if ($service.Status -eq 'Stopped') {
$tries = 0
while (($tries -lt $maxTries) -and ($service.Status -ne 'Running')) {
if ($tries -eq 0) {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStoppedMsg = "[$timestamp] $serviceName service status is $($service.Status), attempting to Start. Will try up to $maxTries times."
Add-Content -Path $logFullPath -Value $logSvcStoppedMsg
}
try {
Start-Service $ServiceName -ErrorAction Stop # Throws exception if command fails, for example if the service is Disabled
$tries += 1
Start-Sleep -s 10
$service.Refresh()
if ($service.Status -eq 'Running') {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStartSuccessMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)"
Add-Content -Path $logFullPath -Value $logSvcStartSuccessMsg
}
}
catch {
$errorMsg = $_
$tries += 1
Start-Sleep -s 10
$service.Refresh()
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStartExceptionMsg = "[$timestamp] Attempt #$tries - $serviceName service status is $($service.Status) and failed to start with error:`n $errorMsg"
Add-Content -Path $logFullPath -Value $logSvcStartExceptionMsg
if ($tries -ne $maxTries) {
Start-Sleep -s $secondsBeforeRetry
}
}
$service.Refresh()
if (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending')) {
$maxStateChecks = 3
$stateChecks = 0
while (($stateChecks -lt $maxStateChecks) -and (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending'))) {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStillPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status is $($service.Status). This may indicate the service is hung in the Starting or Stopping state. Waiting another $secondsBeforeRetry seconds before checking again."
Add-Content -Path $logFullPath -Value $logSvcStillPendingMsg
$stateChecks += 1
if ($stateChecks -ne $maxStateChecks) {
Start-Sleep -s $secondsBeforeRetry
}
$service.Refresh()
if ($service.Status -eq 'Running') {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStartSuccessMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)"
Add-Content -Path $logFullPath -Value $logSvcStartSuccessMsg
} elseif ($service.Status -eq 'Stopped') {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStoppedAfterPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status). If any Start attempts remain the script will try again on the next loop."
Add-Content -Path $logFullPath -Value $logSvcStoppedAfterPendingMsg
}
}
$service.Refresh()
if (($stateChecks -eq $maxStateChecks) -and (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending'))) {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStuckPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status appears stuck in a Pending (Starting or Stopping) state. Attempting to force kill process."
Add-Content -Path $logFullPath -Value $logSvcStuckPendingMsg
$servicePID = Get-CimInstance -Class Win32_Service -Filter "Name LIKE '$serviceName'" | Select-Object -ExpandProperty ProcessId
$resultMsg = taskkill /pid $servicePID /f
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcTaskKillMsg = "[$timestamp] Attempt #$tries - taskkill result:`n $resultMsg"
Add-Content -Path $logFullPath -Value $logSvcTaskKillMsg
Start-Sleep -s 10
$service.Refresh()
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logSvcStatusMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)"
Add-Content -Path $logFullPath -Value $logSvcStatusMsg
}
}
if (($tries -eq $maxTries) -and ($service.Status -ne 'Running')) {
$timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss)
$logNoMoreAttemptsMsg = "[$timestamp] $serviceName service status is $($service.Status) after $maxTries Start attempts. This run of the script will not continue trying to Start the service."
Add-Content -Path $logFullPath -Value $logNoMoreAttemptsMsg
}
}
# Add line break at end of log file entry
Add-Content -Path $logFullPath -Value "`n"
}
It outputs a log file that looks like this:
## Log file for Netman auto-start script ##
## Created [2022-07-11--22-55-38] ##
[2022-07-11--23-25-53] Netman service status is Stopped, attempting to Start. Will try up to 3 times.
[2022-07-11--23-26-03] Attempt #1 - Netman service status is Stopped and failed to start with error:
Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'.
[2022-07-11--23-26-43] Attempt #2 - Netman service status is Stopped and failed to start with error:
Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'.
[2022-07-11--23-27-23] Attempt #3 - Netman service status is Stopped and failed to start with error:
Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'.
[2022-07-11--23-27-53] Netman service status is Stopped after 3 Start attempts. This run of the script will not continue trying to Start the service.
[2022-07-12--01-46-15] Netman service status is Stopped, attempting to Start. Will try up to 3 times.
[2022-07-12--01-46-25] Attempt #1 - Netman service status is now Running
Start the service if it is stopped
Get-Service "servicename*" | Where {$_.Status -ne 'Stopped'} | Start-Service
Context
We have a product that has many variations and we work on them at once. Each variations has its own service. When multiple people work on the same version and one person manages to crash the service then someone needs to connect on the machine remotely and fix it.
Solution
So I made something that could manage multiple instances. Luckily all of them have the same prefix and Get-Service can take a "wildcard".
$ServiceName = 'ASService_*'; # Your wildcard goes here.
while ($true)
{
Get-Service $ServiceName | Where {$_.Status -eq 'Stopped'} | Foreach-Object {
Start-Service $_;
# Logging it so that you know it was you.
Get-Date;
Write-Output "``$($_.Name)`` has stopped running.";
}
Start-Sleep -Seconds 1;
}
This can be further simplified if you don't care about logs.
$ServiceName = 'ASService_*'; # Your wildcard goes here.
while ($true)
{
Get-Service $ServiceName | Where {$_.Status -eq 'Stopped'} | Foreach-Object { Start-Service $_ };
Start-Sleep -Seconds 1;
}

How to Disable all BizTalk Hostinstances with PowerShell script

I'm trying to make a PowerShell script to stop and disable from starting all BizTalk host instances.
Stopping is no problem with this code:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 1) -and ($hostinst.ServiceState -ne 8) ) {
Write-Host "Stop Hostinstance" $hostinst.HostName
$hostinst.Stop()
Write-Host "Hostinstance" $hostinst.HostName "stopped"
}
}
But now I'm trying to Disable all stopped Host Instances from starting up.
My first try gives no error but doesn't do anything.
All host instance are mentioned in the output but they are not disabled.
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
$hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
My second try gives an error because of the -path parameter.
$hosts = Get-WmiObject MSBTS_HostInstance -namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
Set-ItemProperty -Path $hostinst__PATH -Name IsDisabled -Value $True
# $hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
What is the correct method to set the property IsDisabled to $true or to $false?
BizTalk host instance is a windows service. So you can use powershell's Get-Service cmdlet to stop and disable it.
Suppose your host name is BizTalkServerApplication
Then following script will do the job:
Get-Service -Name BTSSvc`$BizTalkServerApplication | Stop-Service -PassThru | Set-Service -StartupType disabled
Also note the "$" is escaped as "`$"
#Zee is close, but still needs to loop through.. Here's one way to do that - concat the host's name with BTSSvc
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Stop-Service -PassThru | Set-Service -StartupType disabled
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And if you need to set them back to Automatic/started:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Set-Service -StartupType Automatic -PassThru | Start-Service
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And here's a way that might be even a little clearer:
Get-Service | Where-Object { $_.Name.StartsWith("BTSSvc") } | Stop-Service -PassThru | Set-Service -StartupType Disabled
Thanks for your answers.
However there are 2 reasons why this doesn't work completely fine in a BizTalk environment with multiple servers.
First in your solution you have to manually configure the list of servers for each environment in OTAP. With the option Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer' BizTalk knows which servers belong the BizTalkGroup.
Second (and more important) the present state is "Automatic(Delayed start)".
Setting the state back to Automatic(Delayed start) with Powershell script is not posible according to several websites.
I understand now why $hostinst.IsDisabled = $true didn't work.
Because the change must be saved first.
That's why I have added a command to save the changes.
$script:btscatalog.SaveChanges() | Out-Null
Unfortunately still nothing seems to be changed.
Do not use default windows service to disable the BizTalk service
Use WMI to get list of BizTalk host instances
$inProcessHosts = "HostType=1"
$nsBTS = "root/MicrosoftBizTalkServer"
$filter = "($inProcessHosts)"
$hostInstances = Get-WmiObject MSBTS_HostInstance -Namespace $nsBTS -Filter $filter
Disable items in a for each loop (redirect output from put)
foreach ($hostInstance in $hostinstances)
{
$hostInstance.IsDisabled = $true
$hostInstance.Put() > $null
}
EDIT:
There is a way to set automatic (delayed start) if needed
#=== Change the startup type for BizTalk services to Automatic (Delayed Start) ===#
get-service BTSSvc* | foreach-object -process { SC.EXE config $_.Name start= delayed-auto}
From Technet WIKI:
https://social.technet.microsoft.com/wiki/contents/articles/19701.biztalk-server-best-practices-create-and-configure-biztalk-server-host-and-host-instances.aspx

Interesting trouble with windows services and the Stop-Process cmdlet

We have a few home-brewed windows services over here. One of them is problematic, in that it won't always stop when asked. It gets stuck in the 'Stopping' state sometimes.
Using powershell we're retrieving its PID and using the Stop-Process cmdlet to kill the related process, but that's not working either.
Instead we get a message about a service named System.ServiceProcess.ServiceController.Name which obviously isn't our service, but the PID it references is.
Here's what we're doing to get our service to stop. First, we use the Get-Service cmdlet:
$ServiceNamePID = Get-Service -ComputerName $Computer | where { ($_.Status -eq 'StopPending' -or $_.Status -eq 'Stopping') -and $_.Name -eq $ServiceName}
Then, with that ServiceNamePID, we get the PID and use that in the Stop-Process cmdlet
$ServicePID = (get-wmiobject win32_Service -ComputerName $Computer | Where { $_.Name -eq $ServiceNamePID.Name }).ProcessID
Stop-Process $ServicePID -force
That's when the Stop-Process cmdlet squawks about Cannot find a process with the process identifier XYZ, when in fact PID XYZ is the correct Process ID for the service, per the task manager. Has anyone seen a problem like this before?
In order to stop a process on a remote machine, use remoting e.g.
Invoke-Command -cn $compName {param($pid) Stop-Process -Id $pid -force } -Arg $ServicePID
This requires remoting to be enabled on the remote PC and the local account has admin price on the remote PC.
Of course, once you're using remoting you could do the script using remoting e.g.:
Invoke-Command -cn $compName {
$ServiceName = '...'
$ServiceNamePID = Get-Service | Where {($_.Status -eq 'StopPending' -or $_.Status -eq 'Stopping') -and $_.Name -eq $ServiceName}
$ServicePID = (Get-WmiObject Win32_Service | Where {$_.Name -eq $ServiceNamePID.Name}).ProcessID
Stop-Process $ServicePID -Force
}