Sprawdź, czy usługa systemu Windows istnieje i usuń w programie PowerShell

148

Obecnie piszę skrypt wdrażania, który instaluje szereg usług systemu Windows.

Nazwy usług są wersjonowane, dlatego chcę usunąć poprzednią wersję usługi systemu Windows w ramach instalacji nowej usługi.

Jak najlepiej to zrobić w PowerShell?

Adrian Russell
źródło

Odpowiedzi:

235

Możesz użyć do tego WMI lub innych narzędzi, ponieważ nie ma polecenia Remove-Servicecmdlet aż do Powershell 6.0 ( zobacz dokument Remove-Service)

Na przykład:

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

Lub za pomocą sc.exenarzędzia:

sc.exe delete ServiceName

Wreszcie, jeśli masz dostęp do programu PowerShell 6.0:

Remove-Service -Name ServiceName
ravikanth
źródło
2
Możesz również przenieść odpowiednią część tego przykładu do programu PowerShell (użyj klasy TransactedInstaller): eggheadcafe.com/articles/20060104.asp Jednak metoda Ravikantha jest prawdopodobnie prostsza.
JohnL
7
Nowsze wersje PS mają Remove-WmiObject i uważaj na ciche niepowodzenia $ service.delete () - dodałem kolejną odpowiedź ze sformatowanymi przykładami.
Straff
1
Krótko mówiąc, najbardziej aktualna wersja polega na uruchomieniu Powershell jako Administrator i uruchomieniu: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS
Dla wszystkich informacji, odpowiedź Straffa brzmi: „Uważaj na ciche niepowodzenia $service.delete()
sirdank
Począwszy od programu Windows PowerShell 3,0, polecenie cmdlet Get-WmiObject zostało zastąpione przez Get-CimInstance. Teraz możesz to zrobić:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares
122

Nie ma nic złego w używaniu odpowiedniego narzędzia do pracy, uważam, że działa (z Powershell)

sc.exe \\server delete "MyService" 

najbardziej niezawodna metoda, która nie ma wielu zależności.

dcx
źródło
55
Część .exe jest bardzo ważna, ponieważ sam sc jest aliasem dla Set-Content.
Tom Robinson
@tjrobinson Dzięki za to, pominąłem ten .exekomentarz, dopóki nie zobaczyłem twojego komentarza. Teraz to działa dla mnie.
gwin003
Jest to przydatne tylko wtedy, gdy masz uprawnienia do komputera zdalnego. Jeśli nie (jak w najbardziej bezpiecznych środowiskach), to nie zadziała i będziesz potrzebować czegoś, co obsługuje przekazywanie poświadczeń
DaveStephens
Nazwa serwera ( \\server) jest po prostu pomijana, jeśli usługa jest lokalna.
jpmc26
1
to jest lepsze, ponieważ jest łatwiejsze do skryptu z %i$_
Chaim Eliyah
84

Jeśli chcesz tylko sprawdzić istnienie usługi:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}
Dmitrij Fiodorkow
źródło
21

Użyłem rozwiązania „-ErrorAction SilentlyContinue”, ale później napotkałem problem polegający na tym, że pozostawia za sobą ErrorRecord. Oto kolejne rozwiązanie pozwalające po prostu sprawdzić, czy Usługa istnieje, za pomocą funkcji „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 

Ale ravikanth ma najlepsze rozwiązanie, ponieważ Get-WmiObject nie zgłosi błędu, jeśli usługa nie istnieje. Więc zdecydowałem się na użycie:

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

Aby zaoferować bardziej kompletne rozwiązanie:

# 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
}
Kent
źródło
7
Postanowiłem zrobić porównanie prędkości między Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"i Get-Service $serviceName -ErrorAction Ignore(co całkowicie ukrywa błąd, jeśli usługa nie istnieje) dla kompletności. Spodziewałem się, że Get-WmiObject może być szybszy, ponieważ nie zgłasza błędu. Bardzo się myliłem. Uruchomienie każdego w pętli 100 razy, Get-Service zajęło 0,16 sekundy, a Get-WmiObject 9,66 sekundy. Więc Get-Service jest 60x szybszy niż Get-WmiObject.
Simon Tewsi
13

Nowsze wersje PS mają Remove-WmiObject. Uważaj na ciche niepowodzenia $ 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:\> 

W mojej sytuacji potrzebowałem uruchomić „Jako administrator”

Straff
źródło
7

Aby usunąć wiele usług w programie PowerShell 5.0, ponieważ usługa usuwania nie istnieje w tej wersji

Uruchom poniższe polecenie

Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c  sc delete $_.Name}
Stuart Smith
źródło
5

Łącząc odpowiedzi Dmitri i dcx, zrobiłem to:

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
    }       
}
Richard
źródło
4

Można by użyć Where-Object

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

ShaneH
źródło
3

Aby sprawdzić, czy usługa Windows o nazwie MySuperServiceVersion1istnieje, nawet jeśli nie jesteś pewien jej dokładnej nazwy, możesz użyć symbolu wieloznacznego, używając podłańcucha takiego jak ten:

 if (Get-Service -Name "*SuperService*" -ErrorAction SilentlyContinue)
{
    # do something
}
Ifedi Okonkwo
źródło
3

Dla jednego komputera:

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

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

Makro do listy komputerów:

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

}
Ivan Temchenko
źródło
3

PowerShell Core ( v6 + ) ma teraz polecenie Remove-Servicecmdlet .

Nie wiem o planach back-portu go do systemu Windows PowerShell, gdzie jest nie dostępna od v5.1.

Przykład:

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

Pamiętaj, że wywołanie kończy się niepowodzeniem, jeśli usługa nie istnieje, więc aby usunąć ją tylko wtedy, gdy obecnie istnieje, możesz wykonać:

# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
  Remove-Service $name
}
mklement0
źródło
3
  • W przypadku wersji programu PowerShell wcześniejszych niż wersja 6 można to zrobić:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • W przypadku wersji 6+ można użyć polecenia cmdlet Remove-Service .

Zwróć uwagę, że począwszy od programu Windows PowerShell 3,0, polecenie cmdlet Get-WmiObject zostało zastąpione przez Get-CimInstance.

Rosberg Linhares
źródło
2

Zaadaptowano to, aby pobrać listę wejściową serwerów, określić nazwę hosta i podać pomocne wyniki

            $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)}
Gerald
źródło