PowerShell loop issue - powershell

I've got a piece of code to check the status of a particular service and if the status is not "running" to start it. The variable seems to have the proper data before the if/else statement but it always defers to else even when I have one of the test server's service set to off. It will report one service as running and one as stopped but will echo "It's Down" for both.
Thanks in advance for your help
$Servers = get-content c:\scripts\list.txt
$Servers|foreach {
$service = Get-WmiObject -ComputerName $_ -Class Win32_Service -Filter "Name='Buildbot'"
$status = Get-Service -ComputerName $_ -Name "Buildbot" | select Status
echo $status
if ($status -eq "Running") {"Its Up!"} else {"It's down"}
#$service.StartService()
#"It should be up now"}
}

Pretty sure your issue is that you are doing a string comparison on an object with the property status as supposed a string of the status state. Update the line that populates $status like either of the following examples
$status = Get-Service -ComputerName $_ -Name "Buildbot" | select -ExpandProperty Status
$status = (Get-Service -ComputerName $_ -Name "Buildbot").Status
As an aid consider the output of the following two commands
PS C:\Users\mcameron> Get-Service -Name "Print Spooler" | select Status
Status
------
Running
PS C:\Users\mcameron> Get-Service -Name "Print Spooler" | select -expand Status
Running
The first result is an object with the property Status. Second is just a string.

Related

Kill only a specific Command Prompt Process Remotely with PowerShell

I am trying to write a script to remote kill a specific command prompt process.
If I locally run get-process I can see that the CMD.exe process can be narrowed down by what is set in the field "MainWindowTitle"
If I get use Get-Process -computer name or get CIMInstance the field "MainTitleWindow" comes back as blank.
$ses = New-CimSession -ComputerName $computer -Credential $cred
$process = Get-CimInstance -ClassName CIM_process -CimSession $ses -filter "name = 'cmd.exe'"
$process | Select-Object name,MainWindowTitle
Remove-CimSession -CimSession $ses
name MainWindowTitle
---- ---------------
cmd.exe
Extracted from MSDN:
A process has a main window associated with it only if the process has
a graphical interface. If the associated process does not have a main
window (so that MainWindowHandle is zero), MainWindowTitle is an empty
string ("").
More info here.
I tried to compare with other processes but the result is the same...
You could parse the output of the tasklist command. Like this:
$cmds = tasklist /v |
Where-Object {$_ -like "cmd.exe*"} |
ForEach-Object {
New-Object -TypeName PSObject -Prop #{"ID"=[int]$_.Substring(30,5); `
"Title"=$_.Substring(157)}
}
$cmds
$Process = Get-CimInstance CIM_Process -CimSession $Ses | Where-Object{ $ProcessNames -contains $_.Name }
using this you can also get the ProcessID and ParentProcessID.
you can then use the similar commands to then find the CMD process that uses the ParentProcessID of your main script.
You must close both the main process of the script and the command prompt as well or else the script will keep running.

Powershell to restart a service running longer than

I'm trying to write a powershell script that will:
Restart a service if it has been running more than 1 hour
Leave it alone if less than 1 hour
Start it if it's in the stopped state.
I currently have the following below but when it comes to adding extra variables and if statements I'm terrible. This script works very well, but I can't get it to restart, only start/stop seem to work.
Get-Service "Print Spooler" |
Where StartTime -lt (Get-Date).AddMinutes(-60) |
Stop-Service
I'd suggest a variable for this:
# for debugging
$PSDefaultParameterValues['*Service:Verbose'] = $true
$svc = Get-Service -Name Spooler
if ($svc.Status -eq 'stopped') {
$svc | Start-Service
} elseif ($svc.StartTime -lt (Get-Date).AddHours(-1)) {
$svc | Stop-Service -PassThru | Start-Service
} else {
'Print Spooler is running and StartTime is within the past hour!'
}
# other logic goes here
StartTime doesn't appear to be a property of the ServiceController class that Get-Service returns on my system. Neither is the service's process ID, absurdly enough. That's infuriatingly poor design, but so it goes. So, I'd use CIM/WMI to get the process ID to determine when the service started.
$Service = Get-Service "Print Spooler"
$ServiceStartTime = (Get-CimInstance -ClassName Win32_Service -Filter "Name = '$($Service.Name)'" -Property ProcessId | ForEach-Object { Get-Process -Id $_.ProcessId }).StartTime
# If services has been running for an hour, stop it
if (($Service.Status -eq 'Running') -and ($ServiceStartTime -lt (Get-Date).AddHours(-1))) {
Stop-Service $Service
}
# If service isn't running, start it
if ($Service.Status -eq 'Stopped') {
Start-Service $Service
}

