Controlla se esiste un servizio Windows ed elimina in PowerShell


148

Attualmente sto scrivendo uno script di distribuzione che installa una serie di servizi Windows.

I nomi dei servizi sono aggiornati, quindi desidero eliminare la precedente versione del servizio Windows come parte delle installazioni del nuovo servizio.

Come posso farlo nel modo migliore in PowerShell?

Risposte:


235

A tale scopo è possibile utilizzare WMI o altri strumenti poiché non esiste un Remove-Servicecmdlet fino a Powershell 6.0 ( consultare il documento Rimuovi servizio)

Per esempio:

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

O con lo sc.exestrumento:

sc.exe delete ServiceName

Infine, se hai accesso a PowerShell 6.0:

Remove-Service -Name ServiceName

2
È inoltre possibile eseguire il porting della parte rilevante di questo esempio su PowerShell (utilizzare la classe TransactedInstaller): eggheadcafe.com/articles/20060104.asp Tuttavia, il metodo di ravikanth è probabilmente più semplice.
JohnL,

7
Le versioni più recenti di PS hanno Remove-WmiObject e attenzione ai guasti silenziosi per $ service.delete () - hanno aggiunto un'altra risposta con esempi formattati.
Straff,

1
In breve, la versione più aggiornata deve eseguire Powershell As Administrator ed eseguire quanto segue: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS,

Per informazione di tutti, la risposta di Straff dice "Attenzione ai silenzi silenziosi $service.delete()"
sirdank,

A partire da Windows PowerShell 3.0, il cmdlet Get-WmiObject è stato sostituito da Get-CimInstance. Quindi oggi puoi farlo:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares,

122

Non c'è nulla di male nell'usare lo strumento giusto per il lavoro, trovo in esecuzione (da Powershell)

sc.exe \\server delete "MyService" 

il metodo più affidabile che non ha molte dipendenze.


55
La parte .exe è molto importante in quanto sc da solo è un alias per Set-Content.
Tom Robinson,

@tjrobinson Grazie per quello, avevo omesso .exefino a quando ho visto il tuo commento. Ora funziona per me.
gwin003,

Ciò è utile solo se si dispone dei diritti per il computer remoto. Altrimenti (come nella maggior parte degli ambienti sicuri) questo non funzionerà e avrai bisogno di qualcosa che supporti il ​​passaggio delle credenziali
DaveStephens,

Il nome del server ( \\server) viene semplicemente omesso se il servizio è locale.
jpmc26

1
questo è meglio perché è più facilmente scriptabile con %e$_
Chaim Eliyah,

84

Se vuoi solo controllare l'esistenza del servizio:

if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
    "service exists"
}

21

Ho usato la soluzione "-ErrorAction SilentlyContinue", ma in seguito ho riscontrato il problema che ha lasciato un ErrorRecord. Quindi, ecco un'altra soluzione per verificare se il servizio esiste utilizzando "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 

Ma ravikanth ha la soluzione migliore poiché Get-WmiObject non genererà un errore se il servizio non esistesse. Quindi ho deciso di usare:

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

Quindi per offrire una soluzione più completa:

# 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
Ho deciso di fare un confronto di velocità tra Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"e Get-Service $serviceName -ErrorAction Ignore(che nasconde completamente l'errore se il servizio non esiste) per completezza. Mi aspettavo che Get-WmiObject potesse essere più veloce perché non generava un errore. Ho sbagliato molto. Eseguendo ciascuno in un ciclo 100 volte, Get-Service ha impiegato 0,16 secondi mentre Get-WmiObject ha impiegato 9,66 secondi. Quindi Get-Service è 60 volte più veloce di Get-WmiObject.
Simon Tewsi,

13

Le versioni più recenti di PS hanno Remove-WmiObject. Attenzione ai guasti silenziosi per $ 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:\> 

Per la mia situazione dovevo eseguire "As Administrator"


7

Per eliminare più servizi in Powershell 5.0, poiché il servizio di rimozione non esiste in questa versione

Esegui il comando seguente

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

5

Combinando le risposte di Dmitri e dcx ho fatto questo:

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

Si potrebbe usare Where-Object

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


3

Per verificare l' MySuperServiceVersion1esistenza di un servizio Windows denominato , anche se non si è sicuri del nome esatto, è possibile utilizzare un carattere jolly, utilizzando una sottostringa in questo modo:

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

3

Per PC singolo:

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

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

Macro per elenco di PC:

$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 + ) ora ha un Remove-Servicecmdlet .

Non so circa i piani di back-port è a di Windows PowerShell, in cui è non è disponibile a partire da V5.1.

Esempio:

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

Nota che l'invocazione fallisce se il servizio non esiste, quindi per rimuoverlo solo se esiste attualmente, puoi fare:

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

3
  • Per le versioni di PowerShell precedenti alla v6, è possibile procedere come segue:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Per v6 +, è possibile utilizzare il cmdlet Remove-Service .

Si noti che a partire da Windows PowerShell 3.0, il cmdlet Get-WmiObject è stato sostituito da Get-CimInstance.


2

Adattato questo per prendere un elenco di input di server, specificare un nome host e fornire un risultato utile

            $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)}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.