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

Comments (5)

  1. Gregor says:

    Windows 7 and windows 2008 R2 have both 6.1.7601.

    How do I make out the difference?

  2. rslaten says:

    The description should list out the OS name, specifically the .OperatingSystem property.

  3. Update - Need help says:

    Thanks much for the script. This is almosst what i need.

    I've tried alot but mu attempts were futile with my limited knowledge on powershell 🙁

    We have multiple forests . Can you please help identify the domain name as well.

    Alpha.local

    —————-

    Windows2003R2 , 45

    Windows2012 , 56

    Windows 7 , 98

    gama.alpha.local

    ————————

    Windows2003R2 , 45

    Windows2012 , 56

    Windows 7 , 98

    Windows 2000 ,  3

  4. rslaten says:

    If you run it from a machine within each forest that should list out everything. You could make modifications to the script that would list out more information, this is just one that I used for a specific scenario in a single forest.

  5. Anand Rao says:

    Thanks  Russ,

    I've been able to get around it by adding Foreach in the domains loop. That gets me the output per domain with domain name

    foreach ($DNDOmains in $domains)

    {

    #Get hash table of domains and distinguished names from current forest

    $DNs = GetDNs -domains $DNDOmains

    #Get OS counts per domain (specify age here)

    $OSCounts = GetOSCountsPerDomain -dns $DNs # -enabled $true -daysOld 30

    $Banner = "Domain Name"| out-file $log -append

    $BannerU = "============"| out-file $log -append

    $DNDOmains | out-file $log -append

    #Display Results

    DisplayOutput -osCounts $OSCounts | out-file $log -append

    }