How to filter the output of get-service so it won't show stopped services

I'm very sure this is something easy but since I am new in powershell I couldn't figure out a way to do it. The following command:
Get-Service | Sort-Object -Property status -Descending
displays services on the PC, sorts them by status so it shows running processes in the beginning of the list. Stopped services come right after started services Can I do any filter so it won't show stopped services?
Please get in the habit of not using abbreviations when posting codes on online forum for this post and all other posts.
Thank You!
Get-Service |
Where-Object { $Psitem.Status -ne 'Stopped' } |
Sort-Object -Property status -Descending
This effectively filters by status.
Depending on the PowerShell version ($PSVersionTable.PSVersion)
You can run two commands:
PS Version 2.0 get-service | where {$_.status -eq 'running'}
PS Version 3.0 or greater get-service | where status -eq 'running'
PS Version 3.0 or greater get-service | ? status -eq 'running'
The big differance between the two versions are the {Curly brackets} and you can also use Alias Get-Alias
The following function will allow you to select only one service that you want to stop. After time of your choice currently 5 minutes. The service will start again. The GUI option does allow you to start and stop when you choose.
Stop a Service
Function ManageService{
$Service=Get-Service | where {$_.status -eq 'running'} | Out-GridView -OutputMode Single
$GUI = new-object -comobject wscript.shell
if ($Service.Status -eq "Running"){
$ServiceName=$Service.DisplayName
$Yes_Cancle = $GUI.popup("Do you want to turn stop $ServiceName ?", `
0,"Manage Service",3)
If ($Yes_Cancle -eq 6) {
Stop-Service $ServiceName
$GUI.popup("$ServiceName service has been STOPPED and will START again in 5 minutes, soon as you hit OK")
start-Sleep -s 300
$GUI.popup("Time is up! $ServiceName service will now start as soon as you hit OK")
Start-Service $ServiceName
cls
}
else {
$GUI.popup("You decided to cancel. $ServiceName will not be stopped")
cls
}}}
cls
ManageService
Kill a Process
Function ManageProcess{
$Process=Get-Process | Out-GridView -OutputMode Single
$GUI = new-object -comobject wscript.shell
if ($Process.processname -ne "$False"){
$ProcessName=$Process.processname
$Yes_Cancle = $GUI.popup("Do you want to turn kill $ProcessName ?", `
0,"Manage Process",3)
If ($Yes_Cancle -eq 6) {
Stop-Process -processname $ProcessName
$GUI.popup("$ProcessName has been killed as soon as you hit OK")
cls
}
else {
$GUI.popup("You decided to cancel. $ProcessName will not be killed")
cls
}}}
cls
ManageProcess

How can I list the Startup Type of a serive running on a remote machine?

I'm trying to find out the startup type of a service running on a remote machine.
I've tried the below but it gives me the Start Mode rather than the Startup Type.
[cmdletbinding()]
param(
[string[]]$Service,
[switch]$Disabled,
[switch]$Automatic,
[switch]$Manual,
[string]$ComputerName = $env:ComputerName
)
foreach($Ser in $Service) {
try {
$Obj = Get-WmiObject -Class Win32_Service -Filter "Name='$Ser'"-ComputerName $ComputerName -ErrorAction Stop
$Obj | select Name, DisplayName, StartMode
} catch {
Write-Error " Failed to get the information. More details: $_"
}
}
.\Get-ServiceStartupType.ps1 –Service wscsvc –ComputerName Computername
The Service is "wscsvc" Security Center
If you use
Get-Service -name $ser -computername $computername | select-object Name,StartType
Instead of get-wmiobject. I've also used the pipeline instead of a variable to make the code a little cleaner.
You'll need to use Get-Service instead of Get-WmiObject:
$svc = Get-Service wscsvc
$svc.StartType
Used in your code like this:
$Obj = Get-Service $Ser -ComputerName $ComputerName -ErrorAction Stop
$Obj | select Name, DisplayName, StartType

Simplify PS Command: Get-Service | where {($_.Status -eq "Stopped") -OR ($_.Status -eq "Running")}

What is the syntax to include several values in an -eq command:
This works but i think there is a way to save some typing:
Get-Service | where {($_.Status -eq "Stopped") -OR ($_.Status -eq "Running")}
Think code should look like but i don't remember exactly the syntax:
Get-Service | where {($_.Status -eq "Stopped"|"Running"|"...")}
You can use -contains and the gsv alias :
gsv | where-object {#("Stopped","Running") -contains $_.Status}
EDIT: You can also use the -match operator:
gsv | where-object {$_.Status -match "Stopped|Running"}
2.EDIT: A shorter version, w/ special thanks to #Joey:
gsv | ? {$_.Status -match "Stopped|Running"}
As stated by #OcasoProtal you can compare an array of valid statuses with your target status using the -contains or -notcontains operators.
Given Status is based on an enum type you can also use that (i.e. as opposed to using string comparisons). This adds additional validation (i.e. without manually specifying a ValidateSet), and allows you to pull a list of values from the Enum (e.g. as shown in my sample code below where Not is specified.
clear-host
[string]$ComputerName = $env:COMPUTERNAME
[string]$ServiceName = "MSSQLSERVER"
function Wait-ServiceStatus {
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$ServiceName
,
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$ComputerName = $env:COMPUTERNAME
,
[switch]$Not
,
[Parameter(Mandatory = $true)]
[System.ServiceProcess.ServiceControllerStatus]$TartgetStatus
)
begin {
[System.ServiceProcess.ServiceControllerStatus[]]$TargetStatuses = #($TartgetStatus)
if ($Not.IsPresent) {
#EXAMPLE: Build your comparison array direct from the ENUM
$TargetStatuses = [Enum]::GetValues([System.ServiceProcess.ServiceControllerStatus]) | ?{$_ -ne $TartgetStatus}
}
}
process {
#EXAMPLE: Compare status against an array of statuses
while ($TargetStatuses -notcontains (Get-Service -ComputerName $ComputerName -Name $ServiceName | Select -Expand Status)) {
write-host "." -NoNewline -ForegroundColor Red
start-sleep -seconds 1
}
write-host ""
#this is a demo of array of statuses, so won't bother adding code for timeouts / etc
}
}
function Write-InfoToHost ($text) {write-host $text -ForegroundColor cyan} #quick thing to make our status updates distinct from function call output
Write-InfoToHost "Report Current Service Status"
get-service -Name $ServiceName -Computer $ComputerName | Select -ExpandProperty Status
Write-InfoToHost ("Stop Service at {0:HH:mm:ss}" -f (get-date))
(Get-WmiObject Win32_Service -Filter "name='$ServiceName'" -Computer $ComputerName).StopService() | out-null #use WMI to prevent waiting
Write-InfoToHost ("Invoked Stop Service at {0:HH:mm:ss}" -f (get-date))
Wait-ServiceStatus -ServiceName $ServiceName -TartgetStatus Stopped
Write-InfoToHost ("Stop Service Completed at {0:HH:mm:ss}" -f (get-date))
Write-InfoToHost "Report Current Service Status"
get-service -Name $ServiceName -Computer $ComputerName | Select -ExpandProperty Status
Write-InfoToHost ("Start Service at {0:HH:mm:ss}" -f (get-date))
(Get-WmiObject Win32_Service -Filter "name='$ServiceName'" -Computer $ComputerName).StartService() | out-null #use WMI to prevent waiting
Write-InfoToHost ("Invoked Start Service at {0:HH:mm:ss}" -f (get-date))
Wait-ServiceStatus -ServiceName $ServiceName -Not -TartgetStatus Stopped
Write-InfoToHost ("Service Not Stopped at {0:HH:mm:ss}" -f (get-date))
Wait-ServiceStatus -ServiceName $ServiceName -Not -TartgetStatus StartPending
Write-InfoToHost ("Service Not Start-Pending at {0:HH:mm:ss}" -f (get-date))
Write-InfoToHost "Report Current Service Status"
get-service -Name $ServiceName -Computer $ComputerName | Select -ExpandProperty Status
Sample Output:
Report Current Service Status
Running
Stop Service at 12:04:49
Invoked Stop Service at 12:04:50
.
Stop Service Completed at 12:04:51
Report Current Service Status
Stopped
Start Service at 12:04:51
Invoked Start Service at 12:04:52
Service Not Stopped at 12:04:52
..
Service Not Start-Pending at 12:04:54
Report Current Service Status
Running
You can also easily get Pending or "Stable State" statuses using something like this:
function PendingDemo([bool]$Pending) {
write-host "Pending is $Pending" -ForegroundColor cyan
[Enum]::GetValues([System.ServiceProcess.ServiceControllerStatus]) | ?{($_ -notlike "*Pending") -xor $Pending}
}
PendingDemo $true
""
PendingDemo $false
Sample Output:
Pending is True
StartPending
StopPending
ContinuePending
PausePending
Pending is False
Stopped
Running
Paused
matching based on regex groups is the shortest and safest way always. You can use also the complementary :
gsv | ? {$_.status -notmatch "Paused|Running_Pending|Pause_Pending|Stop_Pending|Continue_Pending"}
In this case it's not the shortest, obviously; but sometime it is!