header image

Archive for Deep Dive

WMI classes will sometimes have be associated with other classes for example each instance of the Win32_NetworkAdatper class is associated with an instance of the Win32_NetworkAdapterConfiguration.  The link is expressed by the Win32_NetworkAdapterSetting which shows the links.

I normally use WQL queries based on ASSOCIATORS and REFERENCES to discover these classes.  ASSOCIATORS shows the end point of the link and REFERENCES shows the linking class

We can do some of this work directly from the WMI object.

Lets get a network adapter object (you will need to use a deviceid thats present on your machine)

$nic = Get-WmiObject Win32_NetworkAdapter  -Filter "DeviceId=11"

and check its methods

$nic | gm -MemberType method

 

This doesn’t show what we need so we’ll drop to the underlying object

$nic.psbase | gm -MemberType method

 

which shows two methods of interest

GetRelated
GetRelationships

 

We could also use

$nic | gm -MemberType method -View base

The methods relate to WQL like this

GetRelated = Associations
GetRelationships = References

 

What we get with these methods is the full related object.  We don’t have a method on the object to discover the classes that are related. For that we stick with WQL

Get-WmiObject -Query "ASSOCIATORS OF {Win32_NetworkAdapter.DeviceID=11} WHERE ClassDefsOnly"
Get-WmiObject -Query "REFERENCES OF {Win32_NetworkAdapter.DeviceID=11} WHERE ClassDefsOnly"

 

though these snippets are equivalent

$nic.GetRelated() | select __class –Unique

$nic.GetRelationships() | select __class –Unique

 

If we want to see the associated classes we can do this

$nic.GetRelated()

or

Get-WmiObject -Query "ASSOCIATORS OF {Win32_NetworkAdapter.DeviceID=11}"

 

For a specific result class we can do this

$nic.GetRelated("Win32_NetworkAdapterConfiguration")

or

et-WmiObject -Query "ASSOCIATORS OF {Win32_NetworkAdapter.DeviceID=11} WHERE ResultClass=Win32_NetworkAdapterConfiguration"

 

Switching to the links between classes – if we want to see all the links

$nic.GetRelationships()

or

Get-WmiObject -Query "REFERENCES OF {Win32_NetworkAdapter.DeviceID=11} "

 

and if we want to see a single link

$nic.GetRelationships("Win32_NetworkAdapterSetting")

or

Get-WmiObject -Query "REFERENCES OF {Win32_NetworkAdapter.DeviceID=11} WHERE ResultClass=Win32_NetworkAdapterSetting"

This gives us two routes to the information we need.  Use whichever you are most comfortable with.

under: Deep Dive, PowerShell and WMI

During Jeff Hicks’ talk about formatting he did the usual demo of taking an extract of a format file and modify it to create a new default format. 

Jim Truher mentioned that he had a script that would generate the XML for a format file and that he would post it.  He has and its here

http://jtruher3.wordpress.com/2011/04/19/a-tool-for-table-formatting/

 

If you want to modify the way things are displayed or create you own standard formats this will make life much easier.

under: Deep Dive, PowerShellV2

One topic that came up during my talk at Deep Dive was the speed of running a WQL vs using –Filter in Get-WmiObject.  I’d never tested it so its time to find out.

PowerShell v2 has a handy cmdlet called Measure-Command that times how long a command runs

We’ll start with using a filter

Get-WmiObject -Class Win32_Process -Filter "Name=’Notepad.exe’"

 

if we wrap it in Measure-Command we get this

Measure-Command -Expression {Get-WmiObject -Class Win32_Process -Filter "Name=’Notepad.exe’"}

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 81
Ticks             : 817436
TotalDays         : 9.46106481481481E-07
TotalHours        : 2.27065555555556E-05
TotalMinutes      : 0.00136239333333333
TotalSeconds      : 0.0817436
TotalMilliseconds : 81.7436

 

We want the TotalMilliseconds property and we need to do it more than once

 

1..100 | foreach {Measure-Command -Expression {Get-WmiObject -Class Win32_Process -Filter "Name=’Notepad.exe’"}} |

Measure-Object -Property TotalMilliseconds -Average

