Abstract

A common task of any administrator is to manage and maintain the application availability by checking the various services status, accomplish configuring the services and restarting the service on a local/remote system. There are several components are available to accomplish this day to day tasks.This can be done using WMI (Win32_Services/Get-CIMinstance(PowerShell 3.0 onwards)) and use Get-Service along with Stop/Start/Restart-Service cmdlets.There are many instances where we opt for one over the other available GUI tools or commands.Let’s consider a requirement to check only those services where StartMode set to Auto or services that are stopped or services that are disabled. In this case, the Get-Service cmdlet which does not bind any such information hence querying Win32_Service or Get-CIMInstance are appropriate and serves the purpose. But fortunately, we have Windows Management Instrumentation (WMI). This class has several properties such as StartMode, State, start name etc:-
Introduction
This article talk about how to services are administrated using available components in our day to day activities.  This also includes how to monitor service(s) on local/remote systems over a group of servers using credentials and without using credentials.This script will allow you to read a list of servers from the input file and use credentials to connect remote/DMZ servers to pull service status information for a set of specific services. The various output forms are included with this article are excel, CSV, JSON and PowerShell console output.
First, we have to collect all services available on the computer. You can use three methods for this purpose:
  • Get-WMIObject
  • Get-CimInstance:(Supported in PowerShell 3.0 onwards)
  • Get-Service

Querying WMI

WMI is the Microsoft implementation of Web-Based Enterprise Management (WBEM), with some enhancements in the initial version of it, WBEM is an  industry initiative to develop a standard technology for accessing management information in an enterprise environment that covers not only Windows but also many other types of devices like routers, switches, storage arrays …etc. WMI uses the Common Information Model (CIM) industry standard to represent systems, applications, networks, devices, and other managed components. CIM is developed and maintained by the Distributed Management Task Force (DMTF).
All of that sounds pretty but when Microsoft developed the first versions of WMI they use DCOM (Distributed Component Object Model) wish if a proprietary  Microsoft Technology, so the standards and cross compatibility just took a back seat at the time, on more recent versions of the operating system with Windows Management Framework 2.0 and above MS started to include more and more of the standards and shifted to using WS-Management SOAP-based protocol thru their WinRM (Windows Remote Management) protocol.
We can look at WMI as a collection of objects that provide access to different parts of the operating system, just like with PowerShell objects we have properties, methods, and events for each. Each of these objects is defined by what is called MOF  (Manage Object Format) files that are saved in %windir%\System32\wbem with the extension of .mof. The MOF files get loaded by what is called a Provider when the Provider is registered he loads the definitions of the objects into the current WMI Namespace. The Namespace can be seen a file system structure that organizes the objects on function, inside of each namespace the objects are just like in PowerShell in what is called Class Instances and each of this is populated with the OS and Application information as the system runs so we always have the latest information in this classes.
Namespaces are organized in a hierarchical way where \root is the top level for all other namespaces. The default namespace where most of the other namespaces and classes are located is root\CIMv2 on Windows Kernel 6.x on Kernel 5.x it is Default\CIMv2. Some are installed by default and others are only available when specific applications are installed.
In summary, each Namespace contains Classes, these have:
Methods Actions that can be taken.
  • Properties Information that can be retrieved.
  • Instances of the class objects (services, Processes, Disks) each instance with Methods and Properties.
  • Events are actions that WMI can monitor for and take action when they happen.
  • Caveats of WMI
