Check Windows Services statuses using Powershell


To totally unlock this section you need to Log-in

PowerShell is a great and essential "scripting" (the scripting is just one of the many things this language can do) tool. It not only helps save you time, it also provides greater flexibility to execute repeated tasks manually or via scheduled tasks. Almost all Windows roles and features ship with PowerShell cmdlets.

Several Powershell cmdlets, available by default on modern Windows OS versions, let us to perform operational tasks such as checking the status of a particular Windows service on multiple computers, checking the list of software installed on Windows computers, checking and collecting roles and features installed on Windows Server Operating Systems and much more.

One of the tasks Windows administrators frequently perform is checking the status of critical services on critical production servers such as Exchange Servers, SQL Servers and/or Active Directory domain controllers.

Though you can use SCCM and similar tools to provide you with a report on the status of services from a particular set of machines, SCCM requires that the SCCM Client is working on all target computers before SCCM can report on the status of services.

However, we can use a PowerShell script approach to quickly and easily check the status of particular services on a single or multiple Windows computers.

Checking the Status of a Single Service

If you would like to check status of a particular service on a remote computer, what you can do is execute the PowerShell command below:

Get-WMIObject -Computer <RemoteComputerName> -Query "Select * From Win32_Service WHERE Name Like "%SomeServiceName%"

Executing the above PowerShell command will help you get the status, using WMI, of a specific service specified in the %SomeServiceName% parameter. This command connects to a remote computer specified using the -Computer parameter. We will have to change both the computer and service names before executing the above command.

Another approach that we can follow is by using the Get-Service command that allows us to get information about installed services on server and clients getting services details of the remote endpoints also without even log in.

Following are some examples on how to get service details by using Get-Service.

Show all the running services on the system (client or server):

Get-Service | Where {$_.status –eq 'running'}

Checking the Status of Multiple Services

In case you would like to get a list of all Windows Services that are running on a target system, execute the following PowerShell command:

Get-WMIObject Win32_Service -Computer  | Where {$_.State -eq "Running"} | FT -Auto

The above command will list all Windows Services that are running from the remote computer specified in the -Computer parameter, and the output will be displayed in the PowerShell window. If we would like to save the output in a CSV file, adding "Export-CSV" will do the job as shown in the following command:

Get-WMIObject Win32_Service -Computer  | Where {$_.State -eq "Running"} | FT -Auto | Export-CSV "C:\Temp\ServicesStatus.csv"

Another approach would be the following; let's create a 2 txt file and save one as services.txt which is the list of service one by one and in machines.txt list server one by one:

services.txt >

wuauserv
MpsSvc
W32Time
W3SVC
wmiApSrv

machines.txt >

vm1
vm2
vm3
vm4
vm5

Then, we can run the following code, executed in the same directory in which resides the two text files previously created (in this example they are on C:\, but it is not a recommended path), using the Get-Service cmdlet to get details for several services on several systems.

$services = Get-Content -Path "C:\service_list.txt"
$machines = Get-Content -Path "C:\computers_list.txt"
foreach ($computer in $machines){
Write-host "Services are going to be detailed on $computer" -b "green" -foregroundcolor "red"
foreach ($service in $services) {
Get-Service -ComputerName $computer -Name $service
}
}

Another approach, always using the services.txt and machines.txt files, is by download and using PsService.exe, saving it in the same folder from where you are running the below script (it could be necessary to include also user and passowrd parameters):

$services = Get-Content -Path "C:\services.txt"
$sachines = Get-Content -Path "C:\machines.txt"
foreach ($computer in $machines){
Write-host "Services are going to be detailed on $computer" -b "green" -foregroundcolor "red"
foreach ($service in $services) {
PsService.exe \\$computer start $service
}
}

Checking the Status of a Single Service on Multiple Computers

