Quantcast
Channel: Scripting Blog
Viewing all 275 articles
Browse latest View live

Use PowerShell and WMI to Find Wireless Keyboard & Mouse

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell and WMI to find a wireless keyboard or mouse attached to a system.

Microsoft Scripting Guy, Ed Wilson, is here. Yesterday, we had a great time at the Windows PowerShell user group meeting at the Microsoft Office in Munich (actually just outside of Munich). It was great to be back—as it had been five years since I was in the building. The Scripting Wife and I got to see a lot of our old friends.

Today, we are supposed to meet with Windows PowerShell Guru Oliver Lipkau. We'll see him in either Munich or in Regensburg—not sure which town yet. We are in our hotel room right now waiting for his email to detail the plans, and I am sipping an excellent cup of Earl Grey tea—Germany has awesome tea because so much comes through the port of Hamburg. It does not matter where we meet him because both towns are absolutely lovely.

Use WMI to detect wireless keyboard and mouse

One of the things I remember from when I was a consultant is that my customers wanted to be able to know who was using a wireless keyboard or a wireless mouse. This was for inventory purposes, audit purposes, or maybe general information. Anyway, at the time, it was not possible to obtain this information because the two WMI classes (Win32_Keyboard and Win32_PointingDevice) could not detect a wireless device back then. It only reported the “primary devices” physically connected to the computers. Bummer.

At some point, WMI started reporting wireless devices. I do not have the resources to test this out right now, so I cannot report when exactly WMI began reporting wireless keyboards and mice. However, I will use both Windows PowerShell 3.0 and Windows PowerShell 2.0 code so you can test this out for yourself. Remember we are in the middle of a three-week trip, and I did not even pack a “winter coat” let alone three different laptops running various versions of Windows. I do know it works on my Windows 8 laptop.

First, the wireless mouse

Ok, it is a mouse, right? Well, WMI calls it a "point device," and therefore, the WMI class name is Win32_PointingDevice. I can get an inventory of the attached mice by querying the class. This is shown here.

Get-WmiObject win32_PointingDevice

With Windows PowerShell 3.0, use the Get-CimInstance cmdlet, as shown here.

Get-CimInstance Win32_PointingDevice

The output displays a lot of stuff—some of which is not populated. Here is a screen shot of the query and some of the output.

Image of command output

A better output appears when I pipe the results to the HasWMIValue filter from my Scripting Guys WMI module. This filter displays only WMI properties from a class that has values. It makes a much cleaner output. This is shown in the following image.

Image of command output

Ok, I found what I was looking for—a caption that says HID-compliant mouse. I could have found this piece of information in Devices and Printers. In fact, I can even launch it through the Show-ControlPanelItem cmdlet as seen here.

Show-ControlPanelItem devices*

Here is an image of the property page for the mouse.

Image of property page for mouse

From a management perspective, the two most important properties are the description and the PNPDeviceID. I use the Get-WmiObject cmdlet to return both mice; then I use the Where-Object to filter out only the HID type; and, lastly, I send the information to a Format-Table command to produce a nice output, as shown here.

Windows PowerShell 2.0 syntax:

Get-WmiObject win32_PointingDevice | Where-Object { $_.Description -match 'hid'} | Format-Table description, pnpDeviceID -AutoSize -Wrap

Windows PowerShell 3.0 syntax:

Get-CimInstance win32_PointingDevice | Where Description -match 'hid' | Format-Table description, pnpDeviceID -AutoSize –Wrap

Here is the result of both commands.

Image of command output

Next, the wireless keyboard

Just like I can use WMI to find the HID wireless mouse, I can also use it to find the HID wireless keyboard. I use the WMI class Win32_Keyboard. Here is the result of piping the class to the HasWMIValue filter—this is everything WMI will tell me.

Image of command output

Once again, the two properties I am interested in are the PNPDeviceID and the description. Here are the commands used to produce my “report.”

Windows PowerShell 2.0 syntax:

Get-WmiObject win32_Keyboard | Where-Object { $_.Description -match 'hid'} | Format-Table description, pnpDeviceID -AutoSize -Wrap

Windows PowerShell 3.0 syntax:

Get-CimInstance win32_keyboard | Where Description -match 'hid' | Format-Table description, pnpDeviceID -AutoSize –Wrap

The results of running these two commands is shown here.

Image of command output

Dude! They are basically the same—combine ‘em

One of the nice things about WMI is that at times it is very consistent. As it turns out, this is one of those occasions. I am filtering by ‘hid’ and selecting the same two properties: description and pnpDeviceID. This way I can create an array of WMI classes and do both queries at the same time, as shown here, where gwmi is an alias for Get-WmiObject, % is an alias for foreach-object, ? is an alias for the Where-Object, and ft is an alias for Format-Table.

$class = "win32_pointingdevice","win32_keyboard"

$class | % {gwmi $_ | ? description -match 'hid'} | ft description, PNPDeviceID -A -Wr

Here is the output from the command.

Image of command output

Well, that is enough for this morning. We need to go hop a train. Join me tomorrow for some more Windows PowerShell fun.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


Use Hidden WMI Classes and PowerShell to Discover HID Info

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using two WMI classes from the root\wmi namespace to reveal additional HID hardware information.

Microsoft Scripting Guy, Ed Wilson, is here. Well, the Scripting Wife and I returned from Europe yesterday. It is good to be home, but we will miss our friends and all the great food. I fell in love with several new types of food that I have absolutely no hopes of ever finding in Charlotte, North Carolina. While there is a pretty good German restaurant in Charlotte, I have yet to find a Danish, Swedish, Norwegian, Swiss, Polish, Czech, or even Swiss restaurant in Charlotte. Major bummer to be sure. Oh, well. Stay in touch with the Scripting Wife on either Facebook or Twitter because she is already talking about planning a return trip to areas we missed on this trip. We only had three weeks after all.  

Revisiting WMI mouse & keyboard discovery

On the flight from Frankfurt to Charlotte yesterday, I had time (indeed plenty of time) to spend playing around with Windows PowerShell. (I mean one can only watch so many boring movies on a 5-inch screen that bounces every time the person in front of you moves. In my case, the number was exactly 0.) In all fairness, they did have good Jazz music programing, and so I put my headphones, fired up the Windows PowerShell ISE, and began playing.

Last week, I wrote Use PowerShell and WMI to Find Wireless Keyboard & Mouseabout using WMI to identify a wireless mouse and keyboard attached to my system.

So, I was playing around with a function called Get-NameSpace, which I wrote for my new Microsoft Press Windows PowerShell 3.0 Step by Step book, and I decided to investigate additional namespaces for mouse and keyboard information.

Note  The Root\Cimv2 namespace is well documented on MSDN, and the classes there are supported for general use. Classes from other namespaces not documented on MSDN are not supported.

Just because a WMI class is not supported does not mean that it will not work—it only means that I cannot call up Microsoft support for assistance if the thing breaks, quits working, or behaves erratically. With this caveat in place, I begin my investigation.

Note   After things settle down, I intend to add the Get-NameSpace to my HSG*WMI*module.

Get-WMINameSpace Function

Function Get-WmiNameSpace

