Перевірте, чи існує служба Windows, і видаліть її в PowerShell


148

Наразі пишу сценарій розгортання, який встановлює ряд служб Windows.

Назви служб узагальнені, тому я хочу видалити попередню версію служби Windows як частину встановлень нової служби.

Як мені найкраще це зробити в PowerShell?

Відповіді:


235

Ви можете використовувати WMI або інші інструменти для цього, оскільки немає Remove-Serviceкомандлета, поки Powershell 6.0 ( Див. Документ видалення-служби)

Наприклад:

$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
Ви також можете перенести відповідну частину цього прикладу в powerhell (використовуйте клас TransactedInstaller): eggheadcafe.com/articles/20060104.asp Однак метод ravikanth, ймовірно, простіший.
JohnL

7
Більш недавні версії PS мають Remove-WmiObject, і остерігайтесь тихих збоїв для $ service.delete () - додали ще одну відповідь із форматованими прикладами.
Straff

1
Коротше кажучи, найновішою версією є запуск Powershell як адміністратора та запуск наступного: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS

Для інформації всіх, у відповіді Штраффа сказано: "Остерігайтеся мовчазних $service.delete()
невдач

Починаючи з Windows PowerShell 3.0, командлет Get-WmiObject був замінений Get-CimInstance. Тож сьогодні ви можете це зробити:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Розберг Лінґарес

122

У використанні правильного інструменту для роботи немає ніякої шкоди, я вважаю, що працює (від Powershell)

sc.exe \\server delete "MyService" 

найнадійніший метод, який не має багатьох залежностей.


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:\> 

Для моєї ситуації мені потрібно було працювати як "Адміністратор"


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


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, де він не доступний з версії 5.1.

Приклад:

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

Зауважте, що виклик виходить з ладу, якщо сервіс не існує, тому видалити його лише тоді, коли він існує, ви можете зробити:

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

3
  • Для версій PowerShell до версії v6 ви можете це зробити:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Для v6 + ви можете використовувати командлет 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)}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.