Monday, February 04, 2008

PowerShell's [WMI] Type Accelerator

In a recent blog post, I introduced PowerShell's WMI related type accelerators. In this post, I'll look at the [WMI] accelerator in more detail. As I explained earlier, the [WMI] type accelerator helps you to get directly to a particular WMI object. You provide a string containing the path to a particular WMI object and the [WMI]  adapter returns the WMI object (or not if it does not exist). This approach is a little easier than using Get-WMIObject in those cases when you actually know the details of which occurrence you want.

To illustrate this TA, let's look at a WMI Class, Win32_Share. We can find all the shares on a system like this:

PSH [D:\foo]: gwmi win32_share | ft -auto

Name   Path       Description
----   ----       -----------
E$     E:\        Default share
IPC$              Remote IPC
D$     D:\        Default share
ADMIN$ C:\WINDOWS Remote Admin
foo    d:\foo
C$     C:\        Default share

This is fine if you want to just see the shares.  But if you want to access a particular share's methods or properties you need to do a bit more  work. One simple way you can  get access to the Admin$ share is like this:

PSH [D:\foo]: $admin = gwmi win32_share | where {$_.name -eq "Admin$"}

This approach works, but it's a bit ugly and can take some time if there are a lot of shares on a system. And here's where the [WMI] TA works well as follows:

$admin2 = [wmi]"\\dc1\root\cimv2:win32_share.name='admin$'"

This is much easier to write, assuming you know how to construct the path string. A simple way to determine how to construct the path for this TA is to look at the __Path property on the actual object:

PSH [D:\foo]: $admin = gwmi win32_share | where {$_.name -eq "Admin$"}
PSH [D:\foo]: $admin.__Path
\\dc1\root\cimv2:Win32_Share.Name="ADMIN$"

To convert this path for use with [WMI], you need first to replace the double quotes to single quotes, then enclose the resulting string in double quotes prepended with [WMI].  One nice feature of this approach is that the returned object is an object, not a collection/array, which makes it easier to use.

When I was creating this blog post, I wondered if it was possible to create a WMI path using other properties. However this does not appear to work:

PSH [D:\foo]: $admin3 = [wmi]"\root\cimv2:win32_share.description='Remote Admin'"
Cannot convert value "\root\cimv2:win32_share.description='Remote Admin'" to type "System.Management.ManagementObject".
Error: "Invalid object path "
At line:1 char:11
+ $admin3 = [wmi] <<<< "\root\cimv2:win32_share.description='Remote Admin'"
PSH [D:\foo]: $admin3 = [wmi]"\root\cimv2:win32_share.path='c:\windows'"
Cannot convert value "\root\cimv2:win32_share.path='c:\windows'" to type "System.Management.ManagementObject". Error: "
Invalid object path "
At line:1 char:11
+ $admin3 = [wmi] <<<< "\root\cimv2:win32_share.path='c:\windows'"

There are two different formats you can se for the WMI path - with and without a machine name as follows:

$admin4 = [wmi]"\\dc1\root\cimv2:win32_share.name='admin$'"
$admin5 = [wmi]"root\cimv2:win32_share.name='admin$'"

The first format includes a machine name (\\dc1) while the second doesn't. The second format only works on the local machine whereas the first  can work across a network. There's only one small issue (feature?) of the first format which is that you can not provide credentials. Thus if you are logged onto your local machine with your normal userid/password, that set of credentials is used to access WMI. If those credentials do not allow you to access the remote server, then there's no way to provide credentials that would work.

I hope this is a clear explanation - let me know if  you'd like more details.

No comments: