Проверьте, существует ли служба Windows, и удалите в PowerShell.

148

В настоящее время я пишу сценарий развертывания, который устанавливает ряд служб Windows.

Имена сервисов версионированы, поэтому я хочу удалить предыдущую версию сервиса Windows как часть установки новой службы.

Как я могу лучше всего сделать это в PowerShell?

Адриан Рассел
источник

Ответы:

236

Для этого вы можете использовать WMI или другие инструменты, поскольку Remove-Serviceдо Powershell 6.0 нет командлета ( см. 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
ravikanth
источник
2
Вы также можете перенести соответствующую часть этого примера на powershell (используйте класс TransactedInstaller): eggheadcafe.com/articles/20060104.asp Однако метод ravikanth, вероятно, проще.
JohnL
7
Более поздние версии PS имеют Remove-WmiObject, и остерегайтесь молчаливых сбоев для $ service.delete () - добавили еще один ответ с отформатированными примерами.
Straff
1
Короче говоря, самой $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
последней
Для всеобщего сведения, ответ $service.delete()
Страффа
Начиная с Windows PowerShell 3.0, командлет Get-WmiObject был заменен Get-CimInstance. Так что в настоящее время вы можете сделать это:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Росберг Linhares
122

Там нет вреда в использовании правильного инструмента для работы, я считаю, работает (от Powershell)

sc.exe \\server delete "MyService" 

самый надежный метод, который не имеет много зависимостей.

DCX
источник
55
Часть .exe очень важна, поскольку sc сам по себе является псевдонимом Set-Content.
Том Робинсон
@tjrobinson Спасибо за это, я пропустил, .exeпока не увидел ваш комментарий. Теперь это работает для меня.
gwin003
Это полезно только если у вас есть права на удаленный компьютер. Если нет (как в большинстве безопасных сред), это не сработает, и вам понадобится что-то, что поддерживает передачу учетных данных
DaveStephens
Имя сервера ( \\server) просто не указывается, если служба локальная.
jpmc26
1
это лучше, потому что это легче для сценариев с %и$_
Хаим Элия
84

Если вы просто хотите проверить существование сервиса:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}
Дмитрий Федорков
источник
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 есть лучшее решение, так как 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 в 60 раз быстрее, чем Get-WmiObject.
Саймон Тьюси,
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:\> 

Для моей ситуации мне нужно было запустить «Как администратор»

Straff
источник
7

Чтобы удалить несколько сервисов в Powershell 5.0, так как удалить сервис не существует в этой версии

Запустите приведенную ниже команду

Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c  sc delete $_.Name}
Стюарт Смит
источник
5

Объединив ответы Дмитрия и 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" }

ShaneH
источник
3

Чтобы проверить, существует ли названная служба Windows MySuperServiceVersion1, даже если вы не уверены в ее точном названии, вы можете использовать подстановочный знак, используя подстроку так:

 if (Get-Service -Name "*SuperService*" -ErrorAction SilentlyContinue)
{
    # do something
}
Ифеди Оконкво
источник
3

Для одного ПК:

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

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

Макрос для списка компьютеров:

$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 Core ( v6 + ) теперь имеет Remove-Serviceкомандлет .

Я не знаю о планах обратного портирования на 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
}
mklement0
источник
3
  • Для версий PowerShell до v6 вы можете сделать это:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Для версии 6+ вы можете использовать командлет Remove-Service .

Обратите внимание, что начиная с Windows PowerShell 3.0, командлет Get-WmiObject был заменен Get-CimInstance.

Росберг Линхарес
источник
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)}
Джеральд
источник