{

 Param(

  $nameSpace = "root",

  $computer = "localhost"

 )

 Get-WmiObject -class __NameSpace -computer $computer `

 -namespace $namespace -ErrorAction "SilentlyContinue" |

 Foreach-Object `

 -Process `

   {

     $subns = Join-Path -Path $_.__namespace -ChildPath $_.name

     if($subns -notmatch 'directory') {$subns}

     $namespaces += $subns + "`r`n"

     Get-WmiNameSpace -namespace $subNS -computer $computer

   }

} #end Get-WmiNameSpace

 When I run the Get-WmiNameSpace function, I am presented with an extensive listing of new WMI namespaces existing on my computer running Windows 8. The partial listing appears in the following image.

Image of command output

As I look over the listing, I find a couple of namespaces that seem like they might be interesting. The first one is Root\Hardware. I use the following command to see if I can find anything related to a mouse or to a keyboard. As shown here, I found nothing.

PS C:\> Get-CimClass *mouse* -Namespace root\hardware

PS C:\> Get-CimClass *keyboard* -Namespace root\hardware

PS C:\> 

I could also have used the Windows PowerShell 2.0 syntax, but the results are the same.

PS C:\> Get-WmiObject -List *mouse* -Namespace root\hardware

PS C:\> Get-WmiObject -List *keyboard* -Namespace root\hardware

PS C:\> 

After exploring several other namespaces, I decided to go where I felt I would find success—the Root\WMI namespace. Once I queried there, I found several classes I could use.

PS C:\> "*mouse*","*keyboard*" | % {Get-CimClass $_ -Namespace root\WMI}

   NameSpace: ROOT/wmi

CimClassName                        CimClassMethods      CimClassProperties   

------------                        ---------------      ------------------   

MSMouse                             {}                   {}                   

MSMouse_ClassInformation            {}                   {Active, DeviceId, ...

MSMouse_PortInformation             {}                   {Active, Buttons, C...

MSKeyboard                          {}                   {}                   

MSKeyboard_ExtendedID               {}                   {Active, InstanceNa...

MSKeyboard_PortInformation          {}                   {Active, ConnectorT...

MSKeyboard_ClassInformation         {}                   {Active, DeviceId, ...

Notice that the MSMouse and MSKeyboard classes do not expose any properties in the CimClassProperties column. I verified this by using WbemTest as shown here.

Image of Object editor for MSMouse

Basically, the MSMouse class is an abstract class, but it does not have the abstract qualifier. I confirmed this by seeing first there are no instances (I pressed the Instances button). Then I pressed the Derived button, and saw there are two WMI classes derived from the MSMouse class (same thing for MSKeyboard). The derived classes are shown here.

Image of Query Result for MSMouse

Now that I have found the WMI classes that I want to query, I have a couple of choices. If I use the Get-CimInstance cmdlet, I need to supply each class: MSMouse_ClassInformation and MSMouse_PortInformation. But if I use the Get-WmiObject cmdlet, I can take advantage of another unsupported trick. Remember, I said the MSMouse and MSKeyboard classes are abstract? It is not supported to query abstract classes, and the Get-CimInstance cmdlet enforces this ban. However, the Get-WmiObject cmdlet does not. Therefore, when I query an abstract class, the query automatically routes to the two derived classes, and it is from there the answer returns.

Here is the query—I passed the results to the HasWmivalue function from my HSG*WMI* module to filter out empty and system properties.

PS C:\> gwmi msmouse -Namespace root\wmi | ? instancename -match 'hid' | haswmivalue

\\EDLT\root\wmi:MSMouse_PortInformation.InstanceName="HID\\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002

045e_PID&0702&Col02\\9&da0cc6e&0&0001_0"

==========================================================================================================

========================================

 

Name                           Value                                                                     

----                           -----                                                                     

Active                         True                                                                      

Buttons                        5                                                                         

ConnectorType                  2                                                                          

DataQueueSize                  2                                                                         

InstanceName                   HID\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PID&0702&Col02\9...

\\EDLT\root\wmi:MSMouse_ClassInformation.InstanceName="HID\\{00001124-0000-1000-8000-00805f9b34fb}_VID&000

2045e_PID&0702&Col02\\9&da0cc6e&0&0001_0"

==========================================================================================================

=========================================

Active                         True                                                                      

DeviceId                       18446738026718451632                                                      

InstanceName                   HID\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PID&0702&Col02\9...

 I can do the same thing with the MSKeyboard class. The MSKeyboard WMI class does contain the abstract qualifier, as shown here.

Image of Object editor for MSKeyboard

In addition, instead of only two classes derived from the abstract, there are three, as shown in the WbemTest tool.

Image of Query Result for MSKeyboard

Therefore, when I query the abstract MSKeyboard WMI class, three classes report information instead of just the two that report from the MSMouse class. The output from the command is shown here.

PS C:\> gwmi mskeyboard -Namespace root\wmi | ? instancename -match 'hid' | haswmivalue

\\EDLT\root\wmi:MSKeyboard_ClassInformation.InstanceName="HID\\{00001124-0000-1000-8000-00805f9b34fb}_VID&00020

45e_PID&0762&Col01\\9&5c4d6fc&0&0000_0"

===============================================================================================================

=======================================

 

Name                           Value                                                                          

----                           -----                                                                           

Active                         True                                                                           

DeviceId                       18446738026714008784                                                           

InstanceName                   HID\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PID&0762&Col01\9&5c4d...

\\EDLT\root\wmi:MSKeyboard_ExtendedID.InstanceName="HID\\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PI

D&0762&Col01\\9&5c4d6fc&0&0000_0"

===============================================================================================================

=================================

Active                         True                                                                            

InstanceName                   HID\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PID&0762&Col01\9&5c4d...

Type                           81                                                                             

\\EDLT\root\wmi:MSKeyboard_PortInformation.InstanceName="HID\\{00001124-0000-1000-8000-00805f9b34fb}_VID&000204

5e_PID&0762&Col01\\9&5c4d6fc&0&0000_0"

===============================================================================================================

======================================

Active                         True                                                                           

ConnectorType                  2                                                                               

DataQueueSize                  1                                                                              

FunctionKeys                   12                                                                             

Indicators                     3                                                                              

InstanceName                   HID\{00001124-0000-1000-8000-00805f9b34fb}_VID&0002045e_PID&0762&Col01\9&5c4d...

Well, that is all for now. Join me tomorrow for more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell CIM Cmdlets to Discover WMI Associations

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell 3.0 CIM cmdlets to discover WMI class associations.

Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things about the new Windows PowerShell 3.0 CIM cmdlets is the way they enhance WMI discoverability. Indeed, one of the primary questions I get relates back to WMI discoverability. With literally thousands of WMI classes in dozens of WMI namespaces, finding the specific WMI class to solve a particular problem is often a challenge.

Indeed, I used to spend hours searching for a particular WMI class to solve a specific problem. Once I found the WMI class, the actual scripting did not take very long—even in the VBScript days, it did not take me very long because I had written a number of very good templates. Still …. the big problem was finding the appropriate WMI class. Luckily, WMI discoverability using the new CIM cmdlets is a lot easier (for me they replace about a dozen very complex scripts I had written to accomplish the same sorts of things.) But, one script I had not written was one that showed me what WMI classes are related via specific WMI associations. For that purpose, I used the old-fashioned WMI Admin tools.

Finding WMI association classes

I have not been able to get the WMI Admin tools to work correctly on my Windows 8 laptop. This is probably good news, because the WMI Admin tools are like about 100 years old—they are rickety HTML applications that start up with a bunch of prompts, and once loaded, the right pane fails to work. Surprisingly enough, they did work on Windows 7. I say this is good news that they finally fail to work because now I get to move on to use new tools that are safer, faster, and more informative. Yes, I am talking about the new Windows PowerShell 3.0 CIM cmdlets.

Surprise! Association classes have an association qualifier

One of the most powerful tools exposed by the new CIM cmdlets is the Get-CimClass cmdlet. This cmdlet basically replaces the WMI Admin tools—at least the part I used to find WMI classes. The trick to finding WMI association classes is realizing two things. First, all association classes possess the association qualifier. Second, I want to find WMI classes that are dynamic, instead of classes that are abstract. This is because querying abstract WMI classes is not supported. To find all of the association classes, I use the Get-CimClass cmdlet and specify the association qualifier, as shown here.

Get-CimClass -QualifierName association

The output is a couple of hundred WMI association classes—both abstract and dynamic. I can easily filter out WMI classes that begin with Win32—and most dynamic WMI classes begin with Win32. This technique is shown here.

Get-CimClass -QualifierName association | ? cimclassname -match '^win32'

Cool, on my computer I now have the list down to 139 WMI classes. But some of these could be abstract, and I might also miss a dynamic WMI class that begins with CIM_. Unfortunately, the –QualifierName property does not accept an array; therefore, I need to do a couple of queries in the pipeline. I end up with the following command to return dynamic association WMI classes.

Get-CimClass -QualifierName association | % {get-cimclass $_.cimclassname -qualifiername dynamic}

I now have 128 dynamic association WMI class names. In addition, I found Cim_DirectoryContainsFile that is a dynamic association WMI class that begins with the letters CIM.

Finding out which classes make up the association

To find out what WMI classes make up the association, I use the Get-CimClass cmdlet. To illustrate this technique, I will use the Win32_SystemProcesses WMI association class. This class appears to relate processes to a system (at least the name gives that impression). The first thing to do is to use Get-CimClass to return the class. The command and associated results are shown here.

18:19 C:\> Get-CimClass win32_systemprocesses

    NameSpace: ROOT/cimv2

 

CimClassName                        CimClassMethods      CimClassProperties

------------                        ---------------      ------------------

Win32_SystemProcesses               {}                   {GroupComponent, PartCom...

From previous work with association classes, I know that often a WMI association class returns two pieces of information: GroupComponent and PartComponent. The property names themselves are uninteresting, but what IS interesting is the WMI class contained within the GroupComponent or PartComponent property.

Note   Not all WMI association classes return GroupComponent or PartComponent properties. In fact, the most common property names are the properties Antecedent/Dependent, followed by the properties Element/Setting, and then GroupComponent/PartComponent. I used the code shown here to determine the prevalence of Association Class property names (it is a one line command that I broke at the pipeline character).

Get-CimClass -QualifierName association |

% {get-cimclass $_.cimclassname -qualifiername dynamic} |

% { $_ | select -ExpandProperty cimclassproperties} |

Group  name | sort count -Descending

To see what WMI classes return from the association, it is necessary to expand the CimClassProperties property. To do this, I use the Select-Object cmdlet (select is an alias) and I specify the –ExpandProperty parameter (-Expand is a shortened form of that parameter name). This technique is shown here.

18:34 C:\> Get-CimClass win32_systemprocesses | select -expand CimClassProperties

 Name               : GroupComponent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {Aggregate, read, key, MappingStrings...}

ReferenceClassName : Win32_ComputerSystem

 

Name               : PartComponent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {read, key, MappingStrings, Override}

ReferenceClassName : Win32_Process

The ReferenceClassName property of each returned object contains the name of the WMI classes that make up one piece of the association. Therefore, the Win32_SystemProcesses WMI class associates the Win32_ComputerSystem and the Win32_Process WMI classes together. I can now use the Get-CimClass cmdlet to explore the properties and methods that may be contained in the two returned class instances.

That is all there is to exploring WMI association classes. I will continue this topic tomorrow when I will talk about using the new CIM cmdlets to query an association WMI class.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Weekend Scripter: Use PowerShell to Find Local Administrators on a Computer

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell and WMI CIM associations to find local administrators.

Microsoft Scripting Guy, Ed Wilson, is here. Well, we have been really lucky the past couple of days in Charlotte, North Carolina—at least weather wise. Yesterday, it was 60 degrees Fahrenheit and it was sunny with a clear blue sky. I am sitting on the lanai sipping a nice cup of green tea with a cinnamon stick, lemon grass, Jasmine flowers, and just a little bit of lavender. It tastes as great as it smells—certainly a nice way to relax and ease into the day.

Use WMI to find members of the local administrator group

When I can get away with it, I love simplicity. Once you know Windows Management Instrumentation (WMI), the world of Windows administration opens to you. In fact, with the introduction of the CIM cmdlets in Windows PowerShell 3.0, and the movement towards Open Management Infrastructure (OMI), knowing how to use this technology becomes much more important—it is knowledge you can leverage over and over in your daily work.

Anyway, today I was playing around with association WMI classes, and I decided to spend a bit of time using the Win32_GroupUser WMI class.

Note  I talk about WMI associations in Use PowerShell CIM Cmdlets to Discover WMI Associations.

This association class references two other classes: Win32_Group and Win32_Account. This information is shown here.

15:56 C:\> Get-CimClass win32_groupuser | select -expand cimclassproperties

 

Name               : GroupComponent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {Aggregate, read, key, MappingStrings...}

ReferenceClassName : Win32_Group

 

Name               : PartComponent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {read, key, MappingStrings, Override}

ReferenceClassName : Win32_Account

By using Windows PowerShell 2.0 (or Windows PowerShell 3.0), I can query this class by using the Get-WmiObject cmdlet to directly query the association class. I can then filter out the GroupComponent that matches administrators. For each of those, I can use the WMI type accelerator to retrieve the PartComponent property. From the output above, the PartComponent property contains the Win32_Account, and the GroupComponent property contains the Win32_Group, as shown here.

Get-WmiObject win32_groupuser |

Where-Object { $_.GroupComponent -match 'administrators' } |

ForEach-Object {[wmi]$_.PartComponent }

When I run the code, the following appears in the Windows PowerShell console.

16:03 C:\> Get-WmiObject win32_groupuser |

>> Where-Object { $_.groupcomponent -match 'administrators' } |

>> ForEach-Object {[wmi]$_.partcomponent }

>> 

AccountType : 512

Caption     : edLT\Administrator

Domain      : edLT

SID         : S-1-5-21-3464415469-1849125893-2015719117-500

FullName    :

Name        : Administrator

 

AccountType : 512

Caption     : edLT\ed

Domain      : edLT

SID         : S-1-5-21-3464415469-1849125893-2015719117-1001

FullName    :

Name        : ed

 

Caption : IAMMRED\Domain Admins

Domain  : IAMMRED

Name    : Domain Admins

SID     : S-1-5-21-1457956834-3844189528-3541350385-512

The previous command is a single logical line, but it is broken at the pipe character for ease of reading. By using the Windows PowerShell 3.0 syntax, and a few aliases, I can reduce this to a single physical line. The command is shown here.

gwmi win32_groupuser | ? groupcomponent -match 'administrators' | % {[wmi]$_.partcomponent}

Use the PowerShell 3.0 CIM cmdlets to get local admins

I can use the same WMI classes, but use the CIM cmdlets from Windows PowerShell 3.0. This simplifies the code a bit. The first thing I need to do is to obtain a CIM instance. To do this, I use the Get-CimInstance cmdlet. I specify the WMI class as Win32_Group, and I look for groups with the name of administrators. I pipe the returned CIM Instance to the Get-AssociatedInstance cmdlet. This cmdlet will query for an association based upon the association class name.

So you see, it is important to know what WMI classes are made up on which WMI association class. I know, because I know how to use the CIM cmdlets to expand the output to see the association. Now, all I need to do is specify that I am looking for an association and specify the associated class, as shown here.

Get-CimInstance -ClassName win32_group -Filter "name = 'administrators'" |

Get-CimAssociatedInstance -Association win32_groupuser

The command and its associated output is shown here.

16:06 C:\> Get-CimInstance -ClassName win32_group -Filter "name = 'administrators'" |

>> Get-CimAssociatedInstance -Association win32_groupuser

>> 

 

Name             Caption          AccountType      SID              Domain

----             -------          -----------      ---              ------

Administrator    edLT\Administ... 512              S-1-5-21-3464... edLT

ed               edLT\ed          512              S-1-5-21-3464... edLT

 

Caption : IAMMRED\Domain Admins

Domain  : IAMMRED

Name    : Domain Admins

SID     : S-1-5-21-1457956834-3844189528-3541350385-512

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Weekend Scripter: Use PowerShell and WMI Associations to Find User Group Membership

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell and WMI associations to find user group membership.

Microsoft Scripting Guy, Ed Wilson, is here. Today is sort of a mellow day. I just finished reading a mystery story called Some Like it Hawkby Donna Andrews. Donna is really a nice person, and her book is downright funny. Anyway, when I finish reading a book, I am always a little mellow … it is like I want more, but also am not quite ready to go to my unread book pile, and grab another one—just yet. So instead, I grab my laptop and begin playing around with Windows PowerShell. In some ways, Windows PowerShell is sort of like a good mystery story—I basically know how it will turn out, but I am not always certain how complicated things will get. At least with Windows PowerShell, I always know “whodunit.”

Using a WMI association class to find group memberships

Yesterday, I talked about using a WMI association class to find members of the local administrators group. Today, I will reverse that process and find group memberships for a specific user.

One of the key things to remember about WMI association classes is that they work two ways—that is, they link (or associate) one WMI class with another WMI class. In this way, you can always use one member of that association to find the other members of the association.

The workflow, might be something like this … I am exploring members of the local administrators group on a specific computer. I can use the code from yesterday to do this. (In fact, the code will work on a local computer or remotely across the network assuming you have proper rights to do so). I discover a user in the local administrators group that I do not believe should be there. I decide to investigate and see what other groups the user may be a member of. So, using Windows PowerShell 2.0, I can do the following:

Get-WmiObject win32_groupuser |

Where-Object { $_.partcomponent -match 'name="ed"'} |

Foreach-Object {[wmi]$_.groupcomponent}

(Keep in mind, the code can be shortened quite a bit by using aliases.)

When I run the code, the following is shown in the Windows PowerShell console.

16:28 C:\> gwmi win32_groupuser |

>> Where-Object { $_.partcomponent -match 'name="ed"'} |

>> Foreach-Object {[wmi]$_.groupcomponent}

>> 

 

Caption               Domain               Name                 SID

-------               ------               ----                 ---

EDLT\Administrators   EDLT                 Administrators       S-1-5-32-544

IAMMRED\Domain Admins IAMMRED              Domain Admins        S-1-5-21-14579568...

IAMMRED\Domain Users  IAMMRED              Domain Users         S-1-5-21-14579568...

If I have access to Windows PowerShell 3.0, I can use the new CIM cmdlets to perform this query. I first need to use the Get-CImInstance cmdlet to retrieve a specific CIM Instance of the Win32_UserAccount WMI class. I use the –filter parameter to limit the returned object to a specific user. I pipe this CIM instance to the Get-CimAssociatedInstance cmdlet and then specify the association of the Win32_GroupUser. The command is shown here.

Get-CimInstance -Filter "name = 'ed'" -ClassName win32_useraccount |

Get-CimAssociatedInstance -Association win32_groupuser

The command and its output is shown here.

16:31 C:\> Get-CimInstance -Filter "name = 'ed'" -ClassName win32_useraccount |

>> Get-CimAssociatedInstance -Association win32_groupuser

>> 

SID                    Name             Caption                Domain

---                    ----             -------                ------

S-1-5-32-544           Administrators   EDLT\Administrators    EDLT

S-1-5-21-1457956834... Domain Admins    IAMMRED\Domain Admins  IAMMRED

S-1-5-21-1457956834... Domain Users     IAMMRED\Domain Users   IAMMRED

Well, that is about it for today. Join me tomorrow as I begin a new week on the Hey, Scripting Guy! Blog. It will be cool … I promise.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell to Map Disk Drives and Partitions

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell and the CIM cmdlets to use WMI to map disk drives to partitions.

Microsoft Scripting Guy, Ed Wilson, is here. It is definitely a cliché that the more things change, the more they stay the same. This is certainly true in the world of computers. I have been an IT Pro for nearly a quarter of a century (dude, that sounds like a long time when I express it that way), and I have seen many changes in this fascinating field.

But the fact of the matter is that I am still doing the same sorts of things I did nearly forty years ago when I had an Osborne computer—I do databases, word processing, and spread sheets on a day-in and day-out basis. I also interact with other computers. Truth be told, even using the Scripting Wife’s brand spanking new Surface, I am still doing word processing, spreadsheet databases, and interacting with other computers. And so it goes with scripting and with management tasks.

Over the weekend, I was messing around with some of the computers on my network, and I realized that I did not have a mapping of partitions and disk drives … of course, the realization of that fact sprung from a troubleshooting need, but I digress.

I thought there was an association WMI class that could do that, and so I used the CIM cmdlets to search the association classes, until I found what I needed.

Note  For more information on CIM classes, refer back to the Use PowerShell CIM Cmdlets to Discover WMI Associations blog post.

There is a VBScript version of what I am going to do in the Hey Scripting Guy blog post, How Can I Correlate Logical Disk Drives and Physical Disks. After you read that post, you will realize that my lament, that things stay the same, is for the types of tasks we confront and NOT for the tools we have to use. I mean, dude, that is some heavy duty code, and I have all the respect in the world for my Scripting Guys predecessors. See the way cool History of the Scripting Guys blog post for more information about the FAB FOUR (five)!

Mapping Disk Drives and Disk Partitions

The first thing to do when working with WMI association classes is to find out what the association is comprised of. To do this, use the Get-CimClass cmdlet, and pipe the results to the Select-Object cmdlet. Make sure you expand the CimClassProperties property. This command and its output associated are shown here.

16:49 C:\> Get-CimClass win32_diskdriveToDiskPartition | select -exp cimclassproperties

Name               : Antecedent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {read, key, MappingStrings, Override}

ReferenceClassName : Win32_DiskDrive

 

Name               : Dependent

Value              :

CimType            : Reference

Flags              : Property, Key, ReadOnly, NullValue

Qualifiers         : {read, key, MappingStrings, Override}

ReferenceClassName : Win32_DiskPartition

The information I need is in the ReferencedClassName property. In fact, as I will show in just a minute, this information is also valuable from a troubleshooting perspective. I mean, I need to know what I am using in order to use it properly. Initially, I thought I could use Get-Disk and pipe it to the Get-CimAssociatedInstance cmdlet, but as is shown here, it does not work.

17:10 C:\> get-disk | Get-CimAssociatedInstance -Association win32_DiskDriveToDiskpartition

No error returns, but neither does any data. I then decided to look at Get-Disk to see what object it returns. I decide to look at the type object being returned. First, I use the GetType method as shown here.

17:13 C:\> (get-disk).GetType()

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     CimInstance                              System.Object

Well, that did no good. I now use Get-Member, because I know I have seen the underlying WMI classes before (and it is the actual returned WMI class that I suspect is causing problems). Here is the command I used and its associated output.

17:13 C:\> (get-disk | get-member).typename[0]

Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/Storage/MSFT_Disk

I see that the Get-Disk function returns a MSFT_Disk class and not an instance of the Win32_DiskDrive WMI class. So, I am back to basics. I use the Get-CimInstance cmdlet to return an instance of the Win32_DiskDrive WMI class. I pipe the results to the Get-CimAssociatedInstance cmdlet and specify the association as the win32_diskdriveToDiskPartition association class. The command and its associated output are shown here.

17:18 C:\> Get-CimInstance win32_diskdrive | Get-CimAssociatedInstance -Association w

in32_diskdriveToDiskPartition

Name             NumberOfBlock BootPartition PrimaryPartit Size         Index

                 s                           ion

----             ------------- ------------- ------------- ----         -----

Disk #0, Part... 716800        True          True          367001600    0

Disk #0, Part... 311859200     False         True          159671910400 1

That is all there is to using Windows PowerShell, WMI, and the CIM classes to map disk drives and disk partitions.  Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell to Find Non-Starting Automatic Services

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to troubleshoot non-starting automatic services.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have this server in a remote office that is running SharePoint. I do not know what version, but I am not certain that is a problem because it used to work. The problem is the workers in this remote office use this SharePoint server every day—they update copies of an Excel spreadsheet that tracks their daily business activity. Anyway, the server is sort of old, and routinely runs with nearly 100 percent of the memory utilized, and 90 percent of the CPU utilized. Today, I got a call from the office manager saying that they cannot access SharePoint. I tried to make a remote desktop protocol (RDP) connection to troubleshoot the machine, but to be honest, with the limited bandwidth and hardware constraints on the machine, RDP creeps me out, and I want to give up in frustration. What I think I need to do is check the status of the services to see what is started, what is not, and if there are any error codes.

—DD

Hey, Scripting Guy! Answer Hello DD,

Microsoft Scripting Guy, Ed Wilson, is here. Well today, the weather is balmy … at least I think it is balmy, though not sure exactly what balmy is, so it may not actually be balmy. What the weather does do is remind me of when I was growing up in Florida. The weather outside is 60 degrees Fahrenheit with a humidity of nearly 80 percent. It is not raining, but after spending a bit of time outside, it feels like it will rain. The Magnolia tree in my front yard even has a couple of bloom buds on it, but whether those will turn into flowers or not remains to be seen. So why am I talking retro here? Well DD, it is because to check what you need to check will require you to take a retro-type of approach.

Obtaining service startmode and exit code information

I love using the Get-Service Windows PowerShell cmdlet. In fact, the Get-Service cmdlet is one of the cmdlets I refer to as a “demo” cmdlet. Why demo? Well, because it is so easy to use, and because it returns so much good information. I use it every time I am doing a demonstration of Windows PowerShell for network administrators who have never before seen Windows PowerShell. Luckily, that particular audience pool is rapidly shrinking, and I only occasionally speak to an audience where no one has seen Windows PowerShell previously.

But, three pieces of information commonly required for troubleshooting Windows services are not returned by the Get-Service cmdlet. These three pieces of information are the service StartMode, the service StartName, and  ExitCode. To find these three pieces of information requires using the Win32_Service WMI class.

Finding started and stopped services

DD, you stated that you want to see the StartMode, StartName, and the ExitCode of the services. You also say you want to see what is started and what is not. You can easily get what is started and what is not from the Get-Service cmdlet—in fact, the Get-Service cmdlet takes a ComputerNameparameter, and therefore, it might work, depending on the firewall configuration.

By using the Windows PowerShell 3.0 Get-CimInstance cmdlet, the following command returns the service state (what is started and what is not) on a remote computer.

Get-CimInstance win32_service -computer sql1 | Sort state | select name, state

The command and its output associated are shown here.

By using the Windows PowerShell 2.0 cmdlets, the only change required is to change from using the Get-CimInstance cmdlet to using the Get-WmiObject. This command is shown here.

Get-WmiObject win32_service -computer sql1 | Sort state | select name, state

Note   When converting a Get-WmiObject command to Get-CimInstance, keep in mind that the Get-WmiObjectcmdlet uses –Class, and Get-CimInstance cmdlet uses –ClassName. But using –Class (or even using it positionally as done in my previous example) works— the problem would be converting a Get-CimInstance cmdlet that had spelled out –ClassName to Get-WmiObject.

Finding start up accounts, exit codes, and startup type

To find information that is more directly related to troubleshooting, it is better to filter out information more directly related to why the service did not start. I am interested in, first, seeing if the service is set to start up automatically and to see if it is, in fact, running. I use the following filter:

-Filter "startmode = 'auto' AND state != 'running'"

Next, I select the name of the service, the startup account used by the service, and the exit code. The command using the Get-Ciminstance cmdlet (along with output associated with the command is shown here.

15:42 C:\> Get-CimInstance win32_service -Filter "startmode = 'auto' AND state != 'running'" -ComputerName sql1 | select name, startname, exitcode

name                         startname                                      exitcode

----                         ---------                                      --------

FIMSynchronizationService    Administrator@iammred.net                          1066

MSSQLServerADHelper100       NT AUTHORITY\NETWORKSERVICE                        1066

RemoteRegistry               NT AUTHORITY\LocalService                             0

sppsvc                       NT AUTHORITY\NetworkService                           0

SQLAgent$SHAREPOINT          NT AUTHORITY\NETWORK SER...                           0

On Windows PowerShell 2.0, the command is the one showing here.

Get-WmiObject win32_service -Filter "startmode = 'auto' AND state != 'running'" -ComputerName sql1 | select name, startname, exitcode

If a service has an exitcode value of 0, then it means that no error generated when the service exited. For some services, they start, and then stop, and then do not start back up again until they are needed (not all the time, mind you, just some of the time). If I want to hone in on services that do not have an exit code of 0, then I add one more bit of code to my filter. The revised filter is shown here.

-Filter "startmode = 'auto' AND state != 'running' AND Exitcode !=0 "

The complete command is shown here (note, this is a one-line command that is wrapped to display on the blog).

Get-CimInstance win32_service -Filter "startmode = 'auto' AND state != 'running' AND Exitcode !=0 " -ComputerName sql1 | select name, startname, exitcode

Using the Windows PowerShell 2.0 cmdlets, the command is shown here.

Get-wmiobject win32_service -Filter "startmode = 'auto' AND state != 'running' AND Exitcode !=0 " -ComputerName sql1 | select name, startname, exitcode

Both commands and their output are shown here.

DD, that is all there is to using Windows PowerShell to check on the status of Windows Services. Join me tomorrow when I will talk about some more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell to Perform an Orderly Shutdown of a Server Running Hyper-V

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to shut down all virtual machines on a server running Hyper-V prior to shutting down the server.

Hey, Scripting Guy! Question Hey, Scripting Guy! From time to time I need to shut down one of our servers that is running the Hyper-V role. The problem is that these servers have multiple virtual machines running, and I do not want to crash the virtual machines. So, right now, I use the Hyper-V Manager, target the server running Hyper-V, and right-click every running virtual machine and select Shut Down. I do not mind doing this, but some of the virtual machines are running things like Exchange and it takes them a long time to shut down. So, what should be a simple task of shutting down one of our Hyper-V servers ends up taking nearly an hour—an hour of very boring work, I might add.

—BB

Hey, Scripting Guy! Answer Hello BB,

Microsoft Scripting Guy, Ed Wilson, is here. Well, the snow is all gone. Yep, that is right, we had snow in Charlotte, NC. I am sitting here, sipping a nice cup of tea. I have been experimenting a bit. Today my teapot contains the following recipe: 2 teaspoons (tsp.) of English Breakfast, 1 tsp. of generic green tea, ½ tsp. of organic orange peel, ½ tsp. of licorice root, 1 tsp. of lemon grass, and a crushed cinnamon stick. Let it steep for 5 minutes, and I have a very nice pot of tea. It is sweet enough that I feel it needs no sweetener whatsoever.

Note  In this post, I am using the cmdlets from Windows Server 2012 and the Hyper-V module. I obtained this module on my computer running Windows 8 by downloading and installing the RSAT tools. The Windows 8 RSAT tools are available from the Microsoft Download Center.

 

Find all running virtual machines

BB, the first thing you need to do is to use the Get-VM cmdlet and find all virtual machines that are running on the remote host. To do this, use the Get-VM and pipe the results to the Where-Object cmdlet and filter out for a state that is equal to running. It is not as difficult as it may sound. The command is shown here.

$runningVM = Get-VM -ComputerName $vmhost| where state -eq 'running'

Because you more than likely have more than a single virtual machine running on your remote Hyper-V server, I use the ForEach language statement to walk through the collection of virtual machines that I store in the $RunningVM variable. Inside the loop, I create a WMI Event that uses the Win32_ComputerShutdownEvent WMI class to let me know when each virtual machine shuts down. This portion of the code is shown here.

foreach ($cn in $runningVM)

{

Write-Debug "registering shutdown event for $($cn.name)"

 Register-WmiEvent -Class win32_ComputerShutdownEvent -ComputerName $cn.name `

  -SourceIdentifier $cn.name.tostring()

Once I have registered the event, then I call the Stop-Computer cmdlet to shut down the virtual machine. This code is shown here.

Write-debug "Shutting down $($cn.name)"

  Stop-Computer -ComputerName $cn.name -Force

Because I registered a win32_ComputerShutdownEvent for the virtual machine, an event triggers after the virtual machine shuts down. To pick up this event, I use the Wait-Event cmdlet. Once the computer shuts down, the event triggers. This code is shown here.

Write-Debug "Waiting for shutdown to complete"

  Wait-Event -SourceIdentifier $cn.Name.ToString()}

