检查Windows服务是否存在并在PowerShell中删除


148

我目前正在编写一个安装许多Windows服务的部署脚本。

服务名称已版本化,因此我想在安装新服务时删除先前的Windows服务版本。

如何在PowerShell中最好地做到这一点?

Answers:


235

您可以为此使用WMI或其他工具,因为在Remove-ServicePowershell 6.0之前没有cmdlet(请参阅Remove-Service文档)

例如:

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

或使用sc.exe工具:

sc.exe delete ServiceName

最后,如果您确实有权使用PowerShell 6.0:

Remove-Service -Name ServiceName

2
您也可以将此示例的相关部分移植到powershell(使用TransactedInstaller类):eggheadcafe.com/articles/20060104.asp但是ravikanth的方法可能更简单。
JohnL

7
PS的较新版本具有Remove-WmiObject,并提防$ service.delete()的静音失败-添加了带有格式示例的另一个答案。
斯特拉夫'16

1
简而言之,最新版本是以管理员身份运行Powershell并运行以下命令: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS

对于所有人的信息,Straff的回答是“提防沉默失败$service.delete()
sirdank

从Windows PowerShell 3.0开始,cmdlet Get-WmiObject已被Get-CimInstance取代。因此,如今您可以执行以下操作:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares

122

我发现运行正确的工具没有任何危害,我发现运行(来自Powershell)

sc.exe \\server delete "MyService" 

没有很多依赖关系的最可靠的方法。


55
.exe部分非常重要,因为sc本身是Set-Content的别名。
汤姆·罗宾逊

@tjrobinson谢谢,在.exe我看到你的评论之前,我已经省略了。现在它为我工作。
gwin003 2013年

仅当您有权访问远程计算机时,此功能才有用。如果不是这样(就像在大多数安全环境中一样),它将无法正常工作,您将需要一些支持凭据传递的功能
DaveStephens 2015年

\\server如果服务是本地的,则将服务器名称()省略。
jpmc26年

1
这是更好,因为它更容易编写脚本与%$_
哈伊姆Eliyah


21

我使用了“ -ErrorAction SilentlyContinue”解决方案,但后来遇到了一个问题,即它留下了ErrorRecord。因此,这是仅使用“ 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 

但是ravikanth是最好的解决方案,因为如果Service不存在,则Get-WmiObject不会引发错误。所以我决定使用:

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

因此,提供更完整的解决方案:

# 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
}

7
我决定在Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"和之间进行速度比较Get-Service $serviceName -ErrorAction Ignore(如果服务不存在,则会完全隐藏错误),以确保完整性。我预计Get-WmiObject可能会更快,因为它不会引发错误。我错了 每个循环运行100次,Get-Service花了0.16秒,而Get-WmiObject花了9.66秒。因此,Get-Service比Get-WmiObject快60倍。
西蒙·图西

13

PS的较新版本具有Remove-WmiObject。小心$ 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:\> 

对于我的情况,我需要运行“作为管理员”


7

由于此版本中不存在删除服务,因此要在Powershell 5.0中删除多个服务

运行以下命令

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

5

结合Dmitri和dcx的答案,我做到了:

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
    }       
}

4

一个可以使用Where-Object

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


3

要检查Windows服务是否MySuperServiceVersion1存在,即使您不确定其确切名称,也可以使用通配符,使用如下所示的子字符串:

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

3

对于单台PC:

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

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

PC列表的宏:

$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."}

}

3

PowerShell Corev6 +)现在具有一个Remove-Servicecmdlet

我不知道将其反向移植到Windows PowerShell的计划,该版本从v5.1开始不可用。

例:

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

请注意,如果服务不存在,则调用将失败,因此,仅在当前存在服务时将其删除,您可以执行以下操作:

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


2

对此进行了修改,以获取服务器的输入列表,指定主机名并提供一些有用的输出

            $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)}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.