While the above PowerShell commands will help you get you the status of a specific or multiple services from a single Windows computer, the following PowerShell script can be used if you would like to see the status of a single service from multiple Windows computers. All you need to do is create a text file that contains the Windows computer names and modify the script variable "$ServiceNameToCheck" to include the service you would like to check.

$ServiceNameToCheck ="SomeServiceName"
$ReportFile = "C:\Temp\ServiceStatus.csv"
Remove-item $ReportFile -ErrorAction SilentlyContinue
$ThisSTR = "Computer Name, Service Status"
Add-Content $ReportFile $ThisSTR
$CompFile = "C:\Temp\Computers.txt"

Foreach ($ComputerName in Get-Content "$CompFile")
{
$Error.Clear()
Get-WMIObject -Computer $ComputerName -Query "Select * From Win32_Service WHERE Name Like "%$ServiceNameToCheck% AND {$_.State -eq "Running"}
IF ($Error.Count -ne 0)
{
$ThisSTR = $ComputerName+", Could Not Connect to Remote Computer or Service Not Running"
Add-Content $ReportFile $ThisSTR
}
else
{
$ThisSTR = $ComputerName+", Running"
Add-Content $ReportFile $ThisSTR
}
}
Write-Host "Service status was retrieved from the list of computers and the output was saved in $ReportFile"

Once the PowerShell script above has finished executing, a report file will be created named ServiceStatus.csv in the "C:\Temp" folder that contains the status of the service name specified in the $ServiceNameToCheck variable from all computers mentioned in the "C:\Temp\Computers.txt" file.

Note that the script checks to make sure the command was executed successfully before it reports the status of the service. The PowerShell script uses the "Get-WMIObject" PowerShell cmdlet to collect the status of specific service(s) from target computers.

In case the Get-WMIObject is not able to connect to a target computer or if the service status is not retrieved, it will return a "Could Not Connect to Remote Computer or Service Not Running" message in the report.

Instead, using again the Get-Service cmdlet approach, we can reach easily the same goal.

Get the service from (SERVICE-NAME) in SERVER1, SERVER2 with format-table:

Get-Service -ServiceName *SERVICE-NAME* -ComputerName SERVER1, SERVER2 | select name, status, machinename | sort machinename | format-table -AutoSize

Get the service status form the list of server name store in MyServers.txt.

Get-Service -computername (get-content c:\folder\Servers_list.txt) | Select servername,status |sort name | format-table -autosize

Get server from wuauserv (Windows Update service) from listed VM’s:

'vm1','vm2','vm3'| foreach {get-service wuauserv -computername $_} | Format-Table Name,Status,Machinename -AutoSize

Run the service from the listed remote VMs:

Get-Service -Name express* -Computer vm1, vm2, vm3 | ? { $_.Status -eq "Running" } | format-table -auto MachineName, ServiceName, DisplayName, Status

Find out from the list of server in which one SQL is installed and export in csv file.

$Machines = Get-Content -Path "C:\machines.txt"
foreach ($computer in $machines) {
Write-host "SQL Service chacking on $computer" -b "green" -foregroundcolor "red"
Get-Service -Displayname "*SQl Server*" -ComputerName "$computer" }

The following Powershell function, called Get-ServiceStatus, can be used, as well, to check a service on multiple systems; it also integrates the Send-MailMessage function, to send alerts, if the service is not running anymore. This kind of script can be very useful once scheduled on production systems, for example.

The following function can only keep track of the last service status polled and notify when there is a change: to accomplish this, the script uses a text file, written on a specified path on the system, using the -Path parameter.

If a service is down, the code creates the text file with detailed information and sends an alert. When the service is back up, it deletes the text file.

The e-mail notification step is not mandatory (the function will check if SmtpServer and FromAddress variables are set or not).

