Contact

Technology

Mar 03, 2014

Using WMI to Work Smarter Not Harder

Bobby Crotty

Bobby Crotty

Default image background

Have you ever spent time logging into lots of computers to perform the same repetitive task over and over? There’s a better way—work smarter not harder! The invoke-command cmdlet will allow you to run any PowerShell command remotely across many systems. Jeffrey Hicks has a great guide for doing this, but this solution requires that remote PowerShell be enabled, which is not always true, as was the case with a client recently.

I needed another approach. Jason Morgan has a set of functions for remotely enabling remote PowerShell using Windows Management Instrumentation (WMI), but I decided against doing so in order to keep the environment more secure. However, WMI proved to be the key to solving my problem.

The PowerShell cmdlet Get-WmiObject (alias gwmi) can work on systems that do not have remote PowerShell enabled (although some environments do have WMI disabled). Below, I use WMI to get the membership of the local administrators group, but it can be used to get almost anything such as system serial numbers and BIOS information.

FIRST ATTEMPT

My first stab at getting the local administrators group membership across the domain looked like this:

Get-ADComputer -Filter {OperatingSystem -like "Windows Server *"} | %{ gwmi win32_groupuser -ComputerName $_.Name | Where {$_.GroupComponent -match 'n="Administrators"'} | Select ` @{n="Server"; e={$_.__Server}}, @{n="Type"; e={if($_.PartComponent -match "Win32_Group") {"Group"} else {"User"}}}, @{n="Identity"; e={$_.PartComponent.Substring( $_.PartComponent.LastIndexOf('n="')+6).TrimEnd('"')}}}

FILTERING OPTIONS

I was only interested in servers, so I filtered based on the OperatingSystem property. Unfortunately, not every system had the OperatingSystem property populated. An alternate method is to search in a particular OU. Replace the green text with your own value.

Get-ADComputer –Filter * -SearchBase "OU=Servers,DC=corp,DC=com"

By default, this searches everything under the OU. If you want to exclude subfolders, add -SearchScope OneLevel to the command.

In looking for the servers that did not have an operating system listed, I learned that the Get-ADComputer filter does not support comparing to the $null variable. If you want to filter for null values, use the following command:

Get-ADComputer –Filter * -Properties OperatingSystem | ?{$_.OperatingSystem –eq $null}

ADDED RESILIENCY

While the script worked on many systems, it failed when the system could not be reached and also when the system returned an exception. After adding error checking, my final script including the export is:

Get-ADComputer -Filter * -SearchBase "OU=Servers,DC=corp,DC=com" | %{     $server = $_.Name     If (Test-Connection $_.Name -Count 1 -Quiet) {         try {             gwmi win32_groupuser -ErrorAction Stop -ComputerName $_.Name |             ?{$_.GroupComponent -match 'n="Administrators"'} |             Select `                 @{n="Server"; e={$_.__SERVER}},                 @{n="Type"; e={if($_.PartComponent -match "Win32_Group") {"Group"} else {"User"}}},                 @{n="Identity"; e={$_.PartComponent.Substring(                     $_.PartComponent.LastIndexOf('n="')+6).TrimEnd('"')}},                 @{n="Notes"; e={}}         } catch { $_ | Select `             @{n="Server"; e={$server}},             @{n="Type"; e={}},             @{n="Identity"; e={}},             @{n="Notes"; e={$error[0].Exception}}         }     } else { $_ | Select `         @{n="Server"; e={$_.Name}},         @{n="Type"; e={}},         @{n="Identity"; e={}},         @{n="Notes"; e={"Failed to connect"}}     } } | Sort Server,Identity | Export-Csv "<path>\Local Administrators.csv" -NoTypeInformation

FINAL THOUGHTS

A few more small things I learned in finishing this script:

  • If you are using Select across multiple cases, it will output only the attributes from the first Select used, so best practice is to select the same attributes even if they are blank.

  • You can use

     

    @{n=“

    <Name>

    ”; e={

    <Expression>

    }}

     

    to rename a property, which allows you to put values with different property names into the same property.

  • Sometimes you cannot rely on the $_ variable to stay the same, such as in error handling. You can get around this by storing the required information to a temporary variable.

WMI can be used to gather and even change all sorts of information across a domain, and without having remote PowerShell enabled. If you’re working with a lot of systems across your environment or even if you just need to pull information from one system, try the command Get-WmiObject -List. It will return a list of all the WMI classes available, many of which are incredibly useful. I recently used an adapted version of the final script above to get a list of features installed on servers across the domain.

Are you struggling with a systems management solution and need additional information or real world expertise? Credera has extensive experience in designing, planning, and implementing systems management solutions. If you have questions about this blog post, points of view, or IT infrastructure, please use the comment section below or contact us on Twitter at @CrederaIT.

Conversation Icon

Contact Us

Ready to achieve your vision? We're here to help.

We'd love to start a conversation. Fill out the form and we'll connect you with the right person.

Searching for a new career?

View job openings