After all of the virtual machines are shut down, it is time to shut down the Hyper-V host computer (the one that hosts all of the virtual machines). To do this, I use the Stop-Computer cmdlet. This is shown here.

Write-Debug "Shuting down $vmhost"

Stop-Computer -ComputerName $vmhost -Force

Monitor progress of the shutdown

Because I am watching the shutdown of the systems remotely, and I want to know what is happening, I decided to add a series of Write-Debug statements. This is extremely easy to use, and when the script runs without the –debug switch only the default output appears. But when the script runs with the –debug switch, it displays each statement and prompts for the action to take place. This is an interactive type of experience, and it may not be what you want. If you are just wanting more information about each statement without the prompt, then use the Write-Verbose cmdlet instead of Write-Debug. They both work the same—I get them for free as long as I add [cmdletbinding()]

Note   During testing, I noticed that sometimes the script would appear to hang. This happens when the virtual machine stops more quickly than I am able to press “y” to confirm the next step, and therefore, the Wait-Event is waiting for an event that has already occurred.

After testing, I decided I was tired of typing “y” all the time, and so I did a global find and replace of Write-Debug with Write-Verbose. I also decided I needed to remove lingering event objects. So I added the following code.

Get-Event -SourceIdentifier $cn.name.Tostring() | Remove-Event