Now WMI is great, do not get me wrong, but sadly it does have some caveats the main ones being:
Not all classes are available on all versions of Windows. Check
Some applications even from MS have Providers in one version and not in another (Office) and in some cases they even change the properties and methods.
In other words, if you plan on running WMI queries against a series of hosts that may be of different versions of Windows or a specific application do make sure you test and validate your results. This goes the same for Architecture if you are testing x64 or x86.
Display all service names matching a string pattern.  The below example lists all the services starts with character “A”
get-service -ComputerName hqdbsp18|  Where-Object {$_.Name -like 'A*'} | select -expand name 
get-service -ComputerName hqdbsp18|  Where-Object {$_.Name -match '^M' -or $_.Name -match '^SQ' } | select -expand name
[] – for range matching. For example, Name LIKE ‘[M-S]%’ will list all services starting with any letter from a to f.
Get-WMIObject Win32_Service -Filter "Name LIKE '[M-S]%'" -ComputerName hqdbsp18| Select *|format-table -AutoSize
^ – not. For example, Name LIKE ‘[^M-S]%’ will list services that do not start with any letter from a to f.
Get-WMIObject Win32_Service -Filter "Name LIKE '[^M-S]%'" -ComputerName hqdbsp18| Select *|format-table -AutoSize
_ – matches one letter. For example, Name LIKE ‘_QL%’ will list services that start with S and followed by any letter.
Get-WMIObject Win32_Service -Filter "Name LIKE '_Q_S%'" -ComputerName hqdbsp18| Select *|format-table -AutoSize
Group the services based on its startup service account
Get-wmiobject win32_service -ComputerName HQDBSP18 | group startname |select * |Format-Table -AutoSize

Querying Get-CimInstance

PowerShell 3.0 shipping with Windows server 2012 and Windows 8 brings a new set of Cmdlets to manage any server or device that complies with CIM and WS-Man standards defined by DMTF. In this blog post we will explore these new Cmdlets and how can they help IT Pros in managing a data center.The WMI is derived from CIM and it provides and query interface called WMI Query Language (WQL) for accessing CIM object data.

The Get-CimInstance cmdlet available in PowerShell V3 can be used to retrieve WMI information from a remote computer using the WSMAN protocol instead of the legacy WMI service that uses DCOM and RPC. However, the remote computers must be running PowerShell 3 and WSMAN protocol version 3. When querying a remote computer,  Get-CIMInstance setups a temporary CIMSession. However, if the remote computer is running PowerShell 2.0 this will fail. You have to manually create a CIMSession with a CIMSessionOption to use the DCOM protocol. This Script does it for you and creates a CimSession depending on the remote Computer capabilities.

Get-cimInstance win32_service -computer hqdbsp18 -filter "startname like '%localsystem%' and name like '%App%'"| Select Name,startmode,state,startname,systemname |Format-Table -AutoSize
Get-wmiobject win32_service -computer hqdbsp18 -filter "startname like '%localsystem%' and name like '%App%'"| Select Name,startmode,state,startname,systemname |Format-Table -AutoSize

Get-Service

The Get-Service cmdlet retrieves information about all services running on the local/remote system. These cmdlets are.NET objects (of the type System.ServiceProcess.ServiceController) and Its to apply advanced filters and operations to administrate the services
First, Let’s list the available cmdlet to manage the services
Get-Command | findstr Service

Querying Get-Service

The Get-Service cmdlet retrieves information about all services running on the local/remote system. These cmdlets are .NET objects (of the type System.ServiceProcess.ServiceController) and Its to apply advanced filters and operations to administrate the services
The Get-Service cmdlet doesn’t support for supplying credentials, this is one of the main limitation of Get-Service cmdlet when it comes for non-domain or cross-domain scenarios.The workaround for the problem is to make use of Invoke-Command

Credentials

Most of the time it’s not good practice to hardcode the credentials. In that case, you might need to encrypt the password and use the secured code in the script. You need to run the below Powershell script to pull the encrypted password to c:\SecurePassword.txt and copy the code in the script.
$password = read-host -prompt "Enter your Password"
$secure = ConvertTo-SecureString $password -force -asPlainText 
ConvertFrom-SecureString $secure |Out-File c:\SecurePassword.txt
In the below example, Test@2013##) password is encrypted and its content is shown below
There are many instances where it’s ok to store the password in the script itself. In this case, the encrypted password is used in the script which serves the purpose.
The Get-Service and Get-CIMinstance cmdlet doesn’t accept the credential parameter. The workaround for the problem is to use the invoke-command cmdlet to create a session on the remote server.
Invoke-Command { Get-Service "*SQL*" } -ComputerName HQDBSP18 -Credential $Credentials |select Name,displayname,Status |Format-Table -AutoSize
This is the advantage of using WMI object where it accepts the credential parameter.
# Hard code the the Credentials details
$User = "CDW\DDOV810"
$Pass = ConvertTo-SecureString "thanVitha@2016" -AsPlainText -Force
#contain the username and password in a variable
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
Get-WMIObject Win32_Service -computer hqdbsp18 -credential $Credentials |where-object {$_.name -like "*SQL*"} |select Name,startmode,state,startname,systemname |Format-Table -AutoSize

