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

Adr*_*ell 141 powershell windows-services

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

服务名称是版本化的,因此我想删除以前的Windows服务版本作为新服务安装的一部分.

我怎样才能在PowerShell中做到最好?

rav*_*nth 219

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

例如:

$service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'"
$service.delete()
Run Code Online (Sandbox Code Playgroud)

或者使用sc.exe工具:

sc.exe delete ServiceName
Run Code Online (Sandbox Code Playgroud)

最后,如果您有权访问PowerShell 6.0:

Remove-Service -Name ServiceName
Run Code Online (Sandbox Code Playgroud)

  • PS的更新版本有Remove-WmiObject,并且要注意$ service.delete()的静默失败 - 添加了格式化示例的另一个答案. (7认同)
  • 您还可以将此示例的相关部分移植到powershell(使用TransactedInstaller类):http://www.eggheadcafe.com/articles/20060104.asp但是ravikanth的方法可能更简单. (2认同)

小智 122

使用正确的工具进行工作没有坏处,我发现正在运行(来自Powershell)

sc.exe \\server delete "MyService" 
Run Code Online (Sandbox Code Playgroud)

最可靠的方法,没有很多依赖项.

  • .exe部分非常重要,因为sc本身就是Set-Content的别名. (53认同)

Dmi*_*kov 81

如果您只想检查服务是否存在:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}
Run Code Online (Sandbox Code Playgroud)


小智 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 
Run Code Online (Sandbox Code Playgroud)

但是ravikanth有最好的解决方案,因为如果服务不存在,Get-WmiObject不会抛出错误.所以我决定使用:

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

所以提供更完整的解决方案:

# 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
}
Run Code Online (Sandbox Code Playgroud)

  • 我决定在`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倍. (5认同)

Str*_*aff 12

更新版本的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:\> 
Run Code Online (Sandbox Code Playgroud)

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


Stu*_*ith 6

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

运行以下命令

Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c  sc delete $_.Name}
Run Code Online (Sandbox Code Playgroud)


Sha*_*neH 5

可以使用 Where-Object

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