Power Shell Get Service Issue - powershell

Hi I need to get a script that will do the following:
Check if a service exists
If the service doesn't exist run my script
If the service exists do nothing
Here is what I have but it's not working for me:
$service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'"
if($service.Status -eq $NULL)
{
$CLID = $inclid
New-Item -Path "c:\" -Name "folder" -ItemType "directory"
Invoke-WebRequest -Uri https://something.com\setup.exe -OutFile c:\folder\swibm#$CLID#101518#.exe
$installer = "swibm#$CLID#101518#.exe"
Start-Process -FilePath $installer -WorkingDirectory "C:\folder"
}
else
{
Write-Host "Client Already Installed"
}
If I run $service.Status alone I get an "OK" returned. Under this condition I would need the script to stop and run the else section. I only want this script to run if $service.Status returns nothing. Where am I going wrong here?

You may try putting $null on the left hand side of the comparison.
If($null -eq $services.status)
Here is a nice write up discussing it

Simpler way to check if service exists:
if( Get-WmiObject -Class Win32_Service -Filter "Name='servicename'" ) {
# Service exists
}
else {
# Service doesn't exist
}
... or use the Get-Service cmdlet:
if( Get-Service -ErrorAction SilentlyContinue -Name servicename ) {
# Service exists
}
else {
# Service doesn't exist
}

Related

It returns all services even though there is one in list

I want my script to take the server and service as a list from a .txt file. After that I want my script to check that if this service exists on the servers on the txt file.
But when I run this script, it returns all of the services as it exists on the server and not the ones I specified in service list. Also it doesn't drop to catch even tho the service doesn't exist.
Can you tell me why it returns all of the services?
$ErrorActionPreference='stop'
$ServerList = Get-Content 'C:\Users\username\Desktop\service test\servers.txt'
$ServiceList = Get-Content 'C:\Users\username\Desktop\service test\services.txt'
try{
foreach($Server in $ServerList){
foreach($Service in $ServiceList){
$Result = Invoke-Command -ComputerName $Server -ScriptBlock {
Get-Service -Name $Service
}
foreach($List in $Result){
Write-Host "$List exists on $Server"
}
}
}
}
catch [System.Management.Automation.ActionPreferenceStopException]
{
Write-Host "Error"
}
Continuing from my comment. . . when using a local variable against a remote computer in a scriptblock, you have to pass it as an argument, or have it referenced using the remote variable of $using.
This is due to a new session being ran on the remote machine with no clue what $service is on that machine as it's never been declared on that side.
You can pass it using the -Arguments, parameter. Creating a param block to pass it onto or, using the remote variable of $using.
Also, there's really no need for you to invoke the command over to the remote machine as Get-Service has a -ComputerName parameter for remote machines:
$ServerList = Get-Content 'C:\Users\username\Desktop\service test\servers.txt'
$ServiceList = Get-Content 'C:\Users\username\Desktop\service test\services.txt'
foreach ($Server in $ServerList)
{
foreach ($Service in $ServiceList.trim())
{
[PSCustomObject]#{
ComputerName = $Server
Service = $Service
Exists = if (Get-Service -Name $service -ComputerName $Server -ErrorAction SilentlyContinue) { $true } else { $false }
}
}
}
as for what you tried:
$Result = Invoke-Command -ComputerName $Server -ScriptBlock {
Get-Service -Name $Service
}
$service (as mentioned above), is empty and not defined on the remote sessions scope.
When you switched it to $using:service it worked but, it returned the type of object and not the name itself, because you're returning the entirety of an object and not the name property. Instead, just reference the current $service that is being used in the loop and declare if it's there, or not.
the script is not structured correctly, an no need to us the invoke command, when you can use 'get-service -computername' Also the try, catch statement would only catch the last error not each.
I changed your original script to reflect this and moved the try, catch statement to catch each error (if the service does not exist).
$ErrorActionPreference='stop'
$ServerList = Get-Content 'C:\temp\servicetest\servers.txt'
$ServiceList = Get-Content 'C:\temp\servicetest\services.txt'
ForEach($Server in $ServerList){
#Get-Service -ComputerName $Server -Name 'XblAuthManager'
ForEach($Service in $ServiceList){
try {
$a = Get-Service -ComputerName $Server -Name $Service
IF ($a) {
Write-Host "Service - $Service exists on Server - $Server"
}
} catch {
Write-Host "Service - $Service does not exist on Server - $Server"
}
}
}

I'm trying to run a powershell command to uninstall a WinPcap, but after trying trying different methods I'm still not succesfull?