The revised script is shown here.

[cmdletbinding()]

Param($vmhost = 'hyperv2')

Write-Verbose "getting running VM's on $vmhost"

$runningVM = Get-VM -ComputerName $vmhost| where state -eq 'running'

 foreach ($cn in $runningVM)

{

Write-Verbose "registering shutdown event for $($cn.name)"

 Register-WmiEvent -Class win32_ComputerShutdownEvent -ComputerName $cn.name `

  -SourceIdentifier $cn.name.tostring()

Write-Verbose "Shutting down $($cn.name)"

  Stop-Computer -ComputerName $cn.name -Force

Write-Verbose "Waiting for shutdown to complete"

  Wait-Event -SourceIdentifier $cn.Name.ToString()

  Get-Event -SourceIdentifier $cn.name.Tostring() | Remove-Event}

Write-Verbose "Shuting down $vmhost"

Stop-Computer -ComputerName $vmhost -Force

When I run the script now, the following is shown.

Image of command output

BB, that is all there is to using Windows PowerShell to shut down your virtual machines and then to shut down your Hyper-V server.  Join me tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


Use PowerShell to Find Installed Video Codecs on Windows 8

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to find installed video codecs on Windows 8.

Hey, Scripting Guy! Question Hey, Scripting Guy! Dude, I am in trouble. Big time! Last week, I installed Windows 8 on the laptops used by all our department heads and front-line supervisors. I thought the responsiveness and the apps would be very useful and a welcome upgrade—I mean, Windows 8 has gotten great reviews, and personally, I love it. But no!!!!! Come to find out, I guess the only thing these people use their laptops for is to watch DVDs when they are on the road. (I imagine they also check their email, but they could use their phones to do that.) Anyway, I never noticed that Windows 8 does not ship with a CODEC to enable someone to watch a DVD. Huh? I mean, get real, this is ridiculous. Personally, I like Media Player and have used it for years, but not if it is going to get me fired. I need a way to find out if a laptop has a particular CODEC, AND I need to find a DVD CODEC now. Can you help me?

—ML

Hey, Scripting Guy! Answer Hello ML,

Microsoft Scripting Guy, Ed Wilson, is here. WOW, ML, I am sorry you are in trouble. I can imagine that I might have gotten into a similar predicament because I also would not consider watching a DVD on my laptop as a mission-critical use case scenario, and it would have fallen out of the test specs.

Yes, there has been some mixed messaging around playing DVDs on Windows 8. A quick search via Bing reveals lots of blog posts that state that Media Center would be in Windows 8, and not so much that says it will not be in Windows 8. And since we have had Media Center in various editions of Windows for several releases now, I can also expect that you might have missed it. The good news is that you can download the Windows 8 Media Center Pack for Windows 8 Pro for $9.99 USD. The details are available via this web page. Also, if you are not running Windows 8 Pro, we have an upgrade that is available—this upgrade also includes Windows 8 Media Center. I actually did this for one of the Scripting Wife’s computers and it worked very slick, and kept all of her settings (of course, I backed everything up first, just in case).

Finding installed video codecs

To find video codecs installed on your computers, use the Win32_VideoCodec WMI class. You can query it via the old Get-WmiObject cmdlet, as shown here.

Get-WmiObject win32_codecfile -Filter 'group = "video"'

But because you are targeting computers running Windows 8, you can also use the Get-CimInstance cmdlet, as shown here.

Get-CimInstance win32_codecfile -Filter 'group = "video"'

Querying multiple remote computers

To query multiple remote computers, by using the Get-WmiObject cmdlet, you can simply add multiple computer names, and specify the appropriate credentials. This technique is shown here.

Get-WmiObject win32_codecfile -Filter 'group = "video"' -Credential iammred\administrator -ComputerName ws1,ws2,ws3

To query multiple computers by using the CIM cmdlets, first create a cim session, and then do the query. This is shown here.

$session = New-CimSession -ComputerName ws1,ws2,ws3 -Credential iammred\adminIstrator

Get-CimInstance win32_codecfile -Filter 'group = "video"' -CimSession $session

Examine the data

After you have the data, you can examine it by piping it to the Format-List cmdlet and selecting all of the properties. You can then peruse the output to see what properties are most useful for you. Here is an example.

Image of command output

ML, that is all there is to using WMI to examine video codecs. Join me tomorrow for the Weekend Scripter, when I will talk about creating test log files on Saturday and about parsing those log files on Sunday. It will be fun, I promise.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell to Explore Process Threads in Windows

$
0
0

Summary: Microsoft Scripting Guy talks about using Windows PowerShell to explore process threads in Windows.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a problem. On our system, every once in a while, we have this application where the threads go crazy. I need an easy way to check threads. Can you help?

—BC

Hey, Scripting Guy! Answer Hello BC,

Microsoft Scripting Guy, Ed Wilson, is here. Well it is official; there will be a Microsoft Scripting Guy booth at TechEd 2013 in New Orleans. The Scripting Wife will also be at the booth. We are planning to share our booth with the Windows PowerShell community from PowerShell.org as well. It will be a lot of fun, and we are already looking forward to it. The dates for TechEd 2013 in New Orleans, by the way, are June 3 – June 6.

Use WMI to find info about threads

To find information about threads, I use the Win32_Thread WMI class. I found this by using the Get-CimClass cmdlet as shown here.

Get-CimClass *thread*

The command and its associated output are shown in the following image.

Image of command output

I can also do the same thing by using the Get-WmiObject cmdlet. This technique is shown here.

Get-wmiobject -list *thread*

So, I decide to query the WMI class. Here is the Windows PowerShell 2.0 version of the command.

Get-WmiObject win32_thread

I can do the same thing with the CIM cmdlets in Windows PowerShell 3.0. This command is shown here.

Get-CimInstance win32_thread

The command and the output from the command are shown here.

 Image of command output

Find a specific thread

The easiest way to find a specific thread is to first get the process handle, and then use that handle in a WMI filter. The following command obtains the handle for a running instance of Notepad, and then obtains the thread information.

$handle = (Get-Process notepad).handle

Get-WmiObject win32_thread -filter "handle = $handle"

By using the Get-CimInstance Windows PowerShell 3.0 CIM cmdlet, I arrive at the following syntax.

$handle = (Get-Process notepad).handle

Get-CimInstance win32_thread -filter "handle = $handle"

There is very little difference between the two commands. There is a bit of a difference between the output from the two commands. The output from the Get-CimInstance cmdlet is cleaner. The command and output from Get-CimInstance is shown here.

Image of command output

To understand the thread state, it is necessary to look up the ThreadState property. I can do this in the MSDN article, Win32_Thread WMI class. The ThreadState values are shown here.

Value

Meaning

0

  Initialized. It is recognized by the microkernel.

1

  Ready. It is prepared to run on the next available processor.

2

  Running. It is executing.

3

  Standby. It is about to run. Only one thread may be in this state at a time.

4

  Terminated. It is finished executing.

5

  Waiting. It is not ready for the processor. When ready, it will be rescheduled.

6

  Transition. The thread is waiting for resources other than the processor.

7

  Unknown. The thread state is unknown.

The ThreadWaitReason value codes are shown in the table that follows. 

Value

Meaning

0

Executive

1

FreePage

2

PageIn

3

PoolAllocation

4

ExecutionDelay

5

FreePage

6

PageIn

7

Executive

8

FreePage

9

PageIn

10

PoolAllocation

11

ExecutionDelay

12

FreePage

13

PageIn

14

EventPairHigh

15

EventPairLow

16

LPCReceive

17

LPCReply

18

VirtualMemory

19

PageOut

20

Unknown


BC, that is all there is to using Windows PowerShell and WMI to find information about threads. Join me tomorrow when I will talk about more cool stuff.Therefore, the Notepad process is waiting and not ready for the processor. The reason it is waiting is EventPairLow.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Use PowerShell to Explore Windows Audio Drivers

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to explore Windows audio drivers.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a problem with one of my computers—the audio driver is causing me fits. I would like to know if I can use Windows PowerShell to explore this issue. I think it would be really valuable, because I might have this issue come up again. Can you help me?

—DB

Hey, Scripting Guy! Answer Hello DB,

Microsoft Scripting Guy, Ed Wilson, is here. Hey, it is almost the weekend. In celebration of almost the weekend, I decided to get up early, fix a pot of Irish steel-cut oats, and a nice pot of English Breakfast tea. While the oats cooked, I used my Windows Surface to check my email. DB, this is when I ran across your email. Yes, Windows PowerShell can help in many different ways in looking at audio drivers.

First, find the audio device

The first thing to do is to find the audio device. To do this, use the WMI class Win32_SoundDevice WMI class. The Win32_SoundDevice WMI class tells me the device ID and the name of the audio device. The command is shown here.

 Get-CimInstance win32_sounddevice | fl *

 The command and its associated output are shown here.

 Image of command output

Next, find the driver 

Now that I know the name of the audio device, I can look for system drivers. To do this, I use the Win32_SystemDriver WMI class. I “cheap out” and pipe the results to the Where-Object. My resulting command is shown here. (gwmi is an alias for Get-WmiObject, ? is an alias for Where-Object, and fl is an alias for Format-List). 

gwmi win32_systemdriver | ? caption -match 'conexant' | fl * 

The command and its associated output are shown here.

Image of command output

Now get driver file info

Now that I have the path to the driver file, I can use the Get-Item cmdlet to retrieve version information. The first thing I need to do is to obtain the path to the driver. I can get this from the PathName property. I store it in a variable named $path. This is shown here. 

PS C:\> $path = (gwmi win32_systemdriver | ? caption -match 'conexant').pathname 

PS C:\> $path 

C:\WINDOWS\system32\drivers\CHDRT64.sys

Now I want to get only the VersionInfo property. To do this, I use the Get-Item cmdlet and return only VersionInfo as shown here.

PS C:\> (Get-Item $path).versioninfo 

 

ProductVersion   FileVersion      FileName 

--------------   -----------      -------- 

8.32.43.0        8.32.43.0 bui... C:\WINDOWS\system32\drivers\CHDRT64.sys 

Hmm…

I know there is more information in this property, so I pipe it to the Format-List cmdlet as shown here.

(Get-Item $path).versioninfo | fl *

The commands and the associated output are shown here.

Image of command output

DB, that is all there is to using Windows PowerShell to look at audio driver information.  Join me tomorrow for the Weekend Scripter.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Use PowerShell to Find Detailed Windows Profile Information

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to find detailed Windows profile information.

Hey, Scripting Guy! Question Hey, Scripting Guy! I am in a bind. I need to find out who is using what profile on a desktop computer. I also need to find out when the profile was last used. This is because many of the computers in our lab have rather small hard disk drives, and these drives are nearly filled up with user profiles. After I know who has been using a profile and when it was last used, I can decide if I want to remove the profile.

—KG

Hey, Scripting Guy! Answer Hello KG,

Microsoft Scripting Guy, Ed Wilson, is here. It is a new week for the Hey, Scripting Guy! Blog. It is also a new month. This means that this Thursday, March 7, 2013 we will have our Charlotte Windows PowerShell User Group meeting at the Microsoft office. If you are in the area, check it out. You will need to register first so we know how much food to purchase. It is always a lot of fun, and we will be playing a mini Scripting Game.

KG, your request is a reasonable one. To find user profile information, I use WMI.

Finding user profile information

To find user profile information, I use the Win32_UserProfile WMI class. To query the Win32_UserProfile WMI class, I can use the Get-WmiObject cmdlet. This technique is shown here (gwmi is an alias for Get-WmiObject).

gwmi win32_userprofile

The command and its associated output are shown here.

Image of command output

There is a lot of information that I am not interested in examining. In fact, what I really need is LastUseTime, LocalPath, and SID. The revised query is shown here.

gwmi win32_userprofile | select lastusetime, localpath, sid

The revised command and its output are shown here.

Image of command output

But I need something a bit easier to read. Also, I am not interested in profiles that are not used. In Windows PowerShell 3.0, the Get-CimInstance cmdlet translates the time. This brings me a step closer to what I need. Here is the command.

get-ciminstance win32_userprofile | ? lastusetime | select lastusetime, localpath, sid

The command and its output are shown here.

Image of command output

Translating SID to a user

Groovy. Now I need to translate the SID to a readable user account, and I am home free. There are several ways to translate a SID to a user account. One way to do this is to use the Win32_UserAccount WMI class. It is easy to do—and hey, I am already messing around with WMI.

So how does it work? Well, the Win32_UserAccount WMI class has a SID property in addition to a Name property. But I like to use Caption because it has both the domain and the name in it. So I filter on the SID, and boom it works. Here are a couple of examples:

PS C:\> (gwmi win32_useraccount -Filter "sid = 'S-1-5-21-1457956834-3844189528-354135

0385-1613'").name

Tim O'Brian

PS C:\> (gwmi win32_useraccount -Filter "sid = 'S-1-5-21-1457956834-3844189528-354135

0385-1613'").Caption

IAMMRED\Tim O'Brian

PS C:\>

Sweet, so now all I need to do is to create a custom property on my custom object, and I am good to go.

Create custom object with required info

I need to create a custom object with the LastUseTime property, the LocalPath, and the user name. To do this, I use the Select-Object cmdlet. I choose the LastUseTime property and the LocalPath property. I then use a hash table to resolve the SID to a user account name. Here is the hash table I use:

@{LABEL='user';EXPRESSION={(gwmi win32_useraccount -filter "SID = '$($_.sid)'").caption}}

Now, what I am doing in the expression is using WMI to query the Win32_UserAccount WMI class. I specify the filter as Sid = ‘$($_.sid)’. I need the subexpression here to keep the WMI SID property from unraveling. Because the query returns a user account object, and I only want the caption, I group the expression and select only the Caption property. The entire command is shown here (it is a single line command):

get-ciminstance win32_userprofile |

? lastusetime |

select lastusetime, localpath,

@{LABEL='user';EXPRESSION={(gwmi win32_useraccount -filter "SID = '$($_.sid)'").caption}}

The complete command and the output from the command are shown in the image that follows.

Image of command output

KG, that is all there is to using Windows PowerShell and WMI to return user profile stuff. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Testing License State and Setting the License Key

$
0
0

Summary: Microsoft Windows PowerShell MVP, Richard Siddaway, talks about using Windows PowerShell and WMI to work with operating system licensing.

Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual PowerTip. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the book being excerpted that day. Remember that the code is valid only for the day the excerpt is posted. The coupon code is also valid for a second book from the Manning collection.

This excerpt is from PowerShell and WMI
  By Richard Siddaway

Photo of book cover

Product activation for Windows servers may seem to be a pain, but it’s a fact of life. You have to do it for two reasons:

  • To ensure the software is properly licensed and you remain legal
  • To keep the servers working

In this blog, which is based on Chapter 13 of PowerShell and WMI, I will explain how to test license state and set the license key. How can you ensure software is properly licensed in the most efficient manner? My friend James O’Neill answered this in a blog post. In it, he references two WMI classes:

  • SoftwareLicensingProduct
  • SoftwareLicensingService

Note These classes are new in Windows 7 and Windows Server 2008 R2. They’re not available on earlier versions of Windows.

These tips are derived from James’ post. You can test the license status of Windows like this:

Get-WmiObject SoftwareLicensingProduct |

select Name, LicenseStatus

LicenseStatus will return an integer value, where 0 = Unlicensed and 1 = Licensed. A number of results that represent the various ways Windows can be licensed or activated are returned. The important result is the one with a partial product key:

Get-WmiObject SoftwareLicensingProduct |

where {$_.PartialProductKey} |

ft  Name, ApplicationId, LicenseStatus –a

This indicates the licensing situation you’re dealing with. It would be nice, though, if you could get a little bit more information about the licensing state of your system.

Testing license state

Has your IT environment ever been audited? Can you prove that all of your servers are properly activated? This section will help you answer the second question. In addition to being a useful test while you’re building a new server, you can use it to test the setup of your whole estate.

Problem

You need to test the activation and license state of your servers for auditing purposes. Some of the servers are in remote locations and you don’t have the time or resources to physically visit them all.

Solution

You’ve seen that the license status information is available through the SoftwareLicensingProduct class. The following listing shows how you can use that class to generate a meaningful statement about the license status of your server. 

Listing 1: Test license status 

$lstat = DATA {

ConvertFrom-StringData -StringData @'

0 = Unlicensed

1 = Licensed

2 = OOB Grace

3 = OOT Grace

4 = Non-Genuine Grace

5 = Notification

6 = Extended Grace

'@

}

function get-licensestatus {

param (

[parameter(ValueFromPipeline=$true,

   ValueFromPipelineByPropertyName=$true)]

  [string]$computername="$env:COMPUTERNAME"

)

PROCESS {

 Get-WmiObject SoftwareLicensingProduct -ComputerName $computername |

 where {$_.PartialProductKey} |

 select Name, ApplicationId,

 @{N="LicenseStatus"; E={$lstat["$($_.LicenseStatus)"]} }

}}

A hash table, $lstat, is defined at the beginning of the script. You can then call the SoftwareLicensingProduct class against the computer, passed as a parameter to the function. The results are filtered on the PartialproductKey property to ensure you only get the results you need. There are three pieces of data you need:

  • The name of the product
  • The ApplicationId, which is a GUID
  • The decoded license status

The decoding of the license status is managed by the calculated field in the Select-Object statement.

Discussion

The following image shows the results of running the function. The ApplicationId is fixed for versions of Windows. You should get the same result returned on all versions.

Image of command output

The results in the previous image show that you’re still in the grace period after installation of the operating system. You need to set the license key before you can activate the server.

Setting the license key

A Windows license key consists of five groups of five alphanumeric characters. A valid license key is required for each instance of Windows. The key is usually found with the media. Keys are specific to the version of Windows and the source of the media. For instance, you can’t use an MSDN key on a commercial version of Windows.

Problem

The license key needs to be set before you can activate the system. You need to perform this act remotely and ensure that the license key is in the correct format.

Solution

Windows 7 and Windows Server 2008 R2 have a WMI class, SoftwareLicensingService, which you can use to solve this issue. This is shown in the following listing. The license key and computer name are mandatory parameters. This removes the need for default values. The license key pattern is evaluated by using a regular expression and the ValidatePatternmethod. This won’t guarantee that the key is correct, but it will ensure that it’s in the right format.

Listing 2: Set license key 

function set-licensekey {

param (

[parameter(Mandatory=$true)]

[string]

[ValidatePattern("^\S{5}-\S{5}-\S{5}-\S{5}-\S{5}")]

$Productkey,

 

[parameter(Mandatory=$true)]

[string]$computername="$env:COMPUTERNAME"

)

 

 $product = Get-WmiObject -Class SoftwareLicensingService `

-computername $computername

 $product.InstallProductKey($ProductKey)

 $product.RefreshLicenseStatus()

}

