Winter Scripting Games 2014: Practice event…my way

The practice event named Server Inventory is now over and the submitted entries will be judged by very experienced Powershell pratitioners: Don Jones, Jason Helmick, Jeffery Hicks, Ed Wilson and Richard Siddaway.

There are always multiple ways to solve a problem and here’s my way πŸ˜€
This event could be written as a script (vs. a module or a function). I’ve decided to write it for Windows 2012 or Windows 8 or above platforms.

It may not be very explicit in the first requires statements but the DnsClient module is available on Windows 8 or above and the ActiveDirectory module is available if you install RSAT on a Windows 8 or if you enable the feature on the Windows server.

Add-WindowsFeature -Name RSAT-AD-PowerShell -Restart:$false

As it’s a script, the execution policy should also be modified so that it allows running scripts.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

I didn’t add the #Requires -RunAsAdministrator but I validated administrator privileges in the Begin block like this:

using what I previously did in this post.

As I see the event, it could be split into 3 parts.

  1. The network part
  2. I’m not the network guy and I don’t like to reinvent the wheel, so I borrowed two functions from Powershell MVP Dr. Tobias Weltner and Carlos Perez:

    I’ve added a comment based help and some strong parameter validation.

    Now that I could return an array of IP addresses from the subnet submitted in a CIDR notation, I created a workflow to get the name of computer from its IP Address and its operating system version.

    I’ve used the new cmdlet Resolve-DnsName that can be found in the DnsClient module. I’ve also used the ActiveDirectory that store the operating system version as soon as I had the computername.

    As you can see, I’ve chosen to test the Powershell remoting of each server with the Test-WSMan cmdlet because my inventory method is based on remoting. That also means that a recent version of Powershell is installed on each server and the the remoting is configured appropriately. In my case, the default TCP port 5985 would be used and should be also allowed in firewall incoming rules…

    To extract the operating system build from AD in a more standard way, I’ve used a regular expression and the following link help me to write it.

    I did this because you can guess the service pack from the build number as of Windows Vista.
    The main process block in my script is that short:

    I’ve used the following resource to implement it: a must read.

    In the end block of the script, I exported the active and inactive IP Addresses in CSV format like this:

  3. The inventory part
  4. There are many ways to gather the inventory data. I’ve tried to show some of them depending on the target operating system and its version of powershell. I’ve chosen to use fan-out remoting capability provided by the Invoke-Command cmdlet combined with its ability to use jobs.

    Last year, I discovered what the server manager was doing behind the scene and used this technique to gather data on Windows 2012 servers. To query whether Exchange, SharePoint, SQL or IIS were installed, I used the services way.

    Another more classic way to gather inventory data on recent Windows Server editions is the following:

    Another way to know if SQL, IIS and SharePoint are installed consists in loading their snap-in except for Exchange (I couldn’t find a common denominator)

    And there’s also the registry way:

    To query when the last hotfix was installed, the most reliable way isn’t through the WMI Win32_QuickFixEngineering class or the Get-Hotfix cmdlet but with the Microsoft Update comobject like this:

    (New-Object -ComObject Microsoft.Update.Session).            
    QueryHistory(0,1) |            
     Select -ExpandProperty Date

    And for fun there’s another way to gather inventory data, with systeminfo.exe. Either you convert its output to CSV (see this Power Tips) or using a regular expression (I used this in Scripting Games 2012):

    Instead of waiting for jobs to complete without displaying progress this way:

    Get-Job | Where Name -match 'InvScan_' |             
     Wait-Job -Timeout -1 | Out-Null

    … I did the following to display some progress:

    While (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Running') {            
     $Total = (Get-Job | Where Name -match 'InvScan_') ;            
     $completed = (Get-Job | Where Name -match 'InvScan_' | Where State -eq 'Completed') ;            
     $WPHT = @{            
        Activity = 'Waiting for scan inventory to complete' ;            
        Status = ('{0} over {1}' -f $Completed.Count,$Total.Count) ;            
        PercentComplete = (($Completed.Count)/($Total.Count)*100) ;            
     Write-Progress @WPHT            
     Start-Sleep -Seconds 1            
  5. the visualisation part
  6. I didn’t want to install Office on a server just to be able to create the powerpoint presentation. I created a parameter switch dedicated for this part. So, on a Windows 8 or 8.1 workstation with at least Office 2010 installed, using the switch would just read the results of the inventory saved in a share and create the slides.

    To create charts, I thought it would be easier to save the chart as an image rather than creating data in Excel and then create the chart in Powerpoint linked to it.

    I found the following article about charting with PowerShell that helped me build the images and create my ConvertTo-Pie function. To create the second function New-PPTXFile, I found the inspiration in the following code posted by JayKul on

    My powerpoint presentation has 2 slides that look like this:

I’ve uploaded my solution for the practice event as a public gist available on this link
It’s probably not perfect but I had fun and learned many things πŸ˜€
As I write these last lines, the first event of the Winter Scripting Games has already been published, so, it’s your turn now.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.