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
Comments
Anonymous
July 22, 2014
Windows 7 and windows 2008 R2 have both 6.1.7601. How do I make out the difference?Anonymous
July 22, 2014
The description should list out the OS name, specifically the .OperatingSystem property.Anonymous
November 20, 2014
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
Anonymous
November 20, 2014
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.Anonymous
November 23, 2014
The comment has been removed