Count    : 100
Average  : 52.640332
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

Now lets repeat as a query

Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name=’Notepad.exe’"

 

which becomes

Measure-Command -Expression {Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name=’Notepad.exe’"}

 

1..100 | foreach {Measure-Command -Expression {Get-WmiObject -Query "SELECT * FROM Win32_Process WHERE Name=’Notepad.exe’"}} |

Measure-Object -Property TotalMilliseconds -Average

Count    : 100
Average  : 52.345972
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

Just for fun lets try this

1..100 | foreach {Measure-Command -Expression {Get-WmiObject -Class Win32_Process | Where {$_.Name -eq ‘Notepad.exe’} }} |

Measure-Object -Property TotalMilliseconds -Average

Count    : 100
Average  : 92.96794
Sum      :
Maximum  :
Minimum  :
Property : TotalMilliseconds

 

So the results so far

Filter:  52.640332

Query:   52.345972

Where:   92.96794

The filter and the query are almost the same – I’m not going to argue over 0.03 milliseconds.  Using Where-Object takes nearly twice as long. This is understandable because the query and filter pick out a single process but using Where-Object we return all processes and then filter.

I stated in my talk that it was better to use the filter because it was less typing. On these results I’ll stand by that statement for local machines as it takes me more than a few milliseconds to type the extra characters using a query.

Further research is needed:

  1. What happens if running against remote machines?
  2. is it faster to select properties in the query or using select-object

We’ll return to these points later

under: Deep Dive, PowerShell and WMI

One question that I was asked at the deep dive –

Is there a way to link a disk volume back to the physical disk it resides on?

There doesn’t seem to be. If we test the WMI classes associated with a volume we get these results

Win32_Directory
Win32_QuotaSetting
Win32_ShadowProvider
Win32_ShadowCopy
Win32_ComputerSystem
Win32_Volume
Win32_Group

If anyone knows how to relate Win32_Volume to the physical disk (need to get the serial number off the disk) then I’d be interested in hearing about it

under: Deep Dive, PowerShellV2

The PowerShell Deep Dive last week was the best conference I have ever attended. The group consisted of members of the PowerShell team, Ed Wilson – the Scripting Guy, PowerShell MVPs and a large number of PowerShell experts and enthusiasts.  The last word summed it up.  The Scripting Club was supposed to finish at 10pm – it really finished at 3am next morning.

The sessions were short – 35 minutes – and much more interactive than a normal conference. A blog post can’t do justice to the event all I can say is that I’ll be booking for the next one as soon as its announced.

With that many experts drawn together I managed to learn something in every session – even the one I gave!

I’ll post some snippets of I what I learned in a series of posts. Some you may know & some may be new.

The first snippet involves working with COM collections. Many COM objects have properties that are actually collections of other objects. As an example consider the Windows firewall.

$fw = New-Object -ComObject HNetCfg.FwMgr

If we drill into the object we find

$fw.LocalPolicy.CurrentProfile.Services

on my machine I get three services

– File and Printer Sharing
– Network Discovery
– Remote Desktop

The logical thing to try would be

PS> $fw.LocalPolicy.CurrentProfile.Services[0]
Unable to index into an object of type System.__ComObject.
At line:1 char:41
+ $fw.LocalPolicy.CurrentProfile.Services[ <<<< 0]
    + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
    + FullyQualifiedErrorId : CannotIndex

 

But we get an error.  The collection doesn’t have an index.  Bah!!!

But if we do this

$x = @($fw.LocalPolicy.CurrentProfile.Services)

 

we can then do this

PS> $x[0]

Name              : File and Printer Sharing
Type              : 0
Customized        : False
IpVersion         : 2
Scope             : 1
RemoteAddresses   : LocalSubnet
Enabled           : True
GloballyOpenPorts : System.__ComObject

 

which gives us an array where we can work with indexes

Simple but effective.

This is one of the strengths of an event like Deep Dive – you get to pick everyone else’s brain. During a session someone said “None of us know it all but between us in this room we know nearly all of it”

That should be the motto of the PowerShell community!!

under: Deep Dive, PowerShellV2

« Newer Posts

Categories