Files
PowerShell-scripts/Misc/Get-ServerInventory.ps1
Martien de Kleijn 62134801aa Add 12 AI-generated PowerShell scripts with documentation
⚠️ IMPORTANT: These scripts are AI-GENERATED and UNTESTED

Exchange Scripts (5):
- Get-MailboxPermissions.ps1: Audit delegate access permissions
- Get-InactiveMailboxes.ps1: Identify stale mailboxes
- Compare-MailboxDatabases.ps1: Database health comparison
- Export-DistributionGroups.ps1: Distribution group inventory
- Get-MailflowStats.ps1: Transport log analysis

Active Directory Scripts (3):
- Get-ADUserLastLogon.ps1: True LastLogon across all DCs
- Export-OUStructure.ps1: OU hierarchy with GPO links
- Compare-ADGroupMemberships.ps1: Compare user group memberships

System Maintenance Scripts (4):
- Get-ServerInventory.ps1: Hardware/software inventory report
- Monitor-DiskSpace.ps1: Disk space monitoring with alerts
- Backup-ExchangeCertificates.ps1: Certificate backup to PFX
- Test-ExchangeHealth.ps1: Aggregated Exchange health checks

Documentation:
- Updated CLAUDE.md with AI-generated scripts section
- Added AI-GENERATED-SCRIPTS.md with warnings and testing guide

All scripts include prominent warnings and follow established patterns
from existing scripts. Require thorough testing before production use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-15 10:52:44 +02:00

239 lines
11 KiB
PowerShell

<#
.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-<date>
.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("<html><head><meta charset='utf-8'><title>Server Inventory</title>")
[void]$script:HtmlSb.AppendLine("<style>body{font-family:Segoe UI,Arial,sans-serif;margin:20px} h1{font-size:24px;color:#0066cc} h2{font-size:20px;margin-top:30px;color:#333} table{border-collapse:collapse;width:100%;margin:15px 0} th,td{border:1px solid #ccc;padding:8px;text-align:left} th{background:#f3f3f3;font-weight:bold}</style></head><body>")
[void]$script:HtmlSb.AppendLine("<h1>Server Inventory Report</h1>")
[void]$script:HtmlSb.AppendLine("<p><strong>Server:</strong> $env:COMPUTERNAME</p>")
[void]$script:HtmlSb.AppendLine("<p><strong>Generated:</strong> " + (Get-Date).ToString("yyyy-MM-dd HH:mm") + "</p>")
}
}
function Add-Heading([string]$Text, [int]$Level = 2) {
if ($script:UseHtml) {
[void]$script:HtmlSb.AppendLine("<h$Level>$Text</h$Level>")
} 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("<p>$enc</p>")
} 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("<table><thead><tr>")
foreach ($p in $PropOrder) { [void]$script:HtmlSb.AppendLine("<th>$([System.Web.HttpUtility]::HtmlEncode($p))</th>") }
[void]$script:HtmlSb.AppendLine("</tr></thead><tbody>")
foreach ($o in $arr) {
[void]$script:HtmlSb.AppendLine("<tr>")
foreach ($p in $PropOrder) {
$val = if ($o.$p) { [string]$o.$p } else { "" }
[void]$script:HtmlSb.AppendLine("<td>$([System.Web.HttpUtility]::HtmlEncode($val))</td>")
}
[void]$script:HtmlSb.AppendLine("</tr>")
}
[void]$script:HtmlSb.AppendLine("</tbody></table>")
} 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("</body></html>")
$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"