The below screen shot gives more insight on the credentials parameter

The CIM Cmdlets do not have a -Credential parameter. The only way to specify alternate credentials is to manually build a new CIM session object, and pass that into the -CimSession parameter on the other cmdlets. The details are given below

$User = "hadt\sdsdfs"

$Pass = ConvertTo-SecureString "sdfsdf@2016" -AsPlainText -Force
#contain the username and password in a variable
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User,$Pass
$CimSession = New-CimSession -ComputerName abcd -Credential $Credentials
$service = Get-CimInstance -ClassName Win32_service -CimSession $CimSession
$service
Remove-CimSession -CimSession $CimSession


Return to Top


Simple way to get the services Details in a CSV file

The simplest and quickest way to retrieve the services details is by exporting the data to CSV.The two Windows PowerShell cmdlets that work with comma-separated values are ConvertTo-CSV and Export-CSV. The two cmdlets are basically the same; the difference is that Export-CSV will save to a text file, and ConvertTo-CSV does not.
# The output CSV file
 $CSVOutputfile="c:\Services.csv"
#Input file server details location
$input ="c:\server.txt"
# query win32_service class
Get-WmiObject Win32_Service -ComputerName (Get-Content $input )|Select-Object -Property __Server,Name,startmode,state,serviceaccount,displayname |Export-Csv -Path $CSVOutputfile
#The Invoke-Item cmdlet provides a way to open a file  from within Windows PowerShell.
invoke-item $CSVOutputfile

Service details in Excel

PowerShell is made available to use Excel component by invoking excel.application COM object that will allow us to work with excel to add data and format that data.  The New-object -ComObject  creates a new excel object using COM components and it made visible for troubleshooting using visible property set to true.  Once everything is defined, we can call the respective methods and properties to create workbook by adding sheet as its item

#Create a new Excel object using COM
$Excel = New-Object -ComObject Excel.Application
#you can see the Excel sheet and helpful in troubleshooting
$Excel.visible = $True
#After instantiating the excel objects, It's a time use its respective methods and properties
$Excel = $Excel.Workbooks.Add()
$Sheet = $Excel.Worksheets.Item(1)

Workbook number and details

FileFormat numbers in Mac Excel. These are the main file formats in Windows Excel 2007-2016:

51 = xlOpenXMLWorkbook (without macro’s in 2007-2013, xlsx)
52 = xlOpenXMLWorkbookMacroEnabled (with or without macro’s in 2007-2013, xlsm)
50 = xlExcel12 (Excel Binary Workbook in 2007-2013 with or without macro’s, xlsb)
56 = xlExcel8 (97-2003 format in Excel 2007-2013, xls)
$xlOpenXMLWorkbook=[int]51

<#  
.SYNOPSIS     
    Name :  Disk Space Utilization excel Report (Get-ServiceExcelReports.ps1)
    Description : Get disk space usage informations from remote server(s) with WMI and output CSV file
    
    Author : Prashanth Jayaram
       
    * Select list of servers from a text file
    * Get remote Servers informations with WMI and Powershell
    * service (Servername,Name,startmode,state,serviceaccount,displayname + display a Excel output)
      
       
.INPUT
    Input Server text file
    Service list
   
.OUTPUTS
    Excel output
   
.NOTES
    Version:        1.0
    Author:         Prashanth Jayaram
    Creation Date:  2017-02-02
    Purpose/Change: Initial script development
     
