More Improvements to my Test-WSMan Replacement

Recently I shared a replacement function I wrote for Test-WSMan. That version addressed some of the shortcomings in the original command, at least for me. After using it for a bit I realized I wanted a few additional changes so I now have version 2. The new version now supports multiple computer names. I also replaced the ProductVersion property with separate properties for the OS, Service Pack and Stack numbers. Continue reading

Resolving SIDs with WMI, WSMAN and PowerShell

In the world of Windows, an account SID can be a very enigmatic thing. Who is S-1-5-21-2250542124-3280448597-2353175939-1019? Fortunately, many applications, such as the event log viewer resolve the SID to an account name. The downside, is that when you are accessing that same type of information from PowerShell, you end up with the “raw’ SID. And while there are a variety of command line tools, and probably even some cool .NET trick someone will share after I post this, you most likely want to find a PowerShell solution.

Your initial assumption might be to use WMI. Searching Root\CIMv2 you’ll even find a Win32_SID class. Woohoo! This is all I need to do:

Well, no. As you can see in the figure, you can’t query this particular class.


Instead, you need to directly access the instance of the Win32_SID class. In PowerShell, the easy way is to use the [WMI] type accelerator, and specify the path to the instance.


If you wanted to query the SID on a remote computer, the path would be \\SERVERNAME\root\cimv2:CLASSNAME.Keyproperty=’Something’. But be aware that there is no way to specify alternate credentials using [WMI]. Although, you could query the Win32_Account class for the SID.

This gives you the benefit of using a cmdlet, querying a remote computer and using alternate credentials.

In PowerShell 3.0 if you want to use the new CIM cmdlets and query WMI over WSMan, it is pretty easy to turn the previous command into a CIM command.

These queries are pretty good, but I believe that if you can go straight to the instance, so much the better. Unfortunately, I can’t find any CIM related accelerator that would give me the same result as using the [WMI] accelerator. Remember, my goal is to leverage the new WSMan protocol. The solution is to use the Get-WSManInstance cmdlet.

I think you can tell that the ResourceUri is the path to the class and the SelectorSet is a hashtable with key property, in this case SID, and the corresponding value. The result looks a little different, but the critical parts, like the account name are there.

Get-WSManInstance also supports alternate credentials. So given all of this, I put together a function called Resolve-SID that uses this approach. But as a fallback, you can also tell it to use WMI.

I think between the comment based help, internal comments and verbose messages you should be able to understand how the function works. So now you have a variety of techniques for resolving SIDs. Querying locally, using [WMI] or querying the Win32_Account class for the SID should be sufficient performance-wise. But remotely, using [WMI] or Get-WSManInstance is significantly faster than querying and filtering. Using Get-WMIboject or Get-CIMInstance took between 600-750ms, where as the [WMI]approach took about 200MS and using Get-WSManInstance took 150MS.

I hope you are resolved to not let SIDS stand in your way any longer.

Get CIMInstance from PowerShell 2.0

I love the new CIM cmdlets in PowerShell 3.0. Querying WMI is a little faster because the CIM cmdlets query WMI using the WSMAN protocol instead of DCOM. The catch is that remote computers must be running PowerShell 3 which includes the latest version of the WSMAN protocol and the WinRM service. But if your computers are running 3.0 then you can simply run a command like this:

However, if one of the computers is running PowerShell 2.0, you’ll get an error.


In this example, CHI-DC02 is not running PowerShell 3.0. The solution is to create a CIMSession using a CIMSessionOption for DCOM.


So there is a workaround, but you have to know ahead of time which computers are not running PowerShell 3.0. When you use Get-CimInstance and specify a computername, the cmdlet setups up a temporary CIMSession. So why not create the temporary CIMSession with the DCOM option if it is needed? So I wrote a “wrapper” function called Get-MyCimInstance to do just that.

The heart of the function is a nested function to test if a remote computer is running WSMAN 3.0.

The function uses Test-WSMan and a regular expression to get the remoting version. If it is 3.0 the function returns True. In Get-MyCIMInstance I test each computer and if not running 3.0, create the CIMSession option and include it when creating the temporary CIMSession.

I’m using a Try/Catch block because if the computer is offline, my test function will throw an exception which I can catch.

Otherwise, all is good and  I can pass the rest of the parameters to Get-CimInstance.

At the end of the process, I remove the temporary CIMSession. With this, now I can query both v2 and v3 computers.
Notice for CHI-DC02 I’m creating the DCOM option. Here’s the command without all the verboseness.
I could have created a proxy function for Get-CimInstance, but not only are they more complicated, I didn’t want that much transparency. I wanted to know that I’m querying using my function and not Get-CimInstance. Here’s the complete script.

I hope you’ll let me know what you think and if you find this useful.

UPDATE: I’ve revised this script and article since it’s original posting to better handle errors if you can’t test WSMAN. I also added support for alternate credentials, which is something you can’t do with Get-CimInstance.

NOTE: I should also point out that there is an apparent bug with Get-CimInstance. If you run the command for all instances of a given class, like win32_share and the remote computer is running PowerShell v2 you will get the error I’ve written about. But, if you use a query or a filter, it will work. So while this will fail if the computer is running v2, get-ciminstance win32_share -computername $c, these will work:

Get-CimInstance -query “Select * from win32_share” -computername $c
Get-CimInstance -win32_share -filter “Name=’C$'” -computername $c

It is an odd behavior, but it can work in your favor depending on how your structure your command. What I haven’t verified yet is what protocol PowerShell is using in these situations when the remote computer is running v2. Of course, the best, long term solution is to get all of your managed systems to at least PowerShell 3.0.

WinRM: Domain or Workgroup?

I’m curious about something and would like to hear from you. PowerShell v2 remoting uses WinRM which in a domain environment is very secure and easy to use. You can even use a GPO to configure your domain members. However you can also use WinRM in a workgroup environment but you have few hoops to jump through. My question is how many of you need remoting in a non-domain environment? What sort of scenarios do you have to support? I hope you’ll let me know.