What it does...

This function I wrote will return an object which contains the unique name of each OS for guests on a vCenter server. It will also show you the total number of VMs with that OS.

What it needs to run...

This function takes the parameter $vCenter. This should be the name of a vCenter server in your environment. You can also call the function as part of a foreach loop if you have multiple vCenter servers, running it once for each server and then returning that into another variable.

The Code:

function Get-VMOSList {
    Connect-VIServer $vCenter  | Out-Null
    [array]$osNameObject       = $null
    $vmHosts                   = Get-VMHost
    $i = 0
    foreach ($h in $vmHosts) {
        Write-Progress -Activity "Going through each host in $vCenter..." -Status "Current Host: $h" -PercentComplete ($i/$vmHosts.Count*100)
        $osName = ($h | Get-VM | Get-View).Summary.Config.GuestFullName
        [array]$guestOSList += $osName
        Write-Verbose "Found OS: $osName"
    $names = $guestOSList | Select-Object -Unique
    $i = 0
    foreach ($n in $names) { 
        Write-Progress -Activity "Going through VM OS Types in $vCenter..." -Status "Current Name: $n" -PercentComplete ($i/$names.Count*100)
        $vmTotal = ($guestOSList | ?{$_ -eq $n}).Count
        $osNameProperty  = @{'Name'=$n} 
        $osNameProperty += @{'Total VMs'=$vmTotal}
        $osNameProperty += @{'vCenter'=$vcenter}
        $osnO             = New-Object PSObject -Property $osNameProperty
        $osNameObject     += $osnO
    Disconnect-VIserver -force -confirm:$false
    Return $osNameObject

Here is some example output (I tested it within another script I wrote). 
I blacked out the vCenter server name for security reasons.


Here is an example of the code I use to wrap it:

In this example the variables that already exist are:

$vCenterServers (this is an array of my vCenter servers)
$vCenter              (this is a parameter of my main script, the value of "all" is what the example below shows)
$getGuestOSList (this is a boolean parameter my script uses. What you see below is what happens if it is $true)

The below code will go through each of the individual vCenter servers and use the function above to build the variable $guestOSObjects with the output.

if (Get-View $DefaultViserver.ExtensionData.Client.ServiceContent.SessionManager) {Disconnect-VIServer * -confirm:$false -force;Write-Host "Disconnecting VI Server Sessions" -foregroundColor $foregroundColor}

if ($getGuestOSList) {
    Switch ($vCenter) {
    {$_ -like "all"} {
        $i = 0
        Foreach ($v in $vCenterServers) {
            $vCenter = $vcenterServers[$i]
            Write-Progress -Activity "Looking up VM Guests" -Status "Current vCenter Server: $vCenter" -PercentComplete ($i/$vCenterServers.Count*100)
            [array]$GuestOSObjects += Get-VMOSList $vCenter
    Return $guestOSOBjects