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?

Adrian Russell
la source

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
ravikanth
la source
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.

dcx
la source
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"
}
Dmitry Fedorkov
la source
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
}
Kent
la source
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 ''

Straff
la source
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}
Stuart Smith
la source
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
    }       
}
Richard
la source
4

On pourrait utiliser Where-Object

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

ShaneH
la source
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
}
Ifedi Okonkwo
la source
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."}

}
Ivan Temchenko
la source
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
}
mklement0
la source
3
  • Pour les versions PowerShell antérieures à la v6, vous pouvez le faire:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Pour v6 +, vous pouvez utiliser l'applet de commande Remove-Service .

Notez qu'à partir de Windows PowerShell 3.0, l'applet de commande Get-WmiObject a été remplacée par Get-CimInstance.

Rosberg Linhares
la source
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)}
Gérald
la source