PowerShell to Get OS Type and Count

My manager asked for the count of Windows Server 2012 virtual servers. So I did a fast and dirty script to get just the count of Server 2012

$server2012 = ((get-vm).extensiondata.guest | Where GuestFullName -eq "Microsoft Windows Server 2012 (64-bit)").count

After I provided the results from this, I worked to make it a better, more robust script. I started by brainstorming how to make this dynamic enough that I wouldn’t have to update the script for new OS types. So using an array was out as it would have static fields. So I then thought about a hash table. This would allow me to add the OS types to the hash table then adding up the number of that type.

$OS_hashtable = $null
$OS_hashtable = @{}
$VMs = Get-VM

So with the above, it starts the creation for the hash table, and then I gather all of the VMs in the environment.

foreach ($VM in $VMs){
    $OSName = $VM.ExtensionData.Guest.GuestFullName
    If(!($OS_hashtable.ContainsKey($OSName))){
        $OS_hashtable.add($OSName,0)
    }
    $Value = $OS_hashtable.$OSName
    $NewValue = $Value + 1
    $OS_hashtable[$osName] = $NewValue
}
$OS_hashtable | FT -AutoSize

This next portion starts parsing the VMs one at a time to get the OS name. It then looks at the hash table to see if the OS name is in the table, if not it will add it. When adding a new entry to the hash table, it needs to include default value. So I used 0. Then in the next section, I got the value associated with the OS name, and added one to it.

Name                                            Value
----                                            -----
Microsoft Windows 2000 Professional             1    
Red Hat Enterprise Linux 5 (64-bit)             11   
Red Hat Enterprise Linux 7 (64-bit)             88   
Other 2.6.x Linux (64-bit)                      15   
Other 2.6.x Linux (32-bit)                      2    
Microsoft Windows Server 2003 Standard (64-bit) 1    
VMware Photon OS (64-bit)                       16   
Windows Server 2019, 64-bit  (Build 17763)      382  
Microsoft Windows Server 2008 (64-bit)          26   
Microsoft Windows Server 2003 (32-bit)          8    
Microsoft Windows Server 2008 (32-bit)          54   
Microsoft Windows Server 2016 (64-bit)          1036 
Microsoft Windows Server 2008 R2 (64-bit)       340  
Microsoft Windows XP Professional (32-bit)      1    
CentOS 6 (32-bit)                               1    
Other Linux (64-bit)                            3    
Microsoft Windows Server 2003 Standard (32-bit) 24   
CentOS 7 (64-bit)                               6    
Microsoft Windows 7 (32-bit)                    2    
Other 3.x Linux (64-bit)                        8    
CentOS 6 (64-bit)                               15   
Debian GNU/Linux 9 (64-bit)                     2    
Microsoft Windows Server 2012 (64-bit)          1212 
Red Hat Enterprise Linux 8 (64-bit)             1    
Red Hat Fedora (64-bit)                         4    
Microsoft Windows 10 (64-bit)                   64   
SUSE openSUSE (64-bit)                          7    
Red Hat Enterprise Linux 6 (64-bit)             36   
SUSE Linux Enterprise 12 (64-bit)               4    
SUSE Linux Enterprise 11 (64-bit)               8    
FreeBSD Pre-11 versions (64-bit)                4    
Other 4.x or later Linux (64-bit)               3    
CentOS 4/5 or later (64-bit)                    10   
Ubuntu Linux (64-bit)                           18   
Oracle Linux 7 (64-bit)                         1    
FreeBSD 12 or later versions (64-bit)           2    
                                                46

After reviewing the output of the script, I found an issue. The last entry in the hash table is blank, but has a value. So I added some debug lines so I can find what is going wrong.

IF ($debug){write-host "$VM - $OSName"}

The debug line is added right after $OSName variable is populated. So I watch the script run. When I see a output that doesn’t include the OS name, I check the Get-VM to see if it really doesn’t have any information about the OS or how I need to get it. So I found another property that provides the OS name that was missing.

IF ($OSName -eq $NULL){$OSName = $VM.ExtensionData.Config.GuestFullName}

With the new line above, it didn’t solve the blank line issue. Although my totals changed, so it did help. Now I need to find a new way to solve the blank value issue. So the $OSName isn’t $Null on the blank value VMs. The more I thought about this, I just captured the value and out-file the variable. Reviewing the output was blank. Odd results, but I then Get-Content of the file to do the compare.

# Added this to the beginning of the script
$NullOS = Get-Content C:\Scripts\Logs\Guestfullname.txt
# Added this to the foreach loop section
IF ($OSName -eq $NullOS){$OSName = "Unknown"}

With everything worked out the final script is below.

$debug = $false
$OS_hashtable = $null
$OS_hashtable = @{}
$NullOS = Get-Content C:\Scripts\Logs\Guestfullname.txt
$VMs = Get-VM
Foreach ($VM in $VMs){
    $OSName = $VM.ExtensionData.Guest.GuestFullName
    IF ($OSName -eq $NULL){$OSName = $VM.ExtensionData.Config.GuestFullName}
    IF ($OSName -eq $NullOS){$OSName = "Unknown"}
    IF ($debug){write-host "$VM - $OSName"}
    If(!($OS_hashtable.ContainsKey($OSName))){
        $OS_hashtable.add($OSName,0)
    }
    $Value = $OS_hashtable.$OSName
    $NewValue = $Value + 1
    $OS_hashtable[$osName] = $NewValue
}
$OS_hashtable | FT -AutoSize

This was a fun little script to create.

-Stuart

Leave a Reply

Your email address will not be published. Required fields are marked *

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