<# .SYNOPSIS Comprehensive server hardware and software inventory report .DESCRIPTION Collects system information including CPU, RAM, disk, OS version, installed roles, and key services. Generates Word document (with HTML fallback) similar to Exchange-Inventory.ps1 structure. .PARAMETER OutputFolder Destination folder for reports. Default: .\ServerInventory- .PARAMETER IncludeInstalledSoftware Include installed software list (can be slow, default: $false) .PARAMETER IncludeWindowsFeatures Include Windows Features/Roles (default: $true) .NOTES ⚠️ AI-GENERATED SCRIPT - UNTESTED This script was generated by Claude AI and has not been tested in production. Review and test thoroughly in a non-production environment before use. - Run with Administrator privileges for complete information - Works on Windows Server 2012+ - Report generation uses Word COM or HTML fallback .EXAMPLE .\Get-ServerInventory.ps1 .EXAMPLE .\Get-ServerInventory.ps1 -IncludeInstalledSoftware $true -OutputFolder "D:\Inventory" #> [CmdletBinding()] param( [string]$OutputFolder = (Join-Path -Path (Get-Location) -ChildPath ("ServerInventory-" + (Get-Date -Format "yyyyMMdd-HHmm"))), [bool]$IncludeInstalledSoftware = $false, [bool]$IncludeWindowsFeatures = $true ) function NowTag { (Get-Date).ToString("yyyy-MM-dd HH:mm:ss") } Write-Host "[$(NowTag)] ⚠️ AI-GENERATED SCRIPT - UNTESTED" -ForegroundColor Yellow Write-Host "[$(NowTag)] Starting server inventory..." -ForegroundColor Green # Create output folder New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null $ReportDocx = Join-Path $OutputFolder "Server-Inventory.docx" $ReportHtml = Join-Path $OutputFolder "Server-Inventory.html" # Word COM or HTML fallback (reused pattern from Exchange-Inventory.ps1) $script:Word = $null $script:Doc = $null $script:UseHtml = $false $script:HtmlSb = New-Object System.Text.StringBuilder function Start-Report { try { $script:Word = New-Object -ComObject Word.Application -ErrorAction Stop $script:Word.Visible = $false $script:Doc = $script:Word.Documents.Add() Add-Heading "Server Inventory Report" 1 Add-Paragraph ("Server: $env:COMPUTERNAME") Add-Paragraph ("Generated: " + (Get-Date).ToString("yyyy-MM-dd HH:mm")) } catch { $script:UseHtml = $true [void]$script:HtmlSb.AppendLine("Server Inventory") [void]$script:HtmlSb.AppendLine("") [void]$script:HtmlSb.AppendLine("

Server Inventory Report

") [void]$script:HtmlSb.AppendLine("

Server: $env:COMPUTERNAME

") [void]$script:HtmlSb.AppendLine("

Generated: " + (Get-Date).ToString("yyyy-MM-dd HH:mm") + "

