Get Counts of all Operating Systems in a Forest Per Domain

I was recently asked to get the count of all Windows XP systems in a forest. I decided to do a bit more work and make a modular script that gets all the operating systems and lists the count of each one for every domain in a forest. This version of the script only gets computers where the account is enabled and PwdLastSet has been modified in the last 30 days.

Requirements

Remote Server Administration Tools (RSAT)

  • For desktop OS’s download RSAT
  • For server OS’s use Add-WindowsFeature RSAT-AD-PowerShell. *Note, the script will try to install this feature if it isn’t already installed, but it only works for server OS’s.

Instructions

From a domain joined machine simply open PowerShell (as an admin if you want it to automatically add the RSAT role) and run the script .\GetForestOSCounts.ps1.

Output

*Each "dot” after Getting Data represents a domain, so in large forests this may take a while to run

Getting Data………

west.contoso.com

Name Value
Windows 8 Pro – 6.2 (9200) 5,000
Windows 7 Enterprise – 6.1 (7600) 2,200
Windows 7 Professional – 6.1 (7601) 650
Windows Server 2012 R2 Datacenter – 6.3 (9600) 200
Windows Server 2008 R2 Enterprise – 6.1 (7600) 75

east.contoso.com

Name Value
Windows 8 Pro – 6.2 (9200) 10,000
Windows 7 Enterprise – 6.1 (7600) 2,800
Windows 7 Professional – 6.1 (7601) 1,500
Windows Server 2012 R2 Datacenter – 6.3 (9600) 20
Windows Server 2008 R2 Enterprise – 6.1 (7600) 5

central.contoso.com

Name Value
Windows 8 Pro – 6.2 (9200) 1,000
Windows 7 Enterprise – 6.1 (7600) 600
Windows 7 Professional – 6.1 (7601) 500
Windows Server 2012 R2 Datacenter – 6.3 (9600) 150
Windows Server 2008 R2 Enterprise – 6.1 (7600) 50

Code

 #Functions
function ImportADModule
{
  Import-Module ActiveDirectory
  if (!($?))
  { 
    #Only works for Windows Server OS with PS running as admin, download RSAT if using desktop OS
    Add-WindowsFeature RSAT-AD-PowerShell
    Import-Module ActiveDirectory
  }
}

function GetDN
{
  param($domain)
  $names = $domain.Split(".")
  $bFirst = $true
  foreach ($name in $names)
  {
    if ($bFirst)
    {
      $dn += "DC=" + $name
      $bFirst = $false
    }
    else { $dn += ",DC=" + $name }
  }
  return $dn
}

function GetDNs
{
  param($domains)
  $dns = @{}
  foreach ($domain in $domains)
  {
    $dns.Add($domain, (GetDN -domain $domain))
  }
  return $dns
}

function GetOSCountsPerDomain
{
  param($dns, $enabled, $daysOld)
  $osCounts = @{}
  $cutOffDate = ((Get-Date).Adddays(-($daysOld))).ToFileTime()
  Write-Host "Getting Data" -NoNewline -ForegroundColor Yellow

  $filter = "(PwdLastSet -gt {0}) -and (Enabled -eq '{1}')" -f $cutOffDate, $enabled
  foreach ($domain in $dns.GetEnumerator())
  {
    $i = 0
    $domains = @{}
    Write-Host "." -NoNewline -ForegroundColor Yellow
    $computers = Get-ADComputer -Filter $filter -SearchBase $domain.Value -Server $domain.Key -Properties OperatingSystem, OperatingSystemVersion
    foreach ($computer in $computers)
    {
      if ($computer.OperatingSystem -eq $null) { $os = 'NULL'}
      else { $os = $computer.OperatingSystem }
      if ($computer.OperatingSystemVersion -eq $null) { $osver = 'NULL'}
      else { $osver = $computer.OperatingSystemVersion }
      try { $domains.Add(($os + " - " + $osver), 1) }
      catch { $domains.Set_Item(($os + " - " + $osver), ($domains.Get_Item($os + " - " + $osver))+1) }
    }
    $osCounts.Add($domain.Key, $domains)
  }
  Write-Host
  return $osCounts
}

function DisplayOutput
{
  param($osCounts)
  Write-Host
  foreach ($osCount in $osCounts.GetEnumerator())
  {
    Write-Host $OSCount.Key -ForegroundColor Green
    $osCount.Value.GetEnumerator() | Sort-Object Value -Descending | Format-Table -AutoSize
  }
}

#Main

#Import AD Module for PowerShell
ImportADModule

#Get list of domains from current forest
$Domains = (Get-ADForest).domains

#Get hash table of domains and distinguished names from current forest
$DNs = GetDNs -domains $Domains

#Get OS counts per domain (specify age here)
$OSCounts = GetOSCountsPerDomain -dns $DNs -enabled $true -daysOld 30

#Display Results
DisplayOutput -osCounts $OSCounts

GetForestOSCounts.renametops1