function Get-ServiceStatus
{	
	param (
		[string[]]$ComputerName,
		[string]$ServiceName,
		[string]$Path,
		[string]$FromAddress,
		[string]$ToAddress,
		[string]$SmtpServer
	)
	# Test ping
	workflow Test-Ping
	{
		param (
			[Parameter(Mandatory = $true)]
			[string[]]$Computers
		)
		foreach -parallel -throttlelimit 150 ($Computer in $Computers)
		{
			if (Test-Connection -Count 1 $Computer -Quiet -ErrorAction SilentlyContinue)
			{
				$Computer
			}
			else
			{
				Write-Warning -Message "$Computer not online"
			}
		}
	}
	$ComputerName = Test-Ping -Computers $ComputerName
	
	foreach ($Computer in $ComputerName)
	{
		$NewPath = Join-Path -Path $Path -ChildPath $Computer
		#Get previous status
		if (Test-Path -Path $NewPath)
		{
			$PreviousStatus = 'Not Running'
		}
		else
		{
			$PreviousStatus = 'Running'
		}
		
		#Get current status
		$CurrentStatus = Get-Service -Name $ServiceName -ComputerName $Computer | Where-Object { $_.Status -eq 'Running' }
		if ($CurrentStatus)
		{
			$CurrentStatus = 'Running'
		}
		else
		{
			$CurrentStatus = 'Not Running'
		}
		
		#Current status running and previous up
		if ($PreviousStatus -eq 'Running' -and $CurrentStatus -eq 'Running')
		{
			Write-Output "$Computer $ServiceName still running"
			Continue
		}
		
		#Current status running and previous down
		if ($PreviousStatus -eq 'Not Running' -and $CurrentStatus -eq 'Running')
		{
			Write-Warning -Message "$Computer $ServiceName now running"
			Remove-Item -Path $NewPath -Force | Out-Null
			If (($FromAddress) -And ($SmtpServer))
			{
				Send-MailMessage -Body ' ' -From $FromAddress -SmtpServer $SmtpServer -Subject "$Computer $ServiceName is now running" -To $ToAddress
			}
			Continue
		}
		
		#Current status down and previous down 
		if ($PreviousStatus -eq 'Not Running' -and $CurrentStatus -eq 'Not Running')
		{
			Write-Warning -Message "$Computer $ServiceName still not running"
			New-Item -Path $NewPath -ItemType File -Force | Out-Null
			Continue
		}
		
		#Current status down and previous up 
		if ($PreviousStatus -eq 'Running' -and $CurrentStatus -eq 'Not Running')
		{
			Write-Warning -Message "$Computer $ServiceName is not running"
			New-Item -Path $NewPath -ItemType File -Force | Out-Null
			If (($FromAddress) -And ($SmtpServer))
			{
				Send-MailMessage -Body ' ' -From $FromAddress -SmtpServer $SmtpServer -Subject "$Computer $ServiceName is not running" -To $ToAddress
			}
			Continue
		}
	}
}

##### Example ########
Get-ServiceStatus -ServiceName DoSvc -Path C:\Results -ComputerName 127.0.0.1,localhost

The following is how this function operates:

  • Check if a specific text file is the specified path.
  • If there is a text file, it means that the service was not running before.
  • If the service is not running and there is no text file, create a text file.
  • Send an email alert saying that the service is down.
  • If the service is running again, remove the text file.
  • Send an email saying that the service is up.
  • To run the function you’ll need to specify the computer name (remote or local), the service name, and path name where the text files will be stored.

Other important parameters to specify are the source email and destination email addresses.

For example, the below command will check, on multiple computers (in this case I have set both 127.0.0.1 and localhost, basically checking the same system) the status of the DoSvc service, and sending an e-mail in case of a Not Running result:

Get-ServiceStatus -ComputerName 127.0.0.1,localhost -ServiceName DoSvc -Path C:\Results\ -FromAddress [email protected] ‑ToAddress [email protected] -SmtpServer smtp.example.com

Service Status Report

Another approach could be also to create scheduled task, to check several systems (clients and servers), by using the following Powershell code script, that will generate a simple .htm file with the status of all services specified (multiple services), for all the computers (included in a single simple text file, but this approach can be changed easily) that we want to monitor regularly. The function will send also a mail notification, if needed (not mandatory).