.EXAMPLE
    .\Get-ServiceExcelReports.ps1 -ServerList C:\server.txt -includeService "VM","Dhcp","SQL"
#>
  
  
#########################################################################################
  
 
  
param (
    [Parameter(Mandatory=$true)][string]$ServerList,
    [Parameter(Mandatory=$true)][string[]]$includeService
 )
  
 
$excel = New-Object -ComObject Excel.Application
 
$workbook = $excel.Workbooks.Add()
$worksheet = $workbook.Worksheets.Item(1)
 
$worksheet.Cells.Item(1,1) = "Server Name"
$worksheet.Cells.Item(1,2) = "Service Name"
$worksheet.Cells.Item(1,3) = "State"
$worksheet.Cells.Item(1,4) = "StartUp Type"
$worksheet.Cells.Item(1,5) = "Service Account"
$worksheet.Cells.Item(1,6) = "DisplayName"
 
  
$range = $worksheet.UsedRange
$range.Interior.ColorIndex = 19
$range.Font.ColorIndex = 11
$range.Font.Bold = $true
  
$row = 2
  
$IncludeArray=@()
  
#List of programs to exclude
#$IncludeArray = $includeService
  
Foreach($ServerName in (Get-Content $ServerList))
{
$service = Get-WmiObject Win32_Service -ComputerName $servername
if ($Service -ne $NULL)
{
foreach ($item in $service)
 {
 #$item.DisplayName
 Foreach($include in $includeService) 
     {                       
 #write-host $include                                    
 if(($item.name).Contains($include) -eq $TRUE)
    {
        $worksheet.Cells.Item($row, 1) = $servername
        $worksheet.Cells.Item($row, 2) = $item.name
        $worksheet.Cells.Item($row, 3) = $item.Status
        $worksheet.Cells.Item($row, 4) = $item.startmode
        $worksheet.Cells.Item($row, 5) = $item.startname
        $worksheet.Cells.Item($row, 6) = $item.displayname          
        $row++
        
     }
    }
 }
}
}
   
$range.EntireColumn.AutoFit()
$excel.Visible = $True

Excel Output

Return to Top


Service Details in CSV file

The main part of the code takes input details from a text file and output columns are ordered and customized as per the requirement. The five column output are listed in the csv output file and they are Servername, Name,start mode, state, serviceaccount and displayname. The three input parameters input text file, service list used to compare against the listed services and csv output file used to capture all five column outputs.
<#
 
.SYNOPSIS      
    Name :  Disk Space Utilization csv Report (Get-ServiceExcelReports.ps1)
    Description : Get disk space usage informations from remote server(s) with WMI and output CSV file
   
    Author : Prashanth Jayaram
      
    * Select list of servers from a text file
    * Get remote Servers informations with WMI and Powershell
    * service (Servername,Name,startmode,state,serviceaccount,displayname + display a csv output)
     
      
.INPUT
    Input Server text file
    Service list
  
.OUTPUTS
    CSV output, console and Grid output
  
.NOTES
    Version:        1.0
    Author:         Prashanth Jayaram
    Creation Date:  2017-02-02
    Purpose/Change: Initial script development
    
.EXAMPLE
    .\Get-Servicecsv.ps1 -ServerList C:\server.txt -includeService "VM","Dhcp","SQL"
#>
 
 
#########################################################################################
 
 
param (
    [Parameter(Mandatory=$true)][string]$ServerList,
    [Parameter(Mandatory=$true)][string[]]$includeService,
    [Parameter(Mandatory=$true)][string]$CSVoutputFile
 )
 
# Check if the output file CSV exist, if exists then delete it.
 
if (test-path $CSVoutputFile ) { rm $CSVoutputFile } 
#Custom object to maintain the order of the output columns
$props=@()
Foreach($ServerName in (Get-Content $ServerList)) 
$service = Get-WmiObject Win32_Service -ComputerName $servername
if ($Service -ne $NULL) 
  
