Vérifier si un service Windows existe et supprimer dans PowerShell


148

J'écris actuellement un script de déploiement qui installe un certain nombre de services Windows.

Les noms des services sont versionnés, je souhaite donc supprimer la version précédente du service Windows dans le cadre des installations du nouveau service.

Comment puis-je faire cela au mieux dans PowerShell?

Réponses:


235

Vous pouvez utiliser WMI ou d'autres outils pour cela car il n'y a pas d' Remove-Serviceapplet de commande jusqu'à Powershell 6.0 ( voir le document Remove-Service)

Par exemple:

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

Ou avec l' sc.exeoutil:

sc.exe delete ServiceName

Enfin, si vous avez accès à PowerShell 6.0:

Remove-Service -Name ServiceName

2
Vous pouvez également porter la partie pertinente de cet exemple vers PowerShell (utilisez la classe TransacedInstaller ): eggheadcafe.com/articles/20060104.asp Cependant, la méthode de ravikanth est probablement plus simple.
JohnL

7
Les versions plus récentes de PS ont Remove-WmiObject, et méfiez-vous des échecs silencieux pour $ service.delete () - ont ajouté une autre réponse avec des exemples formatés.
Straff

1
En bref, la version la plus à jour consiste à exécuter Powershell en tant qu'administrateur et à exécuter ce qui suit: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS

Pour l'information de tout le monde, la réponse de Straff dit "Méfiez-vous des échecs silencieux pour $service.delete()"
sirdank

À partir de Windows PowerShell 3.0, la cmdlet Get-WmiObject a été remplacée par Get-CimInstance. Donc, de nos jours, vous pouvez le faire:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares

122

Il n'y a aucun mal à utiliser le bon outil pour le travail, je trouve en cours d'exécution (de Powershell)

sc.exe \\server delete "MyService" 

la méthode la plus fiable qui n'a pas beaucoup de dépendances.


55
La partie .exe est très importante car sc en soi est un alias pour Set-Content.
Tom Robinson

@tjrobinson Merci pour cela, j'avais omis le .exejusqu'à ce que je voie votre commentaire. Maintenant ça marche pour moi.
gwin003

Cela n'est utile que si vous avez des droits sur l'ordinateur distant. Sinon (comme dans la plupart des environnements sécurisés) cela ne fonctionnera pas et vous aurez besoin de quelque chose qui prend en charge la transmission des informations d'identification
DaveStephens

Le nom du serveur ( \\server) est simplement omis si le service est local.
jpmc26

1
c'est mieux car il est plus facilement scriptable avec %et$_
Chaim Eliyah

84

Si vous souhaitez simplement vérifier l'existence du service:

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

21

J'ai utilisé la solution "-ErrorAction SilentlyContinue" mais j'ai ensuite rencontré le problème de laisser un ErrorRecord derrière. Voici donc une autre solution pour simplement vérifier si le service existe en utilisant "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 

Mais ravikanth a la meilleure solution puisque le Get-WmiObject ne lèvera pas d'erreur si le service n'existait pas. J'ai donc décidé d'utiliser:

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

Alors pour proposer une solution plus complète:

# 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
J'ai décidé de faire une comparaison de vitesse entre Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"et Get-Service $serviceName -ErrorAction Ignore(ce qui masque complètement l'erreur si le service n'existe pas) pour être complet. Je m'attendais à ce que Get-WmiObject soit plus rapide car il ne génère pas d'erreur. J'avais vraiment tort. En exécutant chacun en boucle 100 fois, Get-Service a pris 0,16 seconde tandis que Get-WmiObject a pris 9,66 secondes. Get-Service est donc 60 fois plus rapide que Get-WmiObject.
Simon Tewsi

13

Les versions plus récentes de PS ont Remove-WmiObject. Attention aux échecs silencieux pour $ 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:\> 

Pour ma situation, je devais exécuter `` En tant qu'administrateur ''


7

Pour supprimer plusieurs services dans Powershell 5.0, car le service de suppression n'existe pas dans cette version

Exécutez la commande ci-dessous

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

5

En combinant les réponses de Dmitri et dcx, j'ai fait ceci:

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

On pourrait utiliser Where-Object

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


3

Pour vérifier si un service Windows nommé MySuperServiceVersion1existe, même si vous n'êtes pas sûr de son nom exact, vous pouvez utiliser un caractère générique, en utilisant une sous-chaîne comme celle-ci:

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

3

Pour un seul PC:

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

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

Macro pour la liste des 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 + ) dispose désormais d'une Remove-Serviceapplet de commande .

Je ne connais pas les plans pour le back-portage vers Windows PowerShell, où il n'est pas disponible à partir de la v5.1.

Exemple:

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

Notez que l'appel échoue si le service n'existe pas, donc pour le supprimer uniquement s'il existe actuellement, vous pouvez faire:

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


2

Adapté ceci pour prendre une liste d'entrée de serveurs, spécifier un nom d'hôte et donner une sortie 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)}

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.