Check Domain Controller Services with PowerShell

Regular readers of my articles know that I am a big proponent of managing at scale. Instead of taking the approach to execute tasks individually, management at scale means that we’re looking for a way to execute multiple tasks with a single command. Fortunately, PowerShell makes this an easy proposition, once you get your head around the concept.

In this article, I want to demonstrate this concept by checking the status of critical services on my domain controllers. This is a task that you most likely perform already. Instead of navigating through cumbersome GUI-based tools or remote desktop sessions, you can use PowerShell to easily manage the task at scale.
Let’s start with a variable of domain controller names.

 $dcs = "chi-dc01","chi-dc02","chi-dc04"

I’m manually entering the names, but you could just as easily read in the contents of a text file, import a CSV, or even query Active Directory if you have the AD module installed.

 $dcs = (Get-ADDomain).ReplicaDirectoryServers

Using PowerShell’s Get-Service Cmdlet

In my domain, all the domain controllers are also DNS servers. Because I plan on using Get-Service, and the cmdlet allows me to query for multiple services, I’ll create a variable with the service names I want to check.

 $svcs = "adws","dns","kdc","netlogon"

At this point, I can let PowerShell do its thing and look at all of these services on the collection of servers.

 Get-Service -name $svcs -ComputerName $dcs

Getting status of multiple services from multiple computers (Image Credit: Jeff Hicks)
Getting status of multiple services from multiple computers (Image Credit: Jeff Hicks)

Well it worked, but the output leaves something to be desired. At a glance, I can’t tell which service goes with which domain controller. This is where you have to look at the resultant objects and see if there’s a property you can use for the computer name. I can do a simple test with a single service and Get-Member.
Getting service properties with Get-Member (Image Credit: Jeff Hicks)
Getting service properties with Get-Member (Image Credit: Jeff Hicks)

I’m betting that Machinename is a likely candidate. Let’s try it out.

 Get-Service -name $svcs -ComputerName $dcs | Select Machinename,Name,Status

Service statuses (Image Credit: Jeff Hicks)
Service statuses (Image Credit: Jeff Hicks)

Perhaps it’s not the prettiest output, but it gets the job done. I can tell PowerShell to display formatted results.

 Get-Service -name $svcs -ComputerName $dcs |
Select @{Name="Computername";Expression={$_.Machinename}},
DisplayName,Status | Format-Table -AutoSize

I’m using a custom hashtable with Select-Object to define a new property called Computername, which will have a value of the MachineName property for each object.

Formatted service status results (Image Credit: Jeff Hicks)
Formatted service status results (Image Credit: Jeff Hicks)

I’m working under the assumption that the same services are running on all the domain controllers. When managing at scale you almost have to assume that everything you are managing is the same type of object. Remember, we’re still dealing with objects in the pipeline and PowerShell works best when the objects are defined the same.
Once you have the core expression to get the data you need, you can have PowerShell format it any number of ways. For example, let’s say I want a formatted table organized by the computer name:

 Get-Service -name $svcs -ComputerName $dcs | Sort Machinename |
Format-Table -group @{Name="Computername";Expression={$_.Machinename.toUpper()}} -Property Name,Displayname,Status

Results organized by domain controller (Image Credit: Jeff Hicks)
Results organized by domain controller (Image Credit: Jeff Hicks)


When you are doing grouping like this with Format-Table, it is strongly recommended to sort first on the same property.
You might want to see the results per service:

 Get-Service -name $svcs -ComputerName $dcs | Sort Displayname |
Format-Table -group @{Name="Service";Expression={"$($_.Displayname) [$($_.name)]"}} -Property @{Name="Computername";Expression={$_.Machinename.toUpper()}},Status -AutoSize

Formatted results by service (Image Credit: Jeff Hicks)
Formatted results by service (Image Credit: Jeff Hicks)

Another approach is to use WMI either through Get-WmiObject or Get-CimInstance.

Using WMI

The tricky part of WMI is building a filter that only returns the services we’re interested in. The WMI filter uses the legacy operators, not PowerShell operators. In my example, I need to construct a WMI filter like this.

 $filter = "Name = 'ADS' OR Name = 'DNS' OR Name = 'KDC' OR Name = 'NetLogon'"

Nothing is case sensitive, but you do need to quote the service names. I can use the filter like this:

 Get-WmiObject -Class Win32_service -filter $filter -ComputerName $dcs |
Select PSComputername,Name,Displayname,State,StartMode | format-table -autosize

I’ve already done the step of running a similar WMI command through Get-Member to discover the property names. WMI even offers some additional information that I can’t get with Get-Service.

Service status via WMI (Image Credit: Jeff Hicks)
Service status via WMI (Image Credit: Jeff Hicks)

Filtered Results

Now, perhaps what you are really interested in are services that aren’t running. With WMI, this is pretty easy to do. Here’s a revised filter.

 $filter = "(Name = 'ADS' OR Name = 'DNS' OR Name = 'KDC' OR Name = 'NetLogon') AND State<>'Running'"

Notice the use of parentheses because I want services with any of those names AND the state not equal to running. All I have to do is re-run the Get-WmiObject command.

Filtered WMI results (Image Credit: Jeff Hicks)
Filtered WMI results (Image Credit: Jeff Hicks)

The advantage with this approach is that filtering is done at the remote server. If nothing meets my query, then nothing comes back across the network. I can also filter with Get-Service:

 Get-Service -name $svcs -ComputerName $dcs | where {$_.Status -ne "running"} |
Select Machinename,Name,Displayname,Status | format-table -AutoSize

Filtered results with Where-Object (Image Credit: Jeff Hicks)
Filtered results with Where-Object (Image Credit: Jeff Hicks)

The downside to this approach is that Get-Service has to bring all the matching services to my machine, and then I filter for those that are not running. I’ll admit that from a practical perspective, given the number of servers and services the performance difference is minor, but you really should be in the habit of filtering as early in your expression as you can.

I hope you’ve seen how easy it is to manage at scale with PowerShell. Working with objects in the pipeline should be your goal. But of course, there are always exceptions, and I have something up my sleeve for next time.