foreach ($item in $service) 
    
 #$item.DisplayName 
 Foreach($include in $includeService)  
         {                        
         #write-host $include                                     
         if(($item.name).Contains($include) -eq $TRUE) 
                {
    
                  $props += [pscustomobject]@{
                  Servername = $servername
                  name =  $item.name
                  Status = $item.Status
                  startmode = $item.startmode
                  state = $item.state
                  serviceaccount=$item.startname
                  DisplayName =$item.displayname}
                
         
     
  
$props | Format-Table Servername,Name,startmode,state,serviceaccount,displayname  -AutoSize
$props | Select-Object Servername,Name,startmode,state,serviceaccount,displayname  |Export-Csv -Path $CSVoutputFile
Invoke-item $CSVoutputFile

Service Details in HTML file

The below section outlines the use of the convert-to-HTML cmdlet.without digging much into the detail, the <table> element, the <th> (table heading) element, and <td> (table cell) element. These styles enable us to put a nice border around our table and around each of the cells in that table: The See Also section has several in-depth information about formatting.
<#
 
.SYNOPSIS      
    Name :  Disk Space Utilization excel Report (Get-ServiceHTML.ps1)
    Description : Get disk space usage informations from remote server(s) with WMI and output HTML file
   
    Author : Prashanth Jayaram
      
    * Select list of servers from a text file
    * Get remote Servers informations with WMI and Powershell
    * Disk (Disk type, letter, capacity in GB, free space in GB, % free , Status + display a HTML output)
     
      
.INPUT
    Input Server text file
    Service list
    Output HTML file
  
.OUTPUTS
    HTML output
    Console Output
  
.NOTES
    Version:        1.0
    Author:         Prashanth Jayaram
    Creation Date:  2017-02-02
    Purpose/Change: Initial script development
    
.EXAMPLE
   
   Get-ServiceHTMLReport.ps1 -ServerList "\\hq6021\c$\server.txt" -includeService "VM","Dhcp","SQL" -OutputHTML "e:\CU2\ServericeReport.htm"
#>
 
 
#########################################################################################
param (
    [Parameter(Mandatory=$true)][string]$ServerList,
    [Parameter(Mandatory=$true)][String[]]$includeService,
    [Parameter(Mandatory=$true)][string]$OutputHTML
 )
<#
[String]$ServerList="\\hq6021\c$\server.txt"
[String[]]$includeService= "VM","Dhcp","SQL"
#>
$props=@()
 
 
Foreach($ServerName in (Get-Content $ServerList)) 
$service = Get-WmiObject Win32_Service -ComputerName $servername
if ($Service -ne $NULL) 
  
foreach ($item in $service) 
    
 #$item.DisplayName 
 Foreach($include in $includeService)  
         {                        
         #write-host $include                                     
         if(($item.name).Contains($include) -eq $TRUE) 
                {
    
                  $props += [pscustomobject]@{
                  Servername = $servername
                  name =  $item.name
                  Status = $item.Status
                  startmode = $item.startmode
                  state = $item.state
                  serviceaccount=$item.startname
                  DisplayName =$item.displayname}
                
         
     
  
$props |format-table Servername,Name,startmode,state,serviceaccount,displayname  -autosize
$a = "<style>"
$a = $a + "BODY{background-color:peachpuff;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;}"
$a = $a + "</style>"
$props |Select-Object Servername,Name,startmode,state,serviceaccount,displayname| ConvertTo-HTML -head $a |  Out-File $OutputHTML
invoke-item $OutputHTML

HTML Output

Conclusion

There are plenty of tools that are available to find the windows service. The article illustrated how to access and query the Windows Service on a local/remote machine using available tools and technique of PowerShell i.e. is WMI, CIM and Get-Service cmdlet also explains the various ways to identify the service status.  The service(s) detail output is reported using CSV, Console, HTML and Excel. The references links also state the difference protocol usage and the use of CIM are have better control over the WIM class libraries in terms of design and performance.  Even though windows remoting is disabled still able to use the CIM cmdlets to query the remote computer.The CIM can also be used to access non-windows systems.

References