Überprüfen Sie, ob ein Windows-Dienst vorhanden ist, und löschen Sie ihn in PowerShell

147

Ich schreibe derzeit ein Bereitstellungsskript, das eine Reihe von Windows-Diensten installiert.

Die Dienstnamen sind versioniert, daher möchte ich die vorherige Windows-Dienstversion im Rahmen der Installation des neuen Dienstes löschen.

Wie kann ich dies am besten in PowerShell tun?

Adrian Russell
quelle

Antworten:

234

Sie können hierfür WMI oder andere Tools verwenden, da Remove-Servicebis Powershell 6.0 kein Cmdlet vorhanden ist ( siehe Dokument zum Entfernen von Diensten).

Beispielsweise:

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

Oder mit dem sc.exeTool:

sc.exe delete ServiceName

Wenn Sie Zugriff auf PowerShell 6.0 haben:

Remove-Service -Name ServiceName
Ravikanth
quelle
2
Sie können den relevanten Teil dieses Beispiels auch auf Powershell portieren (verwenden Sie die TransactedInstaller-Klasse): eggheadcafe.com/articles/20060104.asp Die Methode von Ravikanth ist jedoch wahrscheinlich einfacher.
JohnL
7
Neuere Versionen von PS haben Remove-WmiObject und Vorsicht vor stillen Fehlern für $ service.delete () - haben eine weitere Antwort mit formatierten Beispielen hinzugefügt.
Straff
1
Kurz gesagt, die aktuellste Version besteht darin, Powershell als Administrator auszuführen und Folgendes auszuführen: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS
Zur Information aller sagt $service.delete()
Straffs
Ab Windows PowerShell 3.0 wurde das Cmdlet Get-WmiObject von Get-CimInstance ersetzt. So können Sie heutzutage dies tun:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares
122

Es schadet nicht, das richtige Werkzeug für den Job zu verwenden. Ich finde, es läuft (von Powershell)

sc.exe \\server delete "MyService" 

Die zuverlässigste Methode, die nicht viele Abhängigkeiten aufweist.

dcx
quelle
55
Der EXE-Teil ist sehr wichtig, da sc für sich genommen ein Alias ​​für Set-Content ist.
Tom Robinson
@tjrobinson Danke dafür, ich hatte das weggelassen, .exebis ich deinen Kommentar sah. Jetzt funktioniert es für mich.
Gwin003
Dies ist nur nützlich, wenn Sie Rechte am Remotecomputer haben. Wenn nicht (wie in den meisten sicheren Umgebungen), funktioniert dies nicht und Sie benötigen etwas, das die Übergabe von Anmeldeinformationen unterstützt
DaveStephens
Der Servername ( \\server) wird einfach weggelassen, wenn der Dienst lokal ist.
jpmc26
1
Das ist besser, weil es mit %und$_
Chaim Eliyah
83

Wenn Sie nur die Existenz des Dienstes überprüfen möchten:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}
Dmitry Fedorkov
quelle
21

Ich habe die Lösung "-ErrorAction SilentlyContinue" verwendet, bin dann aber später auf das Problem gestoßen, dass ein ErrorRecord zurückbleibt. Hier ist eine weitere Lösung, um mithilfe von "Get-Service" zu überprüfen, ob der Service vorhanden ist.

# 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 

Aber Ravikanth hat die beste Lösung, da das Get-WmiObject keinen Fehler auslöst, wenn der Service nicht existiert. Also entschied ich mich für:

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

Um eine vollständigere Lösung anzubieten:

# 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
quelle
7
Der Vollständigkeit halber habe ich mich für einen Geschwindigkeitsvergleich zwischen Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"und entschieden Get-Service $serviceName -ErrorAction Ignore(der den Fehler vollständig verbirgt, wenn der Dienst nicht vorhanden ist). Ich habe erwartet, dass das Get-WmiObject möglicherweise schneller ist, da es keinen Fehler auslöst. Ich habe mich sehr geirrt Get-Service wurde jeweils 100 Mal in einer Schleife ausgeführt und dauerte 0,16 Sekunden, während Get-WmiObject 9,66 Sekunden dauerte. Get-Service ist also 60x schneller als Get-WmiObject.
Simon Tewsi
13

Neuere Versionen von PS haben Remove-WmiObject. Vorsicht vor stillen Fehlern für $ 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:\> 

Für meine Situation musste ich "Als Administrator" ausführen.

Straff
quelle
7

So löschen Sie mehrere Dienste in Powershell 5.0, da der Dienst zum Entfernen in dieser Version nicht vorhanden ist

Führen Sie den folgenden Befehl aus

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

Ich kombinierte die Antworten von Dmitri & dcx und machte Folgendes:

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
quelle
4

Man könnte Where-Object verwenden

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

ShaneH
quelle
3

Um zu überprüfen, ob ein Windows-Dienst mit dem Namen MySuperServiceVersion1vorhanden ist, können Sie einen Platzhalter verwenden, indem Sie einen Teilstring wie den folgenden verwenden:

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

Für einen einzelnen PC:

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

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

Makro für Liste der PCs:

$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
quelle
3

PowerShell Core ( v6 + ) verfügt jetzt über ein Remove-ServiceCmdlet .

Ich weiß nichts über Pläne, es auf Windows PowerShell zurück zu portieren , wo es ab Version 5.1 nicht verfügbar ist.

Beispiel:

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

Beachten Sie, dass der Aufruf fehlschlägt, wenn der Dienst nicht vorhanden ist. Um ihn also nur zu entfernen, wenn er derzeit vorhanden ist, können Sie Folgendes tun:

# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
  Remove-Service $name
}
mklement0
quelle
3
  • Für PowerShell-Versionen vor Version 6 können Sie Folgendes tun:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Für Version 6 + können Sie das Cmdlet Remove-Service verwenden .

Beachten Sie, dass ab Cmdlet Get-WmiObject ab Windows PowerShell 3.0 Get-CimInstance ersetzt wurde.

Rosberg Linhares
quelle
2

Dies wurde angepasst, um eine Eingabeliste mit Servern zu erstellen, einen Hostnamen anzugeben und hilfreiche Ausgaben zu liefern

            $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
quelle