Below is the script that I'm running that always gives either a Program error or a The term 'x86' is not recognized as the name of a cmdlet error. The service stops but the Invoke-Command seems to be the problem.
$Servers = Get-Content "C:\DTServerScript\Servers.txt"
ForEach ($Server in $Servers) {
$Status = ""
do
{
#Stopping Service
$ServiceAgent = Get-Service -ComputerName $Server | Where {$_.Name -like "*oneagent*"}
Write-Host "Pending Stop on $Server"
Stop-Service $ServiceAgent
sleep 1
$Status = $ServiceAgent.Status
} until ($Status -eq "Stopped")
Write-Host "Service state is $Status on $Server"
# Execute config change
# Invoking Commands on Server
Invoke-Command -ComputerName $Server {cmd.exe/ c:\Program Files (x86)\WinPcap\uninstall.exe /S }
write-host "Service is starting on $Server"
# Starting Service
Start-Service $ServiceAgent
$ServiceAgent = Get-Service -ComputerName $Server | Where {$_.Name -like "*oneagent*"}
$Status = $ServiceAgent.Status
}
Try quoting the path and using braces around the name containing ()..
Invoke-Command -ComputerName $Server { & $Env:ComSpec /C "${Env:ProgramFiles(x86)}\WinPcap\uninstall.exe" /S }

Is There a function to bypass dependent services when stoping a service in Powershell?

I have some issues with my Powershell code
I need to stop and disable some services with this script BUT there are some issues, here it is:
Get-Content -path $PWD\servicestop1.txt | ForEach-Object
{
$service = $_
(Set-Service -Name $service -Status Stopped -StartupType Disabled -PassThru )
}
1 - I encounter some dependencies issue when I want to stop some services
2 - I can't get to disable and stop them in the same script
Do you have any idea?
Thanks a lot!
PS: I tried to use the parameter "-force" but it didn't work
Without knowing the servicestop1.txt actually holds valid service names, You may try this:
Get-Content -Path "$PWD\servicestop1.txt" | ForEach-Object {
$service = Get-Service -Name $_ -ErrorAction SilentlyContinue
if ($service) {
if ($service.Status -eq 'Running') {
# stop the service and wait for it
$service | Stop-Service -Force
}
if ($service.StartType -ne 'Disabled') {
$service | Set-Service -StartupType Disabled
}
}
else {
Write-Warning "Could not find service with name '$_'"
}
}

How to Disable all BizTalk Hostinstances with PowerShell script

I'm trying to make a PowerShell script to stop and disable from starting all BizTalk host instances.
Stopping is no problem with this code:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 1) -and ($hostinst.ServiceState -ne 8) ) {
Write-Host "Stop Hostinstance" $hostinst.HostName
$hostinst.Stop()
Write-Host "Hostinstance" $hostinst.HostName "stopped"
}
}
But now I'm trying to Disable all stopped Host Instances from starting up.
My first try gives no error but doesn't do anything.
All host instance are mentioned in the output but they are not disabled.
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
$hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
My second try gives an error because of the -path parameter.
$hosts = Get-WmiObject MSBTS_HostInstance -namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -eq 1) -or ($hostinst.ServiceState -eq 8) ) {
Write-Host "disable Hostinstance" $hostinst.HostName
Set-ItemProperty -Path $hostinst__PATH -Name IsDisabled -Value $True
# $hostinst.IsDisabled = $true
Write-Host "Hostinstance" $hostinst.HostName "is disabled"
}
}
What is the correct method to set the property IsDisabled to $true or to $false?
BizTalk host instance is a windows service. So you can use powershell's Get-Service cmdlet to stop and disable it.
Suppose your host name is BizTalkServerApplication
Then following script will do the job:
Get-Service -Name BTSSvc`$BizTalkServerApplication | Stop-Service -PassThru | Set-Service -StartupType disabled
Also note the "$" is escaped as "`$"
#Zee is close, but still needs to loop through.. Here's one way to do that - concat the host's name with BTSSvc
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Stop-Service -PassThru | Set-Service -StartupType disabled
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And if you need to set them back to Automatic/started:
$hosts = Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer'
foreach($hostinst in $hosts) {
if ( ($hostinst.ServiceState -ne 8) ) { # ignore isolated hosts
$svcName = ('BTSSvc${0}' -f $hostinst.HostName) # get something Get-Service can work with
Get-Service -Name $svcName | Set-Service -StartupType Automatic -PassThru | Start-Service
Write-Host "Hostinstance" $hostinst.HostName "stopped and disabled"
}
}
And here's a way that might be even a little clearer:
Get-Service | Where-Object { $_.Name.StartsWith("BTSSvc") } | Stop-Service -PassThru | Set-Service -StartupType Disabled
Thanks for your answers.
However there are 2 reasons why this doesn't work completely fine in a BizTalk environment with multiple servers.
First in your solution you have to manually configure the list of servers for each environment in OTAP. With the option Get-WmiObject MSBTS_HostInstance -Namespace 'root/MicrosoftBizTalkServer' BizTalk knows which servers belong the BizTalkGroup.
Second (and more important) the present state is "Automatic(Delayed start)".
Setting the state back to Automatic(Delayed start) with Powershell script is not posible according to several websites.
I understand now why $hostinst.IsDisabled = $true didn't work.
Because the change must be saved first.
That's why I have added a command to save the changes.
$script:btscatalog.SaveChanges() | Out-Null
Unfortunately still nothing seems to be changed.
Do not use default windows service to disable the BizTalk service
Use WMI to get list of BizTalk host instances
$inProcessHosts = "HostType=1"
$nsBTS = "root/MicrosoftBizTalkServer"
$filter = "($inProcessHosts)"
$hostInstances = Get-WmiObject MSBTS_HostInstance -Namespace $nsBTS -Filter $filter
Disable items in a for each loop (redirect output from put)
foreach ($hostInstance in $hostinstances)
{
$hostInstance.IsDisabled = $true
$hostInstance.Put() > $null
}
EDIT:
There is a way to set automatic (delayed start) if needed
#=== Change the startup type for BizTalk services to Automatic (Delayed Start) ===#
get-service BTSSvc* | foreach-object -process { SC.EXE config $_.Name start= delayed-auto}
From Technet WIKI:
https://social.technet.microsoft.com/wiki/contents/articles/19701.biztalk-server-best-practices-create-and-configure-biztalk-server-host-and-host-instances.aspx

