ChatGPT解决这个技术问题 Extra ChatGPT

Check if a Windows service exists and delete in PowerShell

I am currently writing a deployment script that installs a number of Windows services.

The services names are versioned, so I want to delete the prior Windows service version as part of the installs of the new service.

How can I best do this in PowerShell?


T
Thomas B in BDX

You can use WMI or other tools for this since there is no Remove-Service cmdlet until Powershell 6.0 (See Remove-Service doc)

For example:

$service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'"
$service.delete()

Or with the sc.exe tool:

sc.exe delete ServiceName

Finally, if you do have access to PowerShell 6.0:

Remove-Service -Name ServiceName

You could also port the relevant part of this example to powershell (use the TransactedInstaller class): eggheadcafe.com/articles/20060104.asp However ravikanth's method is probably simpler.
More recent versions of PS have Remove-WmiObject, and beware of silent fails for $service.delete() - have added another answer with formatted examples.
In short, most up to date version is to run Powershell As Administrator and run following: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
For everyone's information, Straff's answer says "Beware of silent fails for $service.delete()"
Starting in Windows PowerShell 3.0, the cmdlet Get-WmiObject has been superseded by Get-CimInstance. So nowadays you can do this: Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
d
dcx

There's no harm in using the right tool for the job, I find running (from Powershell)

sc.exe \\server delete "MyService" 

the most reliable method that does not have many dependencies.


The .exe part is very important as sc on its own is an alias for Set-Content.
@tjrobinson Thanks for that, I had omitted the .exe until I saw your comment. Now its working for me.
This is only useful if you have rights to the remote computer. If not (like in most secure environments) this won't work and you'll need something that supports passing in credentials
The server name (\\server) is simply omitted if the service is local.
this is better because it's more easily scriptable with % and $_
D
Dmitry Fedorkov

If you just want to check service existence:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}

C
Chris Forrence

I used the "-ErrorAction SilentlyContinue" solution but then later ran into the problem that it leaves an ErrorRecord behind. So here's another solution to just checking if the Service exists using "Get-Service".

# Determines if a Service exists with a name as defined in $ServiceName.
# Returns a boolean $True or $False.
Function ServiceExists([string] $ServiceName) {
    [bool] $Return = $False
    # If you use just "Get-Service $ServiceName", it will return an error if 
    # the service didn't exist.  Trick Get-Service to return an array of 
    # Services, but only if the name exactly matches the $ServiceName.  
    # This way you can test if the array is emply.
    if ( Get-Service "$ServiceName*" -Include $ServiceName ) {
        $Return = $True
    }
    Return $Return
}

[bool] $thisServiceExists = ServiceExists "A Service Name"
$thisServiceExists 

But ravikanth has the best solution since the Get-WmiObject will not throw an error if the Service didn't exist. So I settled on using:

Function ServiceExists([string] $ServiceName) {
    [bool] $Return = $False
    if ( Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'" ) {
        $Return = $True
    }
    Return $Return
}

So to offer a more complete solution:

# Deletes a Service with a name as defined in $ServiceName.
# Returns a boolean $True or $False.  $True if the Service didn't exist or was 
# successfully deleted after execution.
Function DeleteService([string] $ServiceName) {
    [bool] $Return = $False
    $Service = Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'" 
    if ( $Service ) {
        $Service.Delete()
        if ( -Not ( ServiceExists $ServiceName ) ) {
            $Return = $True
        }
    } else {
        $Return = $True
    }
    Return $Return
}

I decided to do a speed comparison between Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'" and Get-Service $serviceName -ErrorAction Ignore (which completely hides the error if the service doesn't exist) for completeness. I expected the Get-WmiObject might be faster because it doesn't throw an error. I was very wrong. Running each in a loop 100 times, Get-Service took 0.16 seconds while Get-WmiObject took 9.66 seconds. So Get-Service is 60x faster than Get-WmiObject.
S
Straff

More recent versions of PS have Remove-WmiObject. Beware of silent fails for $service.delete() ...

PS D:\> $s3=Get-WmiObject -Class Win32_Service -Filter "Name='TSATSvrSvc03'"

PS D:\> $s3.delete()
...
ReturnValue      : 2
...
PS D:\> $?
True
PS D:\> $LASTEXITCODE
0
PS D:\> $result=$s3.delete()

