Public/Sync-LinuxInventory.ps1
|
function Sync-LinuxInventory { <# .SYNOPSIS Pings all registered Linux servers and reports their online/offline status. .DESCRIPTION Queries the Linux server OU and pings each registered server to check connectivity. Optionally updates each server's AD description with a last-seen or offline-since timestamp. This provides a lightweight, agent-free health check that works through most firewalls since it uses ICMP (ping). .PARAMETER OrganizationalUnit OU to query. Defaults to "OU=Linux Servers" under the domain root. .PARAMETER TimeoutMs Ping timeout in milliseconds. Defaults to 1000. .PARAMETER UpdateDescription When specified, appends a timestamp tag to the AD description: - Online: "[Last Seen: yyyy-MM-dd HH:mm]" - Offline: "[OFFLINE since: yyyy-MM-dd HH:mm]" .EXAMPLE Sync-LinuxInventory Pings all Linux servers and returns online/offline status. .EXAMPLE Sync-LinuxInventory -UpdateDescription Pings all servers and stamps their AD description with the result. .EXAMPLE Sync-LinuxInventory -TimeoutMs 2000 | Where-Object { -not $_.Online } Returns only offline servers with a 2-second timeout. .EXAMPLE Sync-LinuxInventory | Format-Table Name, IPAddress, Online, ResponseTime Quick table view of connectivity status. .NOTES Requires: ActiveDirectory module (RSAT). ICMP must be allowed through the host firewall for ping to succeed. #> [CmdletBinding()] param( [string]$OrganizationalUnit, [int]$TimeoutMs = 1000, [switch]$UpdateDescription ) begin { Import-Module ActiveDirectory -ErrorAction Stop if (-not $OrganizationalUnit) { $domainDN = (Get-ADDomain).DistinguishedName $OrganizationalUnit = "OU=Linux Servers,$domainDN" } $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm' } process { # Verify the OU exists try { $null = Get-ADOrganizationalUnit -Identity $OrganizationalUnit -ErrorAction Stop } catch { Write-Warning "OU not found: $OrganizationalUnit. No Linux servers registered yet." return } $computers = Get-ADComputer -SearchBase $OrganizationalUnit -Filter * ` -Properties IPv4Address, DNSHostName, Description, OperatingSystem ` -ErrorAction Stop if (-not $computers) { Write-Verbose "No computer objects found in $OrganizationalUnit" return } $results = [System.Collections.Generic.List[PSCustomObject]]::new() $onlineCount = 0 $offlineCount = 0 foreach ($comp in $computers) { $target = if ($comp.IPv4Address) { $comp.IPv4Address } else { $comp.DNSHostName } $isOnline = $false $responseTime = $null if ($target) { Write-Verbose "Pinging $($comp.Name) ($target) with ${TimeoutMs}ms timeout..." try { # PowerShell 5.1 compatible: Test-Connection with -Count 1 $pingResult = Test-Connection -ComputerName $target -Count 1 -ErrorAction SilentlyContinue if ($pingResult) { $isOnline = $true $responseTime = if ($pingResult.ResponseTime) { $pingResult.ResponseTime } else { $pingResult.Latency } } } catch { Write-Verbose "Ping failed for $($comp.Name): $_" } } else { Write-Verbose "No IP or DNS name for $($comp.Name) -- marking offline." } if ($isOnline) { $onlineCount++ } else { $offlineCount++ } # Update the AD description with timestamp if requested if ($UpdateDescription) { $currentDesc = $comp.Description # Strip any existing timestamp tag $cleanDesc = if ($currentDesc) { ($currentDesc -replace '\s*\[(Last Seen|OFFLINE since):.*?\]\s*$', '').Trim() } else { '' } $tag = if ($isOnline) { "[Last Seen: $timestamp]" } else { "[OFFLINE since: $timestamp]" } $newDesc = if ($cleanDesc) { "$cleanDesc $tag" } else { $tag } try { Set-ADComputer -Identity $comp.Name -Description $newDesc -ErrorAction Stop Write-Verbose "Updated description for $($comp.Name): $tag" } catch { Write-Warning "Failed to update description for $($comp.Name): $_" } } $results.Add([PSCustomObject]@{ Name = $comp.Name IPAddress = $comp.IPv4Address Online = $isOnline ResponseTime = $responseTime LastSeen = if ($isOnline) { $timestamp } else { $null } }) } Write-Verbose "Sync complete -- Online: $onlineCount, Offline: $offlineCount" $results } } |