You use the SoftwareLicensingService class to create a WMI object. You can use the InstallProductKey method with the license key as an argument. The last line of the function refreshes the license status information.

Discussion

The function is used as follows:

set-licensekey -Productkey "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"  `

-computername "10.10.54.118"

The "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX" represents the license key. You didn’t really think I’d use my real key? The computer on which you’re installing the key can be designated by IP address as here or by its name.

Configuring a new server is a task that occurs on a regular basis in most organizations. There are a number of steps to be completed after the operating system is installed:

  • Rename the server to something more meaningful.
  • Stop and restart the server as required.
  • Set the IP address and DNS servers.
  • Rename the network connection.
  • Join the server to the domain.
  • Install the license key.
  • Activate the server.
  • Set the power plan.

All of these activities take time. You can use Windows PowerShell functions to perform these tasks remotely so you don’t need to spend time accessing the server directly.

~Richard

Here is the code for the discount offer today at www.manning.com: scriptw6
Valid for 50% off PowerShell and WMI and SharePoint 2010 Workflows in Action
Offer valid from April 6, 2013 12:01 AM until April 7, midnight (EST)

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Performance Counters and Windows System Assessment Report

$
0
0

Summary: Microsoft PowerShell MVP, Richard Siddaway, talks about using Windows PowerShell and WMI to work with performance counters and Windows assessment.

Microsoft Scripting Guy, Ed Wilson, is here. This week we will not have our usual PowerTip. Instead we have excerpts from seven books from Manning Press. In addition, each blog will have a special code for 50% off the book being excerpted that day. Remember that the code is valid only for the day the excerpt is posted. The coupon code is also valid for a second book from the Manning collection.

This excerpt is from PowerShell and WMI
  By Richard Siddaway 

Photo of book cover

Measuring system performance has traditionally involved looking at the performance counters. These can be accessed through the performance monitor (SYSMON for those who remember earlier versions of Windows), and they can be saved as required. You can also use the Get-Counter cmdlet (which works against remote machines), or you can use the WMI Win32_Perf* classes.

Windows Vista introduced the system assessment report. This rates a number of system hardware components (including memory, CPU, disk, and graphics) to produce an overall rating for the system. The higher the score, the better the system should perform.

I’m often asked about system stability. The number of unscheduled restarts is one way to measure stability. Later versions of Windows calculate a stability index on an hourly basis. This is calculated based on failures and changes, with recent events being more heavily weighted. The maximum possible score is 10.

Performance counters are still required to dig into individual aspects of the system. In this set of tips, we’ll cover performance counters and Windows system assessment reports.

Reading performance counters

If you’ve spent any time investigating system performance, you know that there’s a huge list of available Windows performance counters. The problem of finding the correct counter to use is increased when you consider that applications such as SQL Server, IIS, and Exchange Server add their own raft of counters. WMI enables you to access some, but not all, of the counters.

You can see which counters are available on a specific system like this: 

Get-WmiObject -List Win32_PerfFormattedData* | select name 

Here’s an extract from the results:

Win32_PerfFormattedData_PerfDisk_LogicalDisk

Win32_PerfFormattedData_PerfDisk_PhysicalDisk

Win32_PerfFormattedData_PerfOS_PagingFile

Win32_PerfFormattedData_PerfOS_Processor

Win32_PerfFormattedData_PerfOS_Memory

You should use the Recurse parameter when searching for these classes because they won’t necessarily be added to the default WMI namespace.

Tip  The Win32_PerfFormattedData class is a superclass that will call the other performance formatted data classes. There will be a lot of data to wade through.

There are also related classes that return the raw performance counter data. These classes are difficult to use, because each value has to be processed through a calculation to derive a meaningful result. It’s easier to use the formatted WMI classes or Get-Counter.

Problem

You need to monitor the processor performance of one of your systems. The server has multiple processors (or cores), and you need to display the information for each processor core and the total to ensure that the application is using the processor resources in an optimum manner.

Solution

The following listing presents a function that takes a computer name and a number as parameters. The number determines how many times you’ll sample the processor information.

Listing 1 Accessing performance counters

function get-cpucounter{

[CmdletBinding()]

param (

[parameter(ValueFromPipeline=$true,

   ValueFromPipelineByPropertyName=$true)]

   [string]$computername="$env:COMPUTERNAME",

   [int]$number=1

)

BEGIN{                                                              #1

$source=@"

public class CPUcounter

{

    public  string  Timestamp  {get; set;}

    public  string Name         {get; set;}

    public  ulong PercProcTime  {get; set;}

}

"@

Add-Type -TypeDefinition $source -Language CSharpversion3

}#begin

PROCESS{

1..$number | foreach {

 

$date = (Get-Date).ToString()

 

Get-WmiObject -Class Win32_PerfFormattedData_PerfOS_Processor `

 -ComputerName $computername | foreach {

    $value = New-Object -TypeName CPUCounter -Property @{

       TimeStamp = $date

       Name = $_.Name                                                 #2

       PercProcTime  = $_.PercentProcessorTime

    }

    $value

}

 

Start-Sleep -Seconds 1                                               #3

}

}#process

}

#1 Create class

#2 Create object and set properties

#3 Pause execution

Some inline C# code is used to create a new .NET class to store your results (#1). The class defines three properties—a timestamp, the name of the processor, and the percentage processor time (how much it was used during the measurement period). This is compiled by using Add-Type. Creating a class in this manner enables you to strongly type the properties, which supplies another level of error checking.