") } } function Add-Heading([string]$Text, [int]$Level = 2) { if ($script:UseHtml) { [void]$script:HtmlSb.AppendLine("$Text") } else { $range = $script:Doc.Range() $range.Collapse(0) | Out-Null $range.Text = "$Text`r" $style = switch ($Level) { 1 { 'Heading 1' } 2 { 'Heading 2' } default { 'Heading 2' } } $range.set_Style($style) $range.InsertParagraphAfter() | Out-Null } } function Add-Paragraph([string]$Text) { if ($script:UseHtml) { $enc = [System.Web.HttpUtility]::HtmlEncode($Text) [void]$script:HtmlSb.AppendLine("

$enc

") } else { $range = $script:Doc.Range() $range.Collapse(0) | Out-Null $range.Text = $Text $range.InsertParagraphAfter() | Out-Null } } function Add-Table([object]$Objects, [string[]]$PropOrder, [string]$Title) { if ($null -eq $Objects) { Add-Paragraph ("{0}: No data." -f $Title) return } $arr = @() if ($Objects -is [System.Collections.IEnumerable] -and -not ($Objects -is [string])) { foreach ($o in $Objects) { $arr += $o } } else { $arr = @($Objects) } if ($arr.Count -eq 0) { Add-Paragraph ("{0}: No data." -f $Title) return } Add-Heading $Title 3 if ($script:UseHtml) { [void]$script:HtmlSb.AppendLine("") foreach ($p in $PropOrder) { [void]$script:HtmlSb.AppendLine("") } [void]$script:HtmlSb.AppendLine("") foreach ($o in $arr) { [void]$script:HtmlSb.AppendLine("") foreach ($p in $PropOrder) { $val = if ($o.$p) { [string]$o.$p } else { "" } [void]$script:HtmlSb.AppendLine("") } [void]$script:HtmlSb.AppendLine("") } [void]$script:HtmlSb.AppendLine("
$([System.Web.HttpUtility]::HtmlEncode($p))
$([System.Web.HttpUtility]::HtmlEncode($val))
") } else { $rows = $arr.Count $cols = $PropOrder.Count $range = $script:Doc.Range() $table = $script:Doc.Tables.Add($range, [Math]::Max(1, $rows) + 1, $cols) for ($c = 1; $c -le $cols; $c++) { $table.Cell(1, $c).Range.Text = $PropOrder[$c - 1] } $table.Rows.Item(1).Range.Bold = $true for ($r = 0; $r -lt $rows; $r++) { for ($c = 0; $c -lt $cols; $c++) { $val = if ($arr[$r].($PropOrder[$c])) { [string]$arr[$r].($PropOrder[$c]) } else { "" } $table.Cell($r + 2, $c + 1).Range.Text = $val } } $table.AutoFitBehavior(2) | Out-Null $range.InsertParagraphAfter() | Out-Null } } function End-Report { if ($script:UseHtml) { [void]$script:HtmlSb.AppendLine("") $script:HtmlSb.ToString() | Out-File -LiteralPath $ReportHtml -Encoding UTF8 Write-Host "[$(NowTag)] HTML report: $ReportHtml" -ForegroundColor Green } else { $wdFormatXMLDocument = 12 $script:Doc.SaveAs([ref]$ReportDocx, [ref]$wdFormatXMLDocument) $script:Doc.Close(); $script:Word.Quit() Write-Host "[$(NowTag)] Word report: $ReportDocx" -ForegroundColor Green } } Start-Report # System Information Write-Host "[$(NowTag)] Collecting system information..." $cs = Get-CimInstance -ClassName Win32_ComputerSystem $os = Get-CimInstance -ClassName Win32_OperatingSystem $bios = Get-CimInstance -ClassName Win32_BIOS $sysInfo = [PSCustomObject]@{ ComputerName = $cs.Name Domain = $cs.Domain Manufacturer = $cs.Manufacturer Model = $cs.Model TotalPhysicalMemoryGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2) NumberOfProcessors = $cs.NumberOfProcessors NumberOfLogicalProcessors = $cs.NumberOfLogicalProcessors OSName = $os.Caption OSVersion = $os.Version OSArchitecture = $os.OSArchitecture InstallDate = $os.InstallDate LastBootUpTime = $os.LastBootUpTime BIOSVersion = $bios.SMBIOSBIOSVersion SerialNumber = $bios.SerialNumber } Add-Heading "System Information" 2 Add-Table $sysInfo @("ComputerName", "Domain", "Manufacturer", "Model", "TotalPhysicalMemoryGB", "NumberOfProcessors", "NumberOfLogicalProcessors", "OSName", "OSVersion", "OSArchitecture", "InstallDate", "LastBootUpTime", "BIOSVersion", "SerialNumber") "System Details" # CPU Information Write-Host "[$(NowTag)] Collecting CPU information..." $cpus = Get-CimInstance -ClassName Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed, CurrentClockSpeed Add-Table $cpus @("Name", "NumberOfCores", "NumberOfLogicalProcessors", "MaxClockSpeed", "CurrentClockSpeed") "Processors" # Disk Information Write-Host "[$(NowTag)] Collecting disk information..." $disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" | Select-Object @{N = "Drive"; E = { $_.DeviceID } }, @{N = "SizeGB"; E = { [math]::Round($_.Size / 1GB, 2) } }, @{N = "FreeGB"; E = { [math]::Round($_.FreeSpace / 1GB, 2) } }, @{N = "UsedGB"; E = { [math]::Round(($_.Size - $_.FreeSpace) / 1GB, 2) } }, @{N = "PercentFree"; E = { [math]::Round(($_.FreeSpace / $_.Size) * 100, 2) } }, VolumeName, FileSystem Add-Table $disks @("Drive", "SizeGB", "FreeGB", "UsedGB", "PercentFree", "VolumeName", "FileSystem") "Disk Drives" # Network Adapters Write-Host "[$(NowTag)] Collecting network adapter information..." $nics = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" | Select-Object Description, @{N = "IPAddress"; E = { $_.IPAddress -join ", " } }, @{N = "SubnetMask"; E = { $_.IPSubnet -join ", " } }, @{N = "DefaultGateway"; E = { $_.DefaultIPGateway -join ", " } }, @{N = "DNSServers"; E = { $_.DNSServerSearchOrder -join ", " } }, MACAddress, DHCPEnabled Add-Table $nics @("Description", "IPAddress", "SubnetMask", "DefaultGateway", "DNSServers", "MACAddress", "DHCPEnabled") "Network Adapters" # Windows Features/Roles if ($IncludeWindowsFeatures) { Write-Host "[$(NowTag)] Collecting Windows features..." try { Import-Module ServerManager -ErrorAction Stop $features = Get-WindowsFeature | Where-Object Installed | Select-Object Name, DisplayName, FeatureType Add-Table $features @("Name", "DisplayName", "FeatureType") "Installed Windows Features/Roles" } catch { Add-Paragraph "Windows Features: Could not retrieve (ServerManager module not available)" } } # Services Write-Host "[$(NowTag)] Collecting critical services..." $services = Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } | Select-Object Name, DisplayName, Status, StartType if ($services) { Add-Table $services @("Name", "DisplayName", "Status", "StartType") "Automatic Services Not Running (Potential Issues)" } else { Add-Paragraph "All automatic services are running" } # Installed Software (optional, can be slow) if ($IncludeInstalledSoftware) { Write-Host "[$(NowTag)] Collecting installed software (this may take a while)..." $software = Get-CimInstance -ClassName Win32_Product | Select-Object Name, Version, Vendor, InstallDate | Sort-Object Name Add-Table $software @("Name", "Version", "Vendor", "InstallDate") "Installed Software" } # Hotfixes Write-Host "[$(NowTag)] Collecting installed hotfixes..." $hotfixes = Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 20 | Select-Object HotFixID, Description, InstalledBy, InstalledOn Add-Table $hotfixes @("HotFixID", "Description", "InstalledBy", "InstalledOn") "Recent Hotfixes (Last 20)" End-Report Write-Host "[$(NowTag)] Inventory complete! Output folder: $OutputFolder"