Compruebe si existe un servicio de Windows y elimínelo en PowerShell

148

Actualmente estoy escribiendo un script de implementación que instala varios servicios de Windows.

Los nombres de los servicios están versionados, por lo que quiero eliminar la versión anterior del servicio de Windows como parte de las instalaciones del nuevo servicio.

¿Cómo puedo hacer esto mejor en PowerShell?

Adrian Russell
fuente

Respuestas:

235

Puede usar WMI u otras herramientas para esto, ya que no hay Remove-Servicecmdlet hasta Powershell 6.0 ( consulte el documento Eliminar-Servicio)

Por ejemplo:

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

O con la sc.exeherramienta:

sc.exe delete ServiceName

Finalmente, si tiene acceso a PowerShell 6.0:

Remove-Service -Name ServiceName
ravikanth
fuente
2
También puede transferir la parte relevante de este ejemplo a powershell (use la clase TransactedInstaller): eggheadcafe.com/articles/20060104.asp Sin embargo, el método de ravikanth es probablemente más simple.
JohnL
77
Las versiones más recientes de PS tienen Remove-WmiObject, y cuidado con las fallas silenciosas para $ service.delete () - han agregado otra respuesta con ejemplos formateados.
Straff
1
En resumen, la versión más actualizada es ejecutar Powershell como administrador y ejecutar lo siguiente: $service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" $service | Remove-WmiObject
BamboOS
Para información de todos, la respuesta de $service.delete()
Straff
A partir de Windows PowerShell 3.0, el cmdlet Get-WmiObject ha sido reemplazado por Get-CimInstance. Así que hoy en día puedes hacer esto:Stop-Service 'servicename'; Get-CimInstance -ClassName Win32_Service -Filter "Name='servicename'" | Remove-CimInstance
Rosberg Linhares
122

No hay ningún daño en usar la herramienta adecuada para el trabajo, creo que se ejecuta (desde Powershell)

sc.exe \\server delete "MyService" 

El método más confiable que no tiene muchas dependencias.

dcx
fuente
55
La parte .exe es muy importante ya que sc por sí solo es un alias para Set-Content.
Tom Robinson
@tjrobinson Gracias por eso, había omitido el .exehasta que vi tu comentario. Ahora está funcionando para mí.
gwin003
Esto solo es útil si tiene derechos sobre la computadora remota. Si no es así (como en la mayoría de los entornos seguros), esto no funcionará y necesitará algo que admita el paso de credenciales
DaveStephens
El nombre del servidor ( \\server) simplemente se omite si el servicio es local.
jpmc26
1
esto es mejor porque es más fácil de escribir con %y$_
Chaim Eliyah
84

Si solo desea verificar la existencia del servicio:

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

Usé la solución "-ErrorAction SilentlyContinue" pero luego me encontré con el problema de que deja un ErrorRecord atrás. Así que aquí hay otra solución para simplemente verificar si el Servicio existe usando "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 

Pero ravikanth tiene la mejor solución ya que Get-WmiObject no arrojará un error si el Servicio no existiera. Así que decidí usar:

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

Para ofrecer una solución más 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
}
Kent
fuente
77
Decidí hacer una comparación de velocidad entre Get-WmiObject -Class Win32_Service -Filter "Name='$serviceName'"y Get-Service $serviceName -ErrorAction Ignore(que oculta completamente el error si el servicio no existe) para completar. Esperaba que el Get-WmiObject pudiera ser más rápido porque no arroja un error. Estaba muy equivocado Ejecutando cada uno en un bucle 100 veces, Get-Service tomó 0,16 segundos, mientras que Get-WmiObject tardó 9,66 segundos. Entonces Get-Service es 60 veces más rápido que Get-WmiObject.
Simon Tewsi
13

Las versiones más recientes de PS tienen Remove-WmiObject. Cuidado con las fallas silenciosas para $ 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:\> 

Para mi situación, necesitaba ejecutar 'Como administrador'

Straff
fuente
7

Para eliminar varios servicios en Powershell 5.0, ya que el servicio de eliminación no existe en esta versión

Ejecute el siguiente comando

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

Combinando las respuestas de Dmitri y dcx hice esto:

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
    }       
}
Ricardo
fuente
4

Uno podría usar Where-Object

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

ShaneH
fuente
3

Para verificar si MySuperServiceVersion1existe un servicio de Windows con nombre , incluso cuando no esté seguro de su nombre exacto, puede emplear un comodín, usando una subcadena como esta:

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

Para una sola 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 para la lista de 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
fuente
3

PowerShell Core ( v6 + ) ahora tiene un Remove-Servicecmdlet .

No sé acerca de los planes de back-portarlo a de Windows PowerShell, donde es no disponible a partir de la versión 5.1.

Ejemplo:

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

Tenga en cuenta que la invocación falla si el servicio no existe, por lo que para eliminarlo solo si actualmente existe, puede hacer lo siguiente:

# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
  Remove-Service $name
}
mklement0
fuente
3
  • Para las versiones de PowerShell anteriores a v6, puede hacer esto:

    Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
  • Para v6 +, puede usar el cmdlet Remove-Service .

Observe que a partir de Windows PowerShell 3.0, el cmdlet Get-WmiObject ha sido reemplazado por Get-CimInstance.

Rosberg Linhares
fuente
2

Adaptado esto para tomar una lista de entrada de servidores, especificar un nombre de host y dar una salida útil

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