Expert Commentary: 2012 Scripting Games Advanced Event 9

Summary: Microsoft MVP, Arnaud Petitjean, provides expert commentary for 2012 Scripting Games Advanced Event 9.

Microsoft Scripting Guy, Ed Wilson, is here. Arnaud Petitjean is the expert commentator for Advanced Event 9.

Photo of Arnaud Petitjean

Arnaud is an author, speaker, system engineer, and trainer. Arnaud is the founder of the French-speaking Windows PowerShell Community. He specializes in managing VMware (by using Windows PowerShell and PowerCLI) and in desktop virtualization.


Hi! This is Arnaud Petitjean from Montreal. Today we are going to learn how to deal with XML files. Like almost everything with Windows PowerShell, you will see that it is very easy and straightforward.

But first, before generating any file, we need to gather the data about the computer hardware. When we deal with system information, you should immediately start thinking about Windows Management Instrumentation (WMI). Indeed, WMI is a real gold mine. With it, you can collect hardware and software information, as well as interact with a computer locally or remotely in an easy manner. The only “complicated” part of WMI is to find out where the information we need is located.

You should keep in mind that for how huge WMI is, most information related to computer hardware and the operating system are located in the classes respectively named Win32_ComputerSystem and Win32_OperatingSystem.

How do I know that? Well, it’s called “experience.” And it comes over time…

One of the trickiest parts of this event is, in my opinion, to get the MAC address of the primary network interface. To achieve this goal, we need to find out (one more time), where this property is located. One possibility would be to use a tool like WMI Explorer to search for the property name. We could also create our proper Windows PowerShell script based on the Get-WmiObject cmdlet to look for this property. Or best of all, we could use the new cmdlet called Get-CimClass in Windows PowerShell 3.0 (currently in the Beta version). This specific cmdlet has been designed to ease the WMI discoverability process.

The following example shows finding the MacAddress property.

Image of command output

The latest solution is the fastest and the easiest. Instantaneously, we get two results, which are the class names on which the MacAddress property relies. Then we have to explore one of those to see what is inside it. I personally chose the Win32_NetworkAdapter class because I already solved a similar issue, and I remembered that this class worked for me. But after investigating the other one, Win32_NetworkAdapterConfiguration, I can assure you that the MacAddress is also there.

After we apply a filter on the adapter type to get rid of all adapters except the Ethernet adapters, and we apply a filter based on the connection status to get only the connected adapters, we remove all the virtual ones from VMWare (if any). Then we select only the first one because we suppose this is the primary one.

Image of command output

After we capture all the needed properties and place the result inside of some variables, we now have to put all the properties in common. This is when the New-Object cmdlet comes into play. We now are creating a custom hash table with the property names of our choice and mapping the right properties to them. Then we pass this hash table to the Property parameter and we are almost done!

Regarding the PhysicalMemory property, we can notice several things. The first is the use of the megabyte quantifier (MB). This is basically a predefined constant that aims to ease the readability of a script. It is the same but nicer and more understandable than writing 1024*1024. We divide by 1 MB to get the result in megabytes instead of bytes. The second thing is that we truncate the result thanks to the floor static method from the .NET Math class.

Then we create the file name (no difficulty here) and the path to store our XML file. Because there’s no environment variable that stores the “My documents” location, we are using the System.Environment .NET class to gain access to the system special folders. For more information about all the other special folders, please read Environment.SpecialFolder Enumeration in the MSDN Library.

Last but not least, we can convert our final object into an XML string only by using the ConvertTo-XML cmdlet, and then redirect the result to disk.

Getting the five extra points

It can happen that on some machines, some properties are null, for example, the manufacturer’s name or the computer’s model. In that case we would like our script to handle that and provide a way to add a nice ‘N/A’ string instead of a blank value.

So, one way to get the five extra points for this event, could be to check each individual property value of our resulting object (stored in the $result variable), and if we detect a null value, we replace it with the string ‘N/A’.

To do so, a generic approach is needed instead of having a ton of if instructions in our script for every property. Indeed, no matter what the number of properties the object has, accessing the raw Windows PowerShell object via the PSObject property, followed by a simple loop on each of the properties will do the trick. Using this technique will ensure that we won’t miss any property.


The 2012 Scripting Games Guest Commentator Week Part 2 will continue tomorrow when we will present the scenario for Event 10.

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

Ed Wilson, Microsoft Scripting Guy 

Comments (4)

  1. Jaap Brasser says:

    The problem with counting the capacity values in win32_physicalmemory is that you might not only get the physicalmemory you are looking for as detailed in MSDN,…/aa394347(v=vs.85).aspx

    Here is an example on one of my computers, as you can see just counting capacity would not give you an accurate representation of the physical memory eg:

    tag               formfactor typedetail   capacity

    —               ———- ———-   ——–

    Physical Memory 0          8        128 1073741824

    Physical Memory 1          8        128 1073741824

    Physical Memory 2          8        128 1073741824

    Physical Memory 4          0       4096    4194304

  2. aml says:

    Another approach is to look at the routing table, whichever NIC has the default route ( has a good claim to being the primary NIC.  

    $defaultNICID = (get-wmiobject -class win32_ip4routetable |

    where-object{$_.Destination -eq ""}).interfaceindex

    The interface index you get back matches the interface index used in win32_networkadapter and allows you to work out which has the default route.

  3. aml says:

    Most of the examples I've seen use TotalPhysical memory from win32_computersystem to determine how much RAM is in the machine.  But this is always slightly off.  

    The value in TotalPhysicalMemory is the physical memory minus the memory reserved for hardware; it's the memory the operating system has to use.  (If you fire up resource monitor from within task manager and go to the memory tab, you'll see how much memory is assigned to hardware.)

    A more accurate measure of memory is in win32_physicalmemory.  You can get the machine's physical memory with something like:

    $physicalMemory = 0

    $wmiPhysicalMemory = Get-WMIObject -class win32_physicalmemory

    $wmiPhysicalMemory | foreach-object{$physicalMemory += [int64]($_.Capacity)}

    Most of the time the values are pretty similar, but it's nicer to have a value like 4GB for memory, instead of something 3.87GB.  I used TotalPhysicalMemory as my fallback value, and used win32_physicalmemory as the preferred option.

  4. Cameron Wilson says:

    Hmm… I didn't think the adapter with "index 0" would be counted as the "primary" network adapter — especially considering my active network adapter on my machine is actually #2.  How I achieved the primary network adapter was to look at the binding order of the network adapters and choose the adapter with index 0 in the binding order.