Function Get-ServiceStatusReport
{
	param (
		[String]$ComputerList,
		[String[]]$includeService,
		[String]$To,
		[String]$From,
		[string]$SMTPMail
	)
	$script:list = $ComputerList
	$ServiceFileName = "C:\DBwiki\ServiceFileName.htm"
	New-Item -ItemType file $ServiceFilename -Force
	# Function to write the HTML Header to the file 
	Function writeHtmlHeader
	{
		param ($fileName)
		$date = (get-date).ToString('yyyy/MM/dd')
		Add-Content $fileName "<html>"
		Add-Content $fileName "<head>"
		Add-Content $fileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"
		Add-Content $fileName '<title>Service Status Report </title>'
		add-content $fileName '<STYLE TYPE="text/css">'
		add-content $fileName  "<!--"
		add-content $fileName  "td {"
		add-content $fileName  "font-family: Tahoma;"
		add-content $fileName  "font-size: 13px;"
		add-content $fileName  "border-top: 1px solid #999999;"
		add-content $fileName  "border-right: 1px solid #999999;"
		add-content $fileName  "border-bottom: 1px solid #999999;"
		add-content $fileName  "border-left: 1px solid #999999;"
		add-content $fileName  "padding-top: 0px;"
		add-content $fileName  "padding-right: 0px;"
		add-content $fileName  "padding-bottom: 0px;"
		add-content $fileName  "padding-left: 0px;"
		add-content $fileName  "}"
		add-content $fileName  "body {"
		add-content $fileName  "margin-left: 5px;"
		add-content $fileName  "margin-top: 5px;"
		add-content $fileName  "margin-right: 0px;"
		add-content $fileName  "margin-bottom: 10px;"
		add-content $fileName  ""
		add-content $fileName  "table {"
		add-content $fileName  "border: thin solid #000000;"
		add-content $fileName  "}"
		add-content $fileName  "-->"
		add-content $fileName  "</style>"
		Add-Content $fileName "</head>"
		Add-Content $fileName "<body>"
		
		add-content $fileName  "<table width='100%'>"
		add-content $fileName  "<tr bgcolor='#CCCCCC'>"
		add-content $fileName  "<td colspan='4' height='25' align='center'>"
		add-content $fileName  "<font face='tahoma' color='#003399' size='4'><strong>Service Stauts Report - $date</strong></font>"
		add-content $fileName  "</td>"
		add-content $fileName  "</tr>"
		add-content $fileName  "</table>"
		
	}
	
	# Function to write the HTML Header to the file 
	Function writeTableHeader
	{
		param ($fileName)
		
		Add-Content $fileName "<tr bgcolor=#CCCCCC>"
		Add-Content $fileName "<td width='10%' align='center'>ServerName</td>"
		Add-Content $fileName "<td width='50%' align='center'>Service Name</td>"
		Add-Content $fileName "<td width='10%' align='center'>Status</td>"
		Add-Content $fileName "</tr>"
	}
	
	Function writeHtmlFooter
	{
		param ($fileName)
		
		Add-Content $fileName "</body>"
		Add-Content $fileName "</html>"
	}
	
	Function writeDiskInfo
	{
		param ($filename,
			$Servername,
			$name,
			$Status)
		if ($status -eq "Stopped")
		{
			Add-Content $fileName "<tr>"
			Add-Content $fileName "<td style='background-color:#FF0000; text-align:center; color:#FFF'><b>$servername</td>"
			Add-Content $fileName "<td style='background-color:#FF0000; text-align:center; color:#FFF'><b>$name</td>"
			Add-Content $fileName "<td style='background-color:#FF0000; text-align:center; color:#FFF'><b>$Status</td>"
			Add-Content $fileName "</tr>"
		}
		else
		{
			Add-Content $fileName "<tr>"
			Add-Content $fileName "<td style='text-align:center'>$servername</td>"
			Add-Content $fileName "<td style='text-align:center'>$name</td>"
			Add-Content $fileName "<td style='text-align:center'>$Status</td>"
			Add-Content $fileName "</tr>"
		}
		
	}
	
	writeHtmlHeader $ServiceFileName
	Add-Content $ServiceFileName "<table width='100%'><tbody>"
	Add-Content $ServiceFileName "<tr bgcolor='#CCCCCC'>"
	Add-Content $ServiceFileName "<td width='100%' align='center' colSpan=3><font face='tahoma' color='#003399' size='2'><strong>Service Details</strong></font></td>"
	Add-Content $ServiceFileName "</tr>"
	
	writeTableHeader $ServiceFileName
	
	#Change value of the following parameter as needed 
	
	$InlcudeArray = @()
	
	#List of programs to exclude 
	#$InlcudeArray = $inlcudeService 
	
	Foreach ($ServerName in (Get-Content $script:list))
	{
		if (Test-Connection -ComputerName $ServerName -Count 1 -ea 0)
		{
			$service = Get-Service -ComputerName $servername
			if ($Service -ne $NULL)
			{
				foreach ($item in $service)
				{
					#$item.DisplayName 
					Foreach ($include in $includeService)
					{
						write-host $inlcude
						if (($item.serviceName).Contains($include) -eq $TRUE)
						{
							Write-Host  $item.MachineName $item.name $item.Status
							writeDiskInfo $ServiceFileName $item.MachineName $item.name $item.Status
						}
					}
				}
			}
		}
	}
	
	Add-Content $ServiceFileName "</table>"
	
	writeHtmlFooter $ServiceFileName
	
	function Validate-IsEmail ([string]$Email)
	{
		
		return $Email -match "^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$"
	}
	
	Function sendEmail
	{
		param ($from,
			$to,
			$subject,
			$smtphost,
			$htmlFileName)
		[string]$receipients = "$to"
		$body = Get-Content $htmlFileName
		$body = New-Object System.Net.Mail.MailMessage $from, $receipients, $subject, $body
		$body.isBodyhtml = $true
		$smtpServer = $MailServer
		$smtp = new-object Net.Mail.SmtpClient($smtphost)
		$validfrom = Validate-IsEmail $from
		if ($validfrom -eq $TRUE)
		{
			$validTo = Validate-IsEmail $to
			if ($validTo -eq $TRUE)
			{
				$smtp.Send($body)
				write-output "Email Sent!!"	
			}
		}
		else
		{
			write-output "Invalid entries. Try again."
		}
	}
	$date = (get-date).ToString('yyyy/MM/dd')
	If ($From -and $To -and $SMTPMail)
	{
		sendEmail -from $From -to $To -subject "Service Status - $Date" -smtphost $SMTPMail -htmlfilename $ServiceFilename
	}
}

##### Example ########
Get-ServiceStatusReport -ComputerList pc.txt -includeService DoSvc,UsoSvc

Scheduling the Powershell code

To automate this kind of monitoring even more, we can use the Microsoft Windows Task Scheduler service to automatically run a PowerShell script, at specific time intervals, such as Get-ServiceStatus function seen above, when specific conditions are met.

The following quick example will create a new task called CheckServ. Let's run the following command in a command prompt (with administrative privileges):

C:\Windows\System32\schtasks.exe /create /TN CheckServ /ST 07:00 /SC DAILY /RI 10 /TR "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile C:\Scripts\Get-ServiceStatus.ps1"

This newly created Windows Task Schedule will run the Get-ServiceStatus function daily starting at 07:00 and every 10 minutes. This approach can be used for any other Powershell script also, obviously.

Summary
Article Name
Check Windows Services statuses using Powershell
Description
Here there are several approches to check services (services.msc) status on Windows systems using Powershell.
Author
Publisher Name
Heelpbook.net

1 thought on “Check Windows Services statuses using Powershell”

Comments are closed.