Tips on scripting with PowerShell objects…

PowerShell is a great tool for collecting information. Here’s some direct tips to try to minimize the pain of coding, or at  least make it (kind of) readable.  I’ve seen some blogs out there that turn some people way just because their script is working.  But, that’s the beauty of PowerShell.  No matter how you build the code, if the end results is what you’re looking for, then good for you. 

I hope later on you realized that your script can be improved, and you will feel the POWER of POWERSHELL!!!

Briefly, I will be covering PSObject, Hash table, and a bonus Array objects

Check this out.  Here’s an example of some script lines building a PowerShell variable object from two Cmdlets executing two different WMI classes: Win32_OperatingSystem and Win32_BIOS.

Original Sample

   1: $ComputerName = "."

   2: $wmi = Get-WmiObject Win32_OperatingSystem –comp $ComputerName | Select CSName,BuildNumber,ServicePackMajorVersion;

   3: $obj = New-Object PSObject;

   4: $obj | Add-Member NoteProperty BuildNumber ($wmi.BuildNumber);

   5: $obj | Add-Member NoteProperty CSName ($wmi.CSName);

   6: $obj | Add-Member NoteProperty SPVersion ($wmi.ServicePackMajorVersion);

   7: $wmi = Get-WmiObject Win32_BIOS –comp $ComputerName | Select SerialNumber;

   8: $obj | Add-Member NoteProperty BIOSSerial ($wmi.SerialNumber);

   9: $obj;

Now, the above code will work.  In my opinion using Add-Member is already old school. 

image

At the end, I checked for the PS variable ($obj) type, using the “.gettype()” method.  This confirmed this variable a PSCustomObject.

I will show you other ways to get a similar results, and hopefully with less typing.  Maybe, it will look nicer too.  The goal is, as you progress using PowerShell for you day-to-day activity, you will continue to improve your existing code.

Improvement #1

   1: $ComputerName = "."

   2: $wmi1 = Get-WmiObject Win32_OperatingSystem –comp $ComputerName | Select CSName,BuildNumber,ServicePackMajorVersion;

   3: $wmi2 = Get-WmiObject Win32_BIOS –comp $ComputerName | select SerialNumber;

   4:  

   5: $results = $wmi1|select csname,BuildNumber,ServicePackMajorVersion,@{Label=”BIOSSerialNum”;Expression={$wmi2.SerialNumber}};

   6: $results;

As you can see, here I’m first collecting all the information by building my PowerShell variables in $wmi1 and $wmi2 which has different results.  Then, I’m combining the values I want from my $wmi1 and $wmi2 using the “Select” command.

image

So we made some improvements from originally 9 lines of code cut down to 5 lines.  And, notice that the new PS variable type still is “PSCustomObject”.

Now, let me show you another very nice variation that is intended to replace the use of “Add-Member” command.  We are going to use the Hash table concept to create our “PSCustomObject” variable.

Here’s another way which is better looking with less typing than our first example.

Improvement #2

   1: $wmi1 = Get-WMIobject -class Win32_OperatingSystem;

   2: $wmi2 = Get-WmiObject Win32_BIOS

   3:  

   4: $PCHashTable = @{

   5:     BuildNumber  = $wmi1.BuildNumber;

   6:     csname       = $wmi1.csname;

   7:     ServPackVersion = $wmi1.ServicePackMajorVersion;

   8:     BIOSSerialNum   = $wmi2.SerialNumber;

   9: }

  10:  

  11: $MyPSObject = New-Object PSObject -Property $PCHashTable;

  12: $MyPSObject;

image

As you can see, this PowerShell code have 10 lines but, for me, it looks cleaner and easy to read.  Basically, we are breaking the code in three sections:

1. Create the variable objects holding our results.

2. Build the hash table where we combine all our selected objects.

3. Convert the hash table to a “PSCustomObject”, so we can display the results in a proper format.  (see next pic.)

image

Hidden Tips:

Check in both improvement samples (1 & 2), I’m showing how you can create/change the label of your variable property in the “Select” command, and when you are creating a Hash table.

Bonus Script: Using Arrays objects to Collect information

Here’s a snippet you could use the gather information about your SQL Servers using .NET SMO SQL Enumeration to get all SQL names on the network.  To run this script you need to have SQLPS loaded in you PowerShell session and have proper server Windows Authentication.

I hope you’ll like it:

   1: ## For SQL Server need SQLPS to be loaded

   2: ##

   3: $SQLSvr = [Microsoft.SqlServer.Management.Smo.SmoApplication]::EnumAvailableSqlServers($false) | Select name;

   4:  

   5: [Array] $SQLinfo += ForEach($SQL in $SQLSvr){

   6:     $MySQL = new-object(“Microsoft.SqlServer.Management.Smo.Server”) $SQL.Name;

   7:     $MySQL | Select NetName, Product, EngineEdition, Version, Platform, ProductLevel;

   8: } 

   9:  

  10: $SQLinfo | select Netname, Product, EngineEdition, Version, ProductLevel | ft -auto;

Hidden Tip: Notice, I  have created an Array object ($SQLInfo) in line 5, in which the “ForEach()” command will be use to add the results from each element read from the server object ($SQLSvr).

BIG REMINDER!!!  Remember that your PS variables will probably have more values you can display in your results using the “.. |Select val1, val2, val5…”.  Use the Get-member command to exposed them.  (see next pic.)

image

That’s it for now!!