Check if a Windows service exists and delete in PowerShell

I am currently writing a deployment script that installs a number of Windows services.
The services names are versioned, so I want to delete the prior Windows service version as part of the installs of the new service.
How can I best do this in PowerShell?
You can use WMI or other tools for this since there is no Remove-Service cmdlet until Powershell 6.0 (See Remove-Service doc)
For example:
$service = Get-WmiObject -Class Win32_Service -Filter "Name='servicename'"
$service.delete()
Or with the sc.exe tool:
sc.exe delete ServiceName
Finally, if you do have access to PowerShell 6.0:
Remove-Service -Name ServiceName
There's no harm in using the right tool for the job, I find usign sc.exe (via PowerShell) to be the most reliable method with few dependencies.
Local:
sc.exe delete "MyService"
Remote server:
sc.exe \\server delete "MyService"
If you just want to check service existence:
if (Get-Service "My Service" -ErrorAction SilentlyContinue)
{
"service exists"
}
I used the "-ErrorAction SilentlyContinue" solution but then later ran into the problem that it leaves an ErrorRecord behind. So here's another solution to just checking if the Service exists using "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
But ravikanth has the best solution since the Get-WmiObject will not throw an error if the Service didn't exist. So I settled on using:
Function ServiceExists([string] $ServiceName) {
[bool] $Return = $False
if ( Get-WmiObject -Class Win32_Service -Filter "Name='$ServiceName'" ) {
$Return = $True
}
Return $Return
}
So to offer a more complete solution:
# 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
}
More recent versions of PS have Remove-WmiObject. Beware of silent fails for $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:\>
For my situation I needed to be running 'As Administrator'
To delete multiple services in Powershell 5.0, since remove service does not exist in this version
Run the below command
Get-Service -Displayname "*ServiceName*" | ForEach-object{ cmd /c sc delete $_.Name}
One could use Where-Object
if ((Get-Service | Where-Object {$_.Name -eq $serviceName}).length -eq 1) {
"Service Exists"
}
Combining Dmitri & dcx's answers I made this:
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
}
}
For single 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 for list of 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."}
}
To check if a Windows service named MySuperServiceVersion1 exists, even when you might not be sure of its exact name, you could employ a wildcard, using a substring like so:
if (Get-Service -Name "*SuperService*" -ErrorAction SilentlyContinue)
{
# do something
}
PowerShell Core (v6+) now has a Remove-Service cmdlet.
I don't know about plans to back-port it to Windows PowerShell, where it is not available as of v5.1.
Example:
# PowerShell *Core* only (v6+)
Remove-Service someservice
Note that invocation fails if the service doesn't exist, so to only remove it if it currently exists, you could do:
# PowerShell *Core* only (v6+)
$name = 'someservice'
if (Get-Service $name -ErrorAction Ignore) {
Remove-Service $name
}
Adapted this to take an input list of servers, specify a hostname and give some helpful output
$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)}
For PowerShell versions prior to v6, you can do this:
Stop-Service 'YourServiceName'; Get-CimInstance -ClassName Win32_Service -Filter "Name='YourServiceName'" | Remove-CimInstance
For v6+, you can use the Remove-Service cmdlet.
Observe that starting in Windows PowerShell 3.0, the cmdlet Get-WmiObject has been superseded by Get-CimInstance.
Windows Powershell 6 will have Remove-Service cmdlet.
As of now the Github release shows PS v6 beta-9
Source: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/remove-service?view=powershell-6
I know it's an old question but if someone is looking for one-liner:
On PS Version > 7.2
Wildcard search on the Name property
Get-Service *name* | Select-Object -First 1 | Remove-Service
Search the Display Name property
Get-Service -DisplayName "My Service Description" | Remove-Service