The range operator (..) is used to put the required series of numbers into the pipeline. Windows PowerShell will process each value, and for each of them retrieve the processor performance data by using Win32_PerfFormattedData_PerfOS_Processor. One object per processor, plus one for the total, will be returned. You create an object by using your specially created .NET class, populate its properties (#2), and output it. A one-second pause is activated before you start again (#3).

On my development system, I use this code: 

1..10 | foreach {Measure-Command -Expression {Get-WmiObject

 [CA] -Class Win32_PerfFormattedData_PerfOS_Processor  }} 

It show that the Get-WmiObject command takes about 300 milliseconds to retrieve the data. The function could be altered to change the delay, or you could even make it a parameter.

Discussion

The following image displays the results from using this function. The results show that processing is relatively equally distributed across the two cores. I wouldn’t expect to see the values being identical across all processors or cores all of the time.

Image of command output

Tip  In case you’re wondering how I managed to drive processor performance so high, I set a few continuously looping recursive directory listings. They’re a good way to tax the system without spending a lot of money on simulation tools.

Each of the WMI performance counter classes will need to be investigated to determine the properties that you need to record. For example, the class used here also returns information regarding interrupts.

One common scenario that you’ll get is users’ claiming a difference in performance between two systems. You can use the Windows system assessment report to provide a high-level comparison between the hardware of the two systems.

Windows system assessment report

The assessment report was introduced in Windows Vista. It examines a number of hardware components to determine an overall score for the system.

Tip  The overall score is determined by the lowest of the individual component scores. Always examine the full report to determine whether a single component is adversely affecting performance.

Accessing this information for the local computer through the GUI is acceptable, but you also need a way to perform this action remotely.

Problem

You need to create Windows system assessment reports for a number of remote computers. This will enable you to determine which computers should be refreshed and which are worth reusing.

Solution

The following listing utilizes the Win32_WinSat class to solve this issue. A hash table lookup is created to decode the assessment state property. 

Listing 2: System assessment information 

$satstate = DATA {

ConvertFrom-StringData -StringData @'

0 = StateUnknown

1 = Valid

2 = IncoherentWithHardware

3 = NoAssessmentAvailable

4 = Invalid

'@

}

 

function get-systemassessment{

[CmdletBinding()]

param (

[parameter(ValueFromPipeline=$true,

   ValueFromPipelineByPropertyName=$true )]

   [string]$computername="$env:COMPUTERNAME"

)

PROCESS{

 Get-WmiObject -Class Win32_WinSat -ComputerName $computername |

 select CPUScore, D3DScore, DiskScore, GraphicsScore,

 MemoryScore, TimeTaken,

 @{N="AssessmentState"; E={$satstate["$($_.WinSATAssessmentState)"]}},

 @{N="BaseScore"; E={$_.WinSPRLevel}}

 

}#process

}

 The function returns the data from the WMI class and uses Select-Object to output the properties and two calculated fields. One calculated field decodes the assessment state and the other renames the overall score.

Discussion

This report shouldn’t be taken in isolation when looking at system performance. The age of the system and any remaining warranty should also be considered.

Working with event logs, scheduled jobs, and performance indicators is an essential part of the administrator’s role. Windows PowerShell and WMI provide a number of tools to help you in these tasks:

  • Event log discovery and configuration
  • Backup and clearing of event logs
  • Lifecycle management for scheduled jobs, including creation, discovery, and deletion
  • Retrieval of data from performance counters
  • Production of system assessment reports and stability index data

These techniques enable you to gather data for possible forensic investigations, perform out-of-hours tasks through scheduling jobs, and determine how your systems are performing in real time and with a historic perspective. We discussed two of those techniques: performance counters and Windows system assessment reports.

~Richard

Here is the code for the discount offer today at www.manning.com: scriptw6
Valid for 50% off PowerShell and WMI and SharePoint 2010 Workflows in Action
Offer valid from April 6, 2013 12:01 AM until April 7, midnight (EST)

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Query Multiple WMI Classes but Return One Object with PowerShell

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to query multiple WMI classes with Windows PowerShell and return a single object.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have this script that I have been working on for a while. It queries three different WMI classes. The first two classes are no problem because they only return a single item—for instance, information about the computer or the operating system. But the last class returns information from the disk drives. I have multiple disk drives; therefore, as my script is written now, I keep repeating the computer and the operating system information over and over. I know I am doing something wrong, but I am not sure what to do. Please help.

—FB

Hey, Scripting Guy! Answer Hello FB,

Microsoft Scripting Guy, Ed Wilson, is here. Today has been one of those days. You know the kind of day: an early morning meeting before breakfast, several meetings in the afternoon, and then another meeting after supper in the evening. Yep, a day’s worth of meetings always offers unique opportunities and challenges.

Between meetings, I check email that comes to scripter@microsoft.com. Personally, I do not check email during meetings because I consider it rude to the presenter. But maybe that is just me. If I attend a meeting, I feel that I should pay attention—or else I do not need to be in the meeting in the first place.

Hmm… something on the forums

FB, interestingly enough, there is a question similar to yours, but not exact, on the Official Scripting Guys Forum. Your problem is that you are trying to create a single object from within your script, yet you are returning multiple objects. In addition, your operating system information and your computer information is a single object, but you have multiple objects that represent your disk drives. This results in a ragged object. The way your script currently works, everything is inside the loop, and you return the same information multiple times. The key is to use Begin, Process, and End in your script.

Begin at the beginning

The Begin section of a script runs one time. This is a great place to put things that you want to use to initialize the script—or things that you do not need to process after you receive the information. In this script, I perform two WMI queries and create a hash table. The two WMI queries obtain computer and operating system information. The hash table is to be used to create a custom object at the end of the script. The Begin keyword accepts a script block (delimited by a pair of curly brackets).

Begin {

 [wmi]$os = Get-WmiObject -Class win32_operatingsystem

 [wmi]$cs = Get-WmiObject -Class win32_computersystem

 [hashtable]$osProperties = @{

    'OSVersion'=$os.version;

    'OSBuild'=$os.buildnumber;

    'SPVersion'=$os.servicepackmajorversion;

    'Model'=$cs.model;

    'Manufacturer'=$cs.manufacturer;

    'RAM'=$cs.totalphysicalmemory / 1GB -as [int];

    'Sockets'=$cs.numberofprocessors;

    'Cores'=$cs.numberoflogicalprocessors;

    'SystemType'=$cs.SystemType}}

Process stuff

The Process portion of the script runs one time for each object it must process. If there are no objects, the Process section does not run. In this portion of the script, the drives return an array of drive objects. The size, the freespace, and the percent of utilization become custom properties on the objects. This is the script that accomplishes this portion of the task:

Process {

[array]$disks = Get-WmiObject -Class win32_logicaldisk -filter 'drivetype = 3' |

  Select-Object -Property `

   @{L = 'size'; E = {[math]::Round($_.size /1gb,2)} } ,

   @{L = 'free'; E ={[math]::Round($_.freespace /1gb,2)}},

   @{L = 'percent'; E = {[math]::Round(($_.freespace/$_.size)*100,2)}} }

The end

The End keyword, like the Begin keyword, specifies the section of the script that runs one time. This time, however, the section runs one time after the process section. The hash table created in the Begin section is now used to add the disk information to the object. Finally, a new PSCustomObject is created and the properties added. This is the script that accomplishes this task:

End {

  [hashtable]$osproperties.Add('disks',$disks)

  New-Object -TypeName PSCustomObject -Property $osProperties } 

When the script runs, the following results appear:

Image of command output

FB, that is all there is to using multiple WMI classes in the same script. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


Weekend Scripter: Introducing the PowerShell and WMI Browser

$
0
0

 

Summary: Guest blogger, Jakob Gottlieb Svendsen, talks about the Windows PowerShell and WMI browser.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog post by Jakob Gottlieb Svendsen. But first, a little bit about Jakob…

Photo of Jakob Gottlieb Svendsen

Jakob is a senior consultant, trainer, and chief developer at Coretech A/S, where he is one of the driving forces in keeping Coretech a System Center Gold Partner and member of the System Center Alliance. Since he started at Coretech in 2007, he has focused on scripting and development, primarily developing tools, extensions, and scripts for the System Center Suite.

His main product focus is System Center Orchestrator (the former Opalis), a product he has been invited to speak about at different summits and user group meetings, leading him to become a renowned voice in his field. Since 2012, he has been travelling the world and teaching his 3-day workshop on Orchestrator, which is called “Mastering System Center Orchestrator 2012.”

He is passionately devoted to the community, and he contributes to it by being a moderator at TechNet and a member of the TechNet Influencers team, and by sharing his knowledge on his blog. In 2012, he and a two other Windows PowerShell geeks started the Danish PowerShell User Group.

Jakob’s contact info:

Blog: Coretech Blog
Twitter:@JakobGSvendsen

Coretech WMI and PowerShell Explorer

Hey scripting guys and girls!

WMI is a great tool, but can sometimes be a hassle to browse, and it can be hard to find the information you are looking for. A great quote says, “I have a love-hate relationship with WMI. I love access to everything, but I can never find it!”

To help in this matter, use a WMI browser! My great colleague, Kaido Järvemets (Enterprise Client Management MVP), has released a new WMI and Windows PowerShell browser tool. It is great for any kind of WMI browsing, but it also enables you to browse the Windows PowerShell commands on the local computer to get a list of the valid parameter sets. Because it is written completely in Windows PowerShell using WPF form, it can be a very nice inspiration for your own GUIs!

To get started, you can download the browser and learn about all the requirements and license (it’s FREE!): Coretech WMI and PowerShell Explorer.

Now let’s get busy using this tool…

Using the WMI feature

Follow these steps to start using the WMI browser.

To connect to the local computer Root\Cimv2 namespace

  1. Launch the Coretech WMI and PowerShell Explorer as an Administrator. In the upper-left corner, expand the Menu, and click Connect.

    Image of menu

  2. In the Connect dialog box, use the Browse button to browse for existing namespaces on the local computer (or you can type the Namespace information). In this example, we will connect to the Root\Cimv2 namespace.

    Image of menu

    Image of menu
  3. From the list, double-click Root\Cimv2 to add the namespace, and then click Connect.

Image of menu

With a successful connection, you are now able to browse all the Root\Cimv2 classes.

To connect to a remote computer

  1. Launch the Coretech WMI and PowerShell Explorer as an Administrator. In the upper-left corner, expand the Menu, and click Connect.
  2. In the Connect dialog box, delete the existing computer name.
  3. Type a User name and Password.
  4. Use the Browse button to browse for existing namespaces on the local computer (or you can type the Namespace information). In this example, we will connect to the Root\Cimv2 namespace.

    Image of menu 
     
  5. Click Connect to connect to the namespace. 

Note When you connect to a remote computer, some classes requires that you change the Authentication to PacketPrivacy. The six Authentication levels are:

  • None 
      No authentication is performed.
  • Connect
      Authentication is performed only when the client establishes a relationship with the application.
  • Call
      Authentication is performed only at the beginning of each call when the application receives the request.
  • Packet
      Authentication is required for all data received from the client.
  • PacketIntegrity
      All data transferred between the client and the application is authenticated and verified.
  • PacketPrivacy
      The properties of the other authentication levels are used, and all data is encrypted.

To query information from a specific WMI class

After you are connected to a namespace, you can use Query tab to query the WMI class instances. In the following example, a query lists all installed MSU updates that are listed in the Win32_QuickFixEngineering class.

  1. Connect to the Root\Cimv2 namespace, and in the Filter dialog box, type Win32_QuickFix (or select the class from the list of classes).

    Image of menu
  2. Select the Win32_QuickFixEngineering class, and then click the Query tab.
  3. Notice that the a query that will list all instances from the class is precreated (Select * from Win32_QuickFixEngineering), and it is ready to be run.

    Image of menu

  4. Click Execute to run the query and list the class instances.

    Image of menu
  5. By default, *will return all columns. You can customize the query to return specific columns by typing Select HotfixId, InstalledOn from Win32_QuickFixEngineering

    Image of menu

To export the query results

All results from a query can be exported to a CSV file.

  1. Run a WMI query, right-click any instance in the query result, and click Export Query result.

    Image of menu

  2. The Export feature automatically creates a CSV file on the desktop.

    Image of menu

To export namespace methods

The Coretech WMI and PowerShell Explorer can also be used to export all methods from a namespace. In the following example, all methods from the Root\Cimv2 namespace will be exported.

  1. Connect to Root\Cimv2, and click the NameSpace Methods tab.

    Image of menu
     
  2. Click Get Methods to get a list of all the methods in the Root\Cimv2 namespace.

    Image of menu

Using the Windows PowerShell feature

The Windows PowerShell feature can be used to browse any Windows PowerShell module. This makes it easy to read the Help files or find a command.

  1. Launch the Coretech WMI and PowerShell Explorer as an Administrator, and click the Modules tab.

    Image of menu
     
  2. Enter a module name, or click Browse to browse for a .psm1 or .psd1 file.
  3. Click Import to import the module.
  4. Click Get Modules to fill the modules drop-down list.
  5. Select a command to show the Help file.
  6. If you want a complete list of valid parameter sets for the cmdlets, click the Generate ParameterSets CSV button to export and open a CSV file.

To use Configuration Manager 2012 features

The Windows PowerShell tab also includes a special Configuration Manager 2012 feature for getting examples from the CM12 SDK website.

  1. Launch the Coretech WMI and PowerShell Explorer as an Administrator, and click the Modules tab.
  2. Click Browse and select the ConfigurationManager.psd1 file. The Windows PowerShell module is part of the Configuration Manager administrator console installation, and it is stored in one of the following locations:
       C:\Programs Files(x86)\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1
       or
       <ConfigMgr server install dir>\AdminConsole\bin\ConfigurationManager.psd1

    Image of menu

  3. In the Coretech WMI and PowerShell Explorer, click Import.

    Image of menu

  4. During the import process, you might be presented with an error message that says Windows PowerShell is not supported in a 64-bit version. You can safely ignore that error by clicking OK.

    Image of error message

  5. Click GetModules to load the imported modules.
  6. All loaded modules will be listed in the Select Module drop-down list. In this list, click ConfigurationManager.

    Image of menu

  7. In the Select Command drop-down list, you’ll be presented with all the cmdlets in the ConfigurationManager module.

    Image of menu

  8. Select the New-CMApplication cmdlet to view the Help topics for that cmdlet.

    Image of menu

  9. In the right pane, select Download Code example from CM12 SDK. You’ll now see one or more code examples that can be used in Configuration Manager 2012.

    Image of menu

  10. Copy the example text, and launch Windows PowerShell from the System Center Configuration Manager Administrator console.

    Image of menu

  11. In Windows PowerShell, type (or paste) the code example from CM12 SDK to create the application.

    Image of command output

More features are available in the browser. Go exploring! More guides will appear very soon on Kent Agerlund's Blog.

Have fun browsing!

~Jakob Gottlieb Svendsen

Thank you, Jakob, for presenting a cool tool and an excellent post. I appreciate the time you took to do this. Join me tomorrow for more way cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Use PowerShell to Report and Set Monitor Brightness

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to report and set monitor brightness.

Microsoft Scripting Guy, Ed Wilson, is here. Today I was exploring the Root/WMI namespace in Windows Management Instrumentation (WMI) on my Windows 8 laptop. I happened to run across a few WMI classes that I had not messed around with before. I like to use the Get-CimClass cmdlet from Windows PowerShell 3.0 for this kind of explorations because it supports tab completion and other features that make this exploration easy.

Look for WMI classes related to monitor brightness

So I was initially looking for anything related to monitors. And as I looked at what scrolled by, I saw that there were classes related to monitor brightness. So I decided to modify my query a bit to include things related to monitor brightness. I derived the following command, and achieved the results shown here:

PS C:\> Get-CimClass -Namespace root/WMI -ClassName *monitorbrightness*

 

   NameSpace: ROOT/wmi

 

CimClassName                        CimClassMethods      CimClassProperties

------------                        ---------------      ------------------

WmiMonitorBrightnessEvent           {}                   {SECURITY_DESCRIPTOR, TI...

WmiMonitorBrightness                {}                   {Active, CurrentBrightne...

WmiMonitorBrightnessMethods         {WmiSetBrightness... {Active, InstanceName}

I thought I would try to query the WmiMonitorBrightness WMI class first because it looks like it would report first. So I edited my previous line and changed from Get-CimClass to Get-CimInstance. Here is the command, and the output associated with the command:

PS C:\> Get-Ciminstance -Namespace root/WMI -ClassName WmiMonitorBrightness

 

Active            : True

CurrentBrightness : 100

InstanceName      : DISPLAY\LEN40B2\4&3062e51&0&UID67568640_0

Level             : {0, 1, 2, 3...}

Levels            : 101

PSComputerName    :

So without any reference material, I can see that the current brightness of my laptop monitor is 100. This is probably a percentage setting. I connect to MSDN, and look up WmiMonitorBrightness class. Sure enough it is the current brightness of the monitor as a percentage. The Level property lists supported values for CurrentBrightness. I check it by piping the results to the Select-Object cmdlet. Here is a sample of the output:

PS C:\> Get-Ciminstance -Namespace root/WMI -ClassName WmiMonitorBrightness | select

-ExpandProperty level

0

1

2

3

4

<truncated>

The strange thing is that Level lists how many different levels are available. The value of 101 makes sense because Level begins with 0 and ends with 100.

Set the brightness

To set the brightness on my laptop display monitor, I figure I can use the WmiMonitorBrightNessMethods WMI class. While I have MSDN open, I check out WmiMonitorBrightnessMethods class, and it appears that I will be able to use it to set my monitor brightness:

PS C:\> Get-CimClass -Namespace root/WMI -ClassName WmiMonitorBrightnessMethods

   NameSpace: ROOT/WMI

 

CimClassName                        CimClassMethods      CimClassProperties

------------                        ---------------      ------------------

WmiMonitorBrightnessMethods         {WmiSetBrightness... {Active, InstanceName}

There are only two properties: Active and InstanceName. I decide to look at them. Here is the result:

PS C:\> Get-CimInstance -Namespace root/WMI -ClassName WmiMonitorBrightnessMethods

                      Active InstanceName                PSComputerName

                      ------ ------------                --------------

                        True DISPLAY\LEN40B2\4&3062e5...

Examine the WMI class methods

So, the WmiMonitorBrightnessMethods WMI class looks like it might be useful. Now, I want to look at the method information in more detail:

PS C:\> $wmi.CimClassMethods

 

Name                            ReturnType Parameters           Qualifiers

----                            ---------- ----------           ----------

WmiSetBrightness                   Boolean {Brightness, Time... {Implemented, Wmi...

WmiRevertToPolicyB...              Boolean {}                   {Implemented, Wmi...

WmiSetALSBrightnes...              Boolean {State}              {Implemented, Wmi...

WmiSetALSBrightness                Boolean {Brightness}         {Implemented, Wmi...

I see that there are four methods for the WmiMonitorBrightnessMethods class. The method that looks like it is the best one for my needs is the WmiSetBrightness method. It takes two parameters that I want to look at in more detail. So I adjust my query to focus on it. I use the Item method to specify which method I want to look at. The command is shown here:

PS C:\> $wmi.CimClassMethods.Item('wmiSetBrightness')

 

Name                            ReturnType Parameters           Qualifiers

----                            ---------- ----------           ----------

WmiSetBrightness                   Boolean {Brightness, Time... {Implemented, Wmi...

But the parameters information is still truncated. So I add Parameters to the end of my query and arrive at the following:

PS C:\> $wmi.CimClassMethods.Item('wmiSetBrightness').parameters

 

Name                               CimType Qualifiers           ReferenceClassName

----                               ------- ----------           ------------------

Brightness                           UInt8 {ID, in}

Timeout                             UInt32 {ID, in}

Cool. Now I know the two parameters that I need to use to call this method. Brightness is expressed as a percentage, and Timeout is expressed in seconds.

I use the Get-WmiObject cmdlet to query the WmiMonitorBrightnessMethods WMI class, and store the returned object in a variable as shown here:

$monitor = Get-WmiObject -ns root/wmi -class wmiMonitorBrightNessMethods

Now, I call the WmiSetBrightNess method and specify that I want the monitor to be at 80% and request that it do so in 10 seconds. Here is the command:

$monitor.WmiSetBrightness(80,10)

Cool! It works. Not sure how I will use this, but it does work.

Well, that is all there is to using the WMI classes to set monitor brightness. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Hey, Dude! Where Are My Methods?

$
0
0

Summary: Windows PowerShell MVP, Richard Siddaway, talks about WMI's missing methods in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog post by Windows PowerShell MVP, Richard Siddaway.

Richard has been working with Microsoft technologies for 25 years and has spent time in most  IT roles, including analyst-programmer, server administrator, support, DBA, and architect. He has been interested in automation techniques (including automating job creation and submission on main frames many years ago). He originally used VBScript and WMI since it became available on Windows NT 4.0. Windows PowerShell caught his interest during the early beta versions in 2005. 

Richard blogs extensively about Windows PowerShell and founded the UK Windows PowerShell User Group in 2007. A Windows PowerShell MVP for the last six years, Richard has given numerous talks on Windows PowerShell at various events in the UK, Europe, and the USA. He is frequent speaker for Windows PowerShell User Groups worldwide.

He has published a number of posts about Windows PowerShell, including expert commentaries on the Microsoft Scripting Games, for which he has been a judge for the last four years. He has written two Windows PowerShell books: Windows PowerShell in Practice (Manning 2010) and Windows PowerShell and WMI (Manning 2012). He then collaborated with Don Jones and Jeff Hicks to write Windows PowerShell in Depth, which was published in 2013. Richard is currently writing an introductory book for Active Directory administrators that features Windows PowerShell.

Contact information: Richard Siddaway's Blog

Take it away Richard…

Thanks, Ed.

WMI has been with us for a long time, and it is one of those technologies that you either love or hate. (Some of us manage both at the same time, but that is another story.) Admins love WMI because it’s so powerful—if I can get a WMI connection to your machine, I can do just about anything to that machine. On the flip side, admins hate WMI because it can be very difficult to use, and finding information can be very difficult.

Windows PowerShell has had great WMI support, which was enhanced in Windows PowerShell 3.0 by the introduction of the CIM cmdlets and other WMI enhancements. The new functionality has caused some confusion because the WMI class methods, which we have come to rely on, seem to have disappeared.         

Before I show you what’s happened to your methods, I need to dive into a little WMI theory.

The starting point is that WMI is Microsoft’s implementation of the Common Information Model (CIM). CIM is part of the Web-Based Enterprise Management (WBEM) industry standards that are maintained by the Distributed Management Task Force (DMTF). WBEM is defined as “a set of management and Internet standard technologies developed to unify the management of distributed computing environments.”  WBEM standards are designed to be independent of the operating system and hardware. 

When you start Windows, the WMI repository is created. The repository consists of a number of things:

  • WMI providers (a DLL that provides access to WMI classes)
  • WMI namespaces
  • WMI class definitions
  • WMI instances

This is where some if the confusion arises. WMI classes can be taken to refer to the class definition (comparable to Active Directory schema definitions) and the class instances (compare to an object in Active Directory, such as a user).

When we only had the WMI cmdlets in Windows PowerShell 2.0, life was fairly simple in that you do things like this:

Get-WmiObject -Class Win32_Volume -Filter "Name = 'C:\\'" |

Get-Member -MemberType method 

And you would see the list of methods:

  • AddMountPoint
  • Chkdsk
  • Defrag
  • DefragAnalysis
  • Dismount
  • Format
  • Mount
  • Reset
  • SetPowerState

At this point, I need to remind you that the WMI is COM based, and the WMI cmdlets work over DCOM to local or remote machines.

You could access the methods by creating a Windows PowerShell object that represents the class, and call the method directly:

$disk = Get-WmiObject -Class Win32_Volume -Filter "Name = 'C:\\'"

$disk.DefragAnalysis()

The methods that you have seen so far are Instance methods. They only make sense and can only be used in the context of an instance. For example, you can’t perform DefragAnalysis against a non-existent volume!

Let’s skip over to Win32_Process for a minute:

Get-WmiObject -Class Win32_Process  | Get-Member -MemberType method

This produces the following list of methods:

  • AttachDebugger
  • GetOwner
  • GetOwnerSid
  • SetPriority
  • Terminate

Notice that there isn’t a Create method—these are all Instance methods. You have to have an instance of a process before you can terminate it.

When you are dealing with instances, you are dealing with the System.Management.ManagementObject .NET class. This is where some of the issues lie because you are working with a .NET wrapper for DCOM-based WMI.

Windows PowerShell is .NET based, and you can create just about any .NET object in Windows PowerShell. The Windows PowerShell team recognized that some .NET objects were of great interest to admins, and they provided shortcuts known as “type accelerators.” WMI has a number of type accelerators—in particular, the [wmiclass] type accelerator.

If you apply the [wmiclass] accelerator to the Win32_Process class, you get this:

$proc = [wmiclass]'\\.\root\cimv2:Win32_Process'

$proc | Get-Member -MemberType method

Name   MemberType

----   ----------

Create Method

We now have access to a method that we can use to create instances of the WMI class. The other important point is that we are dealing with a new .NET class: System.Management.ManagementClass. It’s a ManagementClass rather than a ManagementObject.

As a side note, the Create method is one of the intrinsic methods of a WMI class. It will always be there even if you can’t access it. Creating a new instance of the Win32_OperatingSysyem class could do interesting things to your machine!

In .NET terms, you can think of these as Static methods. You don’t need an instance of the class to utilize the methods. The WMI registry provider is a classic example of using WMI Static methods.

Get-WmiObject is a bit of a general work horse. You can use it to work with the instances of a WMI class, and you can use it to investigate WMI classes.

The Windows PowerShell 3.0 CIM cmdlets have separated these functions. Get-CimInstance is for working with instances of a WMI class only!

Get-CimInstance -Class Win32_Volume -Filter "Name = 'C:\\'" |

Get-Member -MemberType method

  • Clone
  • Dispose
  • Equals
  • GetCimSessionComputerName
  • GetCimSessionInstanceId
  • GetHashCode
  • GetObjectData
  • GetType
  • ToString

Hang on! This is totally different.  These aren’t the methods we want.

Remember that the WMI cmdlets work over DCOM to the local or remote machine. DCOM isn’t a firewall-friendly or Internet-friendly protocol. It also relies on an old programming methodology that is being replace by .NET.

The CIM cmdlets use DCOM to access the local machine if the –ComputerName parameter isn’t specified. As soon as you utilize the –ComputerName parameter to access the local or a remote machine, the CIM cmdlets switch to using WSMAN through the WinRM service. You can also use a CIM session with the CIM cmdlets. CIM sessions also work over WSMAN by default. (CIM sessions will be the subject of a future post.) 

WSMAN is the protocol that is used for Windows PowerShell remoting. Windows PowerShell remoting always returns an inert object—one that doesn’t have any methods. This is exactly the situation with the CIM cmdlets—they are designed to work over WSMAN, so they return inert objects.

The methods that you saw belong to the .NET class, which has changed from the WMI cmdlets. It is now Microsoft.Management.Infrastructure.CimInstance.

So far, it’s been established that you can’t access the Instance methods of a WMI class directly through Get-CimInstance. What you can do is pipe the results from your use of the Get-CimInstance cmdlet to Invoke-CimInstance to trigger the method, for example:

Get-CimInstance -ClassName Win32_Process -Filter "Name = 'notepad.exe'" |

Invoke-CimMethod -MethodName Terminate

The Invoke-CimMethod cmdlet has an –Arguments parameter, so you can work with methods that need arguments.

Get-CimInstance enables you to access instances of a WMI class. How do you investigate WMI classes?

This is the function of the Get-CimClass cmdlet. It gives you access to the WMI class metadata (such as properties, methods, and parameters).

PS> Get-CimClass -ClassName Win32_Process | fl *

 

CimClassName        : Win32_Process

CimSuperClassName   : CIM_Process

CimSuperClass       : ROOT/cimv2:CIM_Process

CimClassProperties  : {Caption, Description, InstallDate, Name...}

CimClassQualifiers  : {Locale, UUID, CreateBy, DeleteBy...}

CimClassMethods     : {Create, Terminate, GetOwner, GetOwnerSid...}

CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties

Notice that the Create method is listed. Let’s drill down into the method definition:

PS> $class.CimClassMethods["Create"].Parameters

Name                       CimType Qualifiers

----                       ------- ----------

CommandLine                 String {ID, In, MappingStrings}

CurrentDirectory            String {ID, In, MappingStrings}

ProcessStartupInformation Instance {EmbeddedInstance, ID, In, MappingStrings}

ProcessId                   UInt32 {ID, MappingStrings, Out}

The fact that I get the parameter name and expected data type makes life so much easier. It’s worth upgrading to Windows PowerShell 3.0 for this alone.

Secondly, Get-CimClass gives you one way to access to the Static methods of a WMI class:

Get-CimClass -ClassName Win32_Process |

Invoke-CimMethod -MethodName Create -Arguments @{CommandLine='notepad.exe'}

The arguments are presented as a hash table with the parameter names as the keys. This removes the issue that arises with Invoke-WmiMethod, where the expected order of the parameters can change from that in the documentation.

One last piece of the puzzle remains: How can we tell if a particular method is a Static (or intrinsic) method as opposed to an Instance method? The information is buried in the qualifiers for the methods. Windows PowerShell MVP, Shay Levy, supplied the following script during the discussions that prompted this post:

$class = Get-CimClass -ClassName Win32_Process

$class.CimClassMethods | select Name, @{N='MethodType';

E={if ($_.Qualifiers['Static']){'Static'}else{'Instance'} }} 

Name           MethodType

----           ----------

Create         Static

Terminate      Instance

GetOwner       Instance

GetOwnerSid    Instance

SetPriority    Instance

AttachDebugger Instance         

You can derive the same information by using the WMI cmdlets:

$class = Get-WmiObject -List Win32_Process -Amended

$class.Methods | select Name, @{N='MethodType';

E={if ($_.Qualifiers['Static']){'Static'}else{'Instance'} }}

You need to be aware that using the –Amended parameter drills deep into the WMI repository, and it is an expensive operation in CPU cycles. It will take several seconds to return the data.

To return to the original question…

Dude, your methods are where they have always been. You just need to access them in a different way.

~Richard

Thanks, Richard! You can learn more about using WMI and the new CIM cmdlets with Windows PowerShell in Richard’s book, Windows PowerShell and WMI from Manning Publications. Join me tomorrow when Windows PowerShell MVP, Sean Kearney, will talk about Getting Funky with Windows PowerShell.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

The Admin’s First Steps: Documenting Servers

$
0
0

Summary: Richard Siddaway talks about using Windows PowerShell to automate the creation of your server documentation.

Hey, Scripting Guy! Question Hey, Scripting Guy! I’ve just starting learning Windows PowerShell, and I understand how to use it as a scripting language and shell. But what can I use it for in my environment to make my job easier? Can you give me some suggestions?

—CA

Hey, Scripting Guy! Answer Hello CA,

Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy.

Richard Siddaway is based out of the UK, and he spends his time automating anything and everything for Kelway Ltd. A Windows PowerShell MVP since 2007. Richard is a prolific blogger, mainly about Windows PowerShell (see Richard Siddaway's Blog: Of PowerShell and Other Things), and a frequent speaker at user groups and Windows PowerShell conferences. He has written a number of Windows PowerShell books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author); and PowerShell Dive (co-editor). He is currently finishing Learn Active Directory Management in a Month of Lunches, which features a lot of Windows PowerShell. All of the books are available from Manning Publications Co.

CA, You’re in luck because today I start a new series that explains how to make the jump from knowing some Windows PowerShell to being able to use it to make your life easier as an administrator. You’ve spent some time learning to use Windows PowerShell. You’ve got some scripts that you copied from books or downloaded. But what you really need is an answer to the question, “How do I get started automating my environment?”

As with so many other things, the only correct answer is that it depends. It depends on what are the most pressing issues you need to solve. It depends on what you have in place in terms of monitoring, configuration management, and change control. Most of all, it depends on the time and resources you have available to develop or tailor automation scripts for your environment.

The Windows PowerShell community has been very good at producing material to help explain Windows PowerShell as you go through the learning process. There is also a mass of “how to do X…” materials in the various code repositories—especially in the Windows PowerShell Script Center Repository.

However, there is one big gap that the community hasn’t addressed properly. How do you get started automating your environment after you’ve learned some Windows PowerShell? That’s the question I’m going to start to answer in this series of posts as I talk you through developing some automation processes. These processes aren’t prescriptive or limited to what is explained here. They are simply suggestions that you can use as is—or better still, to spark an idea of your own.

If you have ideas for topics that could be discussed in future posts please leave a comment at the end of this post. No promises though. If a suggestion is adopted depends on a number of factors, including the limitations of my development environment.

Active Directory administration is a common target for automation, and I’ll certainly discuss that later—but I think a better start is documenting your servers. Server documentation is a fact of life. No one likes doing it, and very few organizations find the time to do it—but boy, are you grateful when it’s there.

Creating a server document has two main steps. First, you need to find the information, and then you need to put it into the document. How you write the information into the document depends on the type of document (Word, Excel, or even a web page). I’m going to assume that we are using a Word document for now.

Let’s look at collecting some data. Typically as a starting point, you would want to document:

  • Operating system version and Service Pack level
  • Hardware (CPU, RAM, disk sizes)
  • Network configuration
  • Running services

Getting this information is a snap with Windows PowerShell because you can use WMI to pull the information directly from the remote machine—all from the comfort of your own Windows PowerShell prompt.

Note   I am assuming throughout this post that you are running Windows PowerShell 3.0 on the local computer and on remote machines.

Starting with the operating system:

Get-CimInstance -ClassName Win32_OperatingSystem |

select Caption, ServicePackMajorVersion, LastBootUpTime

Some of the hardware comes from the Win32_ComputerSystem class:

Get-CimInstance -ClassName Win32_ComputerSystem |

select Manufacturer, Model, NumberOfProcessors, NumberOfLogicalProcessors

The memory could be retrieved from this class, but it may not be accurate because it takes into account memory that is allocated to graphics cards and other peripherals. A better way to get the memory is:

Get-CimInstance -ClassName Win32_PhysicalMemory  |

 Measure-Object -Property Capacity -Sum |

 select -ExpandProperty Sum

We’ll restrict disk sizes to local disks. Life would get very complicated if we included mapped network drives and other options.

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |

 select DeviceId, VolumeName, Size, FreeSpace

Network data comes in two flavors: data on the hardware and data on the configuration (IP address). The IP address data is a good starting point because we can filter to ensure that only those adapters with TCP/IP enabled will be returned.

 Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration `

     -Filter "IPEnabled=$true" |

 foreach  

   select -InputObject $psitem -Property Description, IPAddress, IPSubnet,

   DefaultIPGateway, DNSServerSearchOrder, MACAddress,

   @{Name="Name";

     Expression={Get-CimInstance -ClassName  Win32_NetworkAdapter `

     -Filter "DeviceId=$($_.Index)" | select -ExpandProperty NetConnectionID }}

 }

The last part of the information consists of the running services on the server. You could use Get-Service for this, but I’ll stick with WMI. You’ll see why in a minute.

Each time you make a call to a remote machine by using WMI, you have to create, use, and then destroy the connection. One of the coolest parts of Windows PowerShell 3.0 is the ability to create a persistent session to a remote machine for WMI. This is known as a CIM session. You create them like this:

$cimsess = New-CimSession -ComputerName server02

The CIM session is used via the –CIMsession parameter:

Get-CimInstance -ClassName Win32_ComputerSystem -CimSession $CimSession  

select Manufacturer, Model, NumberOfProcessors, NumberOfLogicalProcessors

The last piece of the WMI side of the puzzle is using the WMI calls. I put them into their own little functions and then put the functions into a module. That way, I can use the functions interactively in addition to generating the report. It also means I’m dealing with objects until I create the report. Each function is of this form:

function getos {

param (

[Microsoft.Management.Infrastructure.CimSession]

$CimSession

)

 

Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession |

select Caption, ServicePackMajorVersion, LastBootUpTime 

}

Pass the CIM session as a parameter and output the required data. I deliberately didn’t hyphenate the function names to separate them from other functions.

How do we get the data into a Word document? First we have to create a new Word document. Unfortunately, you don’t have any cmdlets to work with Word documents, but you can fall back on the COM object:

function Add-Text {

param (

 [string] $style = "Normal",

 [string] $text

)

$paragraph = $doc.Content.Paragraphs.Add()

$range = $paragraph.Range

$paragraph.Range.Text = $Text

$paragraph.Range.Style = $Style 

$paragraph.Range.InsertParagraphAfter()

}

 

$word = New-Object -ComObject "Word.application"

$word.visible = $true

$doc = $word.Documents.Add()

$doc.Activate()

 

add-text -style "Title" -text "Server02"

add-text -style "Heading 1" -text "Operating System"

add-text -style "Normal" -text "Some old text"

 

$file = [ref]"C:\Scripts\HSG\testsave.doc"

$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument97") -as [ref]

$doc.SaveAs($file, $saveformat)

 

$Word.Quit()

Create a COM object for Word:

$word = New-Object -ComObject "Word.application"

Make Word visible, add a document, and then activate the document for use. The Add-Text function is used to write the data into the Word document. Pass a Word style and the text to be written into the document to the function. Add-Text creates a paragraph, sets the style and text, and adds it to the document.

Saving Word documents in Windows PowerShell 3.0 is a little more complicated because of issues handling [ref], and we need to define the file path, the format in which the document will be saved (in this case, a good old .doc format), and then call the SaveAs() method. The final action is to quit Word.

Putting it all together, we get this:

param (

[string]$computer=$env:COMPUTERNAME

)

function getos {

param (

[Microsoft.Management.Infrastructure.CimSession]

$CimSession

)

 

Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession |

select Caption, ServicePackMajorVersion, LastBootUpTime

}

 

function Add-Text {

param (

 [string] $style = "Normal",

 [string] $text

)

$paragraph = $doc.Content.Paragraphs.Add()

$range = $paragraph.Range

$paragraph.Range.Text = $Text

$paragraph.Range.Style = $Style

$paragraph.Range.InsertParagraphAfter()

}

 

$word = New-Object -ComObject "Word.application"

$word.visible = $true

$doc = $word.Documents.Add()

$doc.Activate()

 

$cimsess = New-CimSession -ComputerName $computer

add-text -style "Title" -text $computer

add-text -style "Heading 1" -text "Operating System"

add-text -style "Normal" -text (getos  -CimSession $cimsess | format-list | out-string )

 

$file = [ref]"C:\Scripts\HSG\testreport.doc"

$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument97") -as [ref]

$doc.SaveAs($file, $saveformat)

 

$Word.Quit()

$cimsess | Remove-CimSession

The data from our function is formatted into a list (this makes it easier to make sure that it fits on the page), converted to a string, and passed into the Add-Text function. The previous example shows only a single function. The full script is available in the Script Center Repository: Server Report.

This technique works. I’ve used it to prepare the documentation for 150 servers, overnight, in preparation for an audit. Needless to say, we passed the audit!

Ways you could extend this include:

  • Test for a version of WSMAN on the remote machine, and build a DCOM link if it is WSMAN 2.0.
  • Modify code to deal with a Windows Server 2003 error in reporting processors correctly (or apply the hot fix available in article 932370 in the Microsoft Knowledge Base to your computers running Windows Server 2003).
  • Collect more data.
  • Create a document template to use for the report.
  • Use a fixed width font such as Courier New to improve the formatting.
  • Use Word tables to present the data.
  • Convert the Word document to a .pdf.
  • Use Windows PowerShell workflows to run in parallel on multiple servers.

CA, that is all there is to using Windows PowerShell to document your servers. Next time, I’ll have another idea for you to try as you bring automation into your environment.

Bye for now.

~Richard

Thanks, Richard.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Make Multiple WMI Queries to Remote Machine

$
0
0

Summary: Learn how to make multiple WMI queries to a remote machine more efficient.

Hey, Scripting Guy! Question How can I make running multiple WMI queries against a remote machine more efficient?

Hey, Scripting Guy! Answer Create a CIM session with New-CimSession, and use that in your calls instead of a computer name:

$sess = New-CimSession –Computername server02

Get-CimInstance –ClassName Win32_OperatingSystem –CimSession $sess

Viewing all 275 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>