Public/Get-LinuxInventory.ps1

function Get-LinuxInventory {
    <#
    .SYNOPSIS
        Lists all registered Linux servers from the Active Directory OU.
 
    .DESCRIPTION
        Queries the target OU for all computer objects and returns their registration
        details. Optionally pings each server to check online status, and can generate
        a dark-themed HTML dashboard report.
 
    .PARAMETER OrganizationalUnit
        OU to query. Defaults to "OU=Linux Servers" under the domain root.
 
    .PARAMETER Online
        Ping each server to determine online/offline status. Adds an Online property
        (True/False) and ResponseTime (ms) to the output.
 
    .PARAMETER OutputPath
        If specified, generates an HTML dashboard report at this file path.
 
    .EXAMPLE
        Get-LinuxInventory
 
        Lists all Linux servers in the default OU.
 
    .EXAMPLE
        Get-LinuxInventory -Online | Format-Table
 
        Lists servers with live ping status in a table.
 
    .EXAMPLE
        Get-LinuxInventory -Online -OutputPath .\Reports\linux-inventory.html
 
        Generates an HTML dashboard with online/offline status.
 
    .EXAMPLE
        Get-LinuxInventory | Where-Object OperatingSystem -like '*Ubuntu*'
 
        Filters to Ubuntu servers only.
 
    .NOTES
        Requires: ActiveDirectory module (RSAT).
        The -Online switch uses Test-Connection (ICMP) which may be blocked by firewalls.
    #>

    [CmdletBinding()]
    param(
        [string]$OrganizationalUnit,

        [switch]$Online,

        [string]$OutputPath
    )

    begin {
        Import-Module ActiveDirectory -ErrorAction Stop

        if (-not $OrganizationalUnit) {
            $domainDN = (Get-ADDomain).DistinguishedName
            $OrganizationalUnit = "OU=Linux Servers,$domainDN"
        }
    }

    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
        }

        $properties = @(
            'Name', 'DNSHostName', 'IPv4Address', 'OperatingSystem',
            'OperatingSystemVersion', 'Description', 'ManagedBy',
            'Created', 'Modified', 'Enabled'
        )

        $computers = Get-ADComputer -SearchBase $OrganizationalUnit -Filter * `
            -Properties $properties -ErrorAction Stop

        if (-not $computers) {
            Write-Verbose "No computer objects found in $OrganizationalUnit"
            return
        }

        $results = [System.Collections.Generic.List[PSCustomObject]]::new()

        foreach ($comp in $computers) {
            $obj = [PSCustomObject]@{
                Name                   = $comp.Name
                DNSHostName            = $comp.DNSHostName
                IPv4Address            = $comp.IPv4Address
                OperatingSystem        = $comp.OperatingSystem
                OperatingSystemVersion = $comp.OperatingSystemVersion
                Description            = $comp.Description
                ManagedBy              = $comp.ManagedBy
                Created                = $comp.Created
                Modified               = $comp.Modified
                Online                 = $null
                ResponseTime           = $null
            }

            if ($Online) {
                Write-Verbose "Pinging $($comp.Name) ($($comp.IPv4Address))..."
                $target = if ($comp.IPv4Address) { $comp.IPv4Address } else { $comp.DNSHostName }

                if ($target) {
                    try {
                        $ping = Test-Connection -ComputerName $target -Count 1 -Quiet -ErrorAction SilentlyContinue
                        $obj.Online = $ping

                        if ($ping) {
                            $detail = Test-Connection -ComputerName $target -Count 1 -ErrorAction SilentlyContinue
                            $obj.ResponseTime = if ($detail.ResponseTime) { $detail.ResponseTime } else { $detail.Latency }
                        }
                    }
                    catch {
                        $obj.Online = $false
                        Write-Verbose "Ping failed for $($comp.Name): $_"
                    }
                }
                else {
                    $obj.Online = $false
                    Write-Verbose "No IP or DNS name for $($comp.Name) -- marking offline."
                }
            }

            $results.Add($obj)
        }

        Write-Verbose "Found $($results.Count) Linux servers in $OrganizationalUnit"

        # Generate HTML report if requested
        if ($OutputPath) {
            $reportDir = Split-Path -Path $OutputPath -Parent
            if ($reportDir -and -not (Test-Path $reportDir)) {
                New-Item -Path $reportDir -ItemType Directory -Force | Out-Null
            }

            $html = New-HtmlDashboard -ServerData $results -OrganizationalUnit $OrganizationalUnit
            $html | Out-File -FilePath $OutputPath -Encoding UTF8 -Force
            Write-Verbose "HTML report saved: $OutputPath"
        }

        $results
    }
}