PS D:\> $result.ReturnValue
2

PS D:\> Remove-WmiObject -InputObject $s3
Remove-WmiObject : Access denied 
At line:1 char:1
+ Remove-WmiObject -InputObject $s3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Remove-WmiObject], ManagementException
    + FullyQualifiedErrorId : RemoveWMIManagementException,Microsoft.PowerShell.Commands.RemoveWmiObject

PS D:\> 

For my situation I needed to be running 'As Administrator'


S
Stuart Smith

To delete multiple services in Powershell 5.0, since remove service does not exist in this version

Run the below command

Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c  sc delete $_.Name}

S
ShaneH

One could use Where-Object

if ((Get-Service | Where-Object {$_.Name -eq $serviceName}).length -eq 1) { "Service Exists" }


R
Richard

Combining Dmitri & dcx's answers I made this:

function Confirm-WindowsServiceExists($name)
{   
    if (Get-Service $name -ErrorAction SilentlyContinue)
    {
        return $true
    }
    return $false
}

function Remove-WindowsServiceIfItExists($name)
{   
    $exists = Confirm-WindowsServiceExists $name
    if ($exists)
    {    
        sc.exe \\server delete $name
    }       
}

I
Ivan Temchenko

For single PC:

if (Get-Service "service_name" -ErrorAction 'SilentlyContinue'){(Get-WmiObject -Class Win32_Service -filter "Name='service_name'").delete()}

else{write-host "No service found."}

Macro for list of PCs:

$name = "service_name"

$list = get-content list.txt

foreach ($server in $list) {

if (Get-Service "service_name" -computername $server -ErrorAction 'SilentlyContinue'){
(Get-WmiObject -Class Win32_Service -filter "Name='service_name'" -ComputerName $server).delete()}

else{write-host "No service $name found on $server."}

}

I
Ifedi Okonkwo

To check if a Windows service named MySuperServiceVersion1 exists, even when you might not be sure of its exact name, you could employ a wildcard, using a substring like so:

 if (Get-Service -Name "*SuperService*" -ErrorAction SilentlyContinue)
{
    # do something
}

m
mklement0

PowerShell Core (v6+) now has a Remove-Service cmdlet.

I don't know about plans to back-port it to Windows PowerShell, where it is not available as of v5.1.

Example:

# PowerShell *Core* only (v6+)
Remove-Service someservice

Note that invocation fails if the service doesn't exist, so to only remove it if it currently exists, you could do:

# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
  Remove-Service $name
}

On PowerShell version 7, using the call to RemoteService gets the error "Remove-Service : The term 'Remove-Service' is not recognized as the name of a cmdlet, function, script file, or operable program"
@PedroVicente, note that In the context of remoting, even PowerShell 7 still targets Windows PowerShell on remote machines - see this answer.
G
Gerald

Adapted this to take an input list of servers, specify a hostname and give some helpful output

            $name = "<ServiceName>"
            $servers = Get-content servers.txt

            function Confirm-WindowsServiceExists($name)
            {   
                if (Get-Service -Name $name -Computername $server -ErrorAction Continue)
                {
                    Write-Host "$name Exists on $server"
                    return $true
                }
                    Write-Host "$name does not exist on $server"
                    return $false
            }

            function Remove-WindowsServiceIfItExists($name)
            {   
                $exists = Confirm-WindowsServiceExists $name
                if ($exists)
                {    
                    Write-host "Removing Service $name from $server"
                    sc.exe \\$server delete $name
                }       
            }

            ForEach ($server in $servers) {Remove-WindowsServiceIfItExists($name)}

R
Rosberg Linhares

For PowerShell versions prior to v6, you can do this: Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance

For v6+, you can use the Remove-Service cmdlet.

Observe that starting in Windows PowerShell 3.0, the cmdlet Get-WmiObject has been superseded by Get-CimInstance.


G
Gagan

Windows Powershell 6 will have Remove-Service cmdlet. As of now the Github release shows PS v6 beta-9

Source: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-service?view=powershell-6


M
Musa Biralo

I know it's an old question but if someone is looking for one-liner:

On PS Version > 7.2

Wildcard search on the Name property

Get-Service *name* | Select-Object -First 1 | Remove-Service

Search the Display Name property

Get-Service -DisplayName "My Service Description" | Remove-Service