Public/Get-IP.ps1

function Get-IP {
    <#
.SYNOPSIS
    Displays a colorful, formatted table of network adapters (name, MAC, IP, DHCP status, gateway, DNS, etc.).
 
.DESCRIPTION
    Shows all network adapters in a nicely aligned console table with colors.
    Works in PowerShell 5.1 legacy console (powershell.exe) and modern hosts.
    Uses native console color API — no ANSI escapes.
 
.PARAMETER UpOnly
    Show only adapters where Status is 'Up'
 
.PARAMETER SortBy
    Column to sort by. Default: Description (descending)
 
.PARAMETER Descending
    Sort in descending order. Default: $true when SortBy = Description
 
.EXAMPLE
    Get-IP
 
.EXAMPLE
    Get-IP -UpOnly
 
.EXAMPLE
    Get-IP -SortBy Name -Descending:$false
#>

    [CmdletBinding()]
    [Alias('IP')]
    param(
        [switch] $UpOnly,

        [ValidateSet('Name', 'MAC', 'Description', 'Speed', 'Lnk', 'IPv4_Subnet', 'AddrType')]
        [string] $SortBy = 'Description',

        [switch] $Descending = $true
    )

    # ============================================================================
    # Helper Functions
    # ============================================================================

    function Write-ColorLine {
        <#
    .SYNOPSIS
        Writes one adapter row, correctly handling multi-line values in any column.
        Uses $columnWidths for alignment.
    #>

        [CmdletBinding()]
        param(
            [Parameter(Mandatory)]
            [PSCustomObject] $Adapter
        )

        # ================================================
        # Step 1: Split every field into lines (even single-line becomes 1-element array)
        # ================================================

        $lines = @{
            Name        = @([string]$Adapter.Name -split "`r`n|`n")
            MAC         = @([string]$Adapter.MAC -split "`r`n|`n")
            Description = @([string]$Adapter.Description -split "`r`n|`n")
            Speed       = @([string]$Adapter.Speed -split "`r`n|`n")
            Lnk         = @([string]$Adapter.Lnk -split "`r`n|`n")
            IPv4_Subnet = @([string]$Adapter.IPv4_Subnet -split "`r`n|`n")
            AddrType    = @([string]$Adapter.AddrType -split "`r`n|`n")
            Gateway     = @([string]$Adapter.Gateway -split "`r`n|`n")
            DNS_Servers = @([string]$Adapter.DNS_Servers -split "`r`n|`n")
        }

        # ================================================
        # Step 2: Find the maximum number of lines in this row
        # ================================================

        $maxLines = 1
        foreach ($key in $lines.Keys) {
            $count = $lines[$key].Count
            if ($count -gt $maxLines) { $maxLines = $count }
        }

        # ================================================
        # Step 3: Write one visual row per line index
        # ================================================

        for ($i = 0; $i -lt $maxLines; $i++) {
            # Name (Cyan)
            $text = if ($i -lt $lines.Name.Count) { $lines.Name[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.Name) -ForegroundColor Cyan -NoNewline

            # MAC (Magenta)
            $text = if ($i -lt $lines.MAC.Count) { $lines.MAC[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.MAC) -ForegroundColor Magenta -NoNewline

            # Description (Gray)
            $text = if ($i -lt $lines.Description.Count) { $lines.Description[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.Description) -ForegroundColor Gray -NoNewline

            # Speed (Yellow)
            $text = if ($i -lt $lines.Speed.Count) { $lines.Speed[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.Speed) -ForegroundColor Yellow -NoNewline

            # Lnk / Status (Green)
            $text = if ($i -lt $lines.Lnk.Count) { $lines.Lnk[$i] } else { '' }
            $color = if ($text -eq "Up") { [ConsoleColor]::Green } else { [ConsoleColor]::Red }
            Write-Host $text.PadRight($columnWidths.Lnk) -ForegroundColor $color -NoNewline

            # IPv4_Subnet (Cyan)
            $text = if ($i -lt $lines.IPv4_Subnet.Count) { $lines.IPv4_Subnet[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.IPv4_Subnet) -ForegroundColor Cyan -NoNewline

            # AddrType (already colored string)
            $text = if ($i -lt $lines.AddrType.Count) { $lines.AddrType[$i] } else { '' }
            $color = if ($text -eq "DHCP") { [ConsoleColor]::Green } else { [ConsoleColor]::Gray }
            Write-Host $text.PadRight($columnWidths.AddrType) -ForegroundColor $color -NoNewline

            # Gateway (Yellow)
            $text = if ($i -lt $lines.Gateway.Count) { $lines.Gateway[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.Gateway) -ForegroundColor Yellow -NoNewline

            # DNS_Servers (Magenta)
            $text = if ($i -lt $lines.DNS_Servers.Count) { $lines.DNS_Servers[$i] } else { '' }
            Write-Host $text.PadRight($columnWidths.DNS_Servers) -ForegroundColor Magenta -NoNewline

            # End of visual row
            Write-Host ""   # new line after each visual row
        }
    }


    # ============================================================================
    # Main Logic - Collect adapters
    # ============================================================================

    $adapters = Get-NetAdapter | 
    # Where-Object { $_.Status -eq 'Up' } | # uncomment to filter only Up
    ForEach-Object {
        $adapter = $_

        # MAC formatting
        $MACraw = $adapter.MacAddress
        $MAC = if ($MACraw) { 
            $MACraw = $MACraw -replace '-', ':'
            $MACraw -replace ':', ''
        }
        else { '<virtual>' }

        $ipConfig = Get-NetIPConfiguration -InterfaceAlias $adapter.Name -Detailed -ErrorAction SilentlyContinue 2>$null

        # All IPv4 addresses (array)
        $ipv4Addresses = $ipConfig.IPv4Address | 
        Where-Object { $_.AddressFamily -eq 'IPv4' } | 
        ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" }

        # Status shorthand
        $Lnk = if ($adapter.Status -eq "Disconnected") { "Dwn" } else { $adapter.Status }

        # DHCP / Static
        $addrTypeRaw = if ($ipConfig.NetIPv4Interface.Dhcp -eq 'Enabled') { 'DHCP' } else { 'Static' }

        [PSCustomObject]@{
            Name        = $adapter.Name
            MAC         = $MAC
            Description = $adapter.InterfaceDescription
            Speed       = $adapter.LinkSpeed -replace ' ', ''
            Lnk         = $Lnk
            IPv4_Subnet = if ($ipv4Addresses) { $ipv4Addresses -join "`n" } else { '<none>' }
            AddrType    = $addrTypeRaw
            Gateway     = ($ipConfig.IPv4DefaultGateway | Select-Object -First 1).NextHop
            DNS_Servers = ($ipConfig.DNSServer | Where-Object AddressFamily -eq 2 | Select-Object -ExpandProperty ServerAddresses) -join "`n"
        }
    }

    # ============================================================================
    # Calculate automatic column widths (scan all rows)
    # ============================================================================

    $columnWidths = @{
        Name        = 4   # minimum
        MAC         = 3
        Description = 11
        Speed       = 5
        Lnk         = 3
        IPv4_Subnet = 9    # '<none>'
        AddrType    = 6
        Gateway     = 7
        DNS_Servers = 10
    }
    
    foreach ($a in $adapters) {
        # Name
        if ($a.Name.Length -gt $columnWidths.Name) { $columnWidths.Name = $a.Name.Length }
        # MAC
        if ($a.MAC.Length -gt $columnWidths.MAC) { $columnWidths.MAC = $a.MAC.Length }
        # Description
        if ($a.Description.Length -gt $columnWidths.Description) { $columnWidths.Description = $a.Description.Length }
        # Speed
        if ($a.Speed.Length -gt $columnWidths.Speed) { $columnWidths.Speed = $a.Speed.Length }
        # Lnk
        if ($a.Lnk.Length -gt $columnWidths.Lnk) { $columnWidths.Lnk = $a.Lnk.Length }
        # AddrType
        if ($a.AddrType.Length -gt $columnWidths.AddrType) { $columnWidths.AddrType = $a.AddrType.Length }
        # Gateway
        if ($a.Gateway.Length -gt $columnWidths.Gateway) { $columnWidths.Gateway = $a.Gateway.Length }
        # DNS_Servers - longest line
        $dnsLines = $a.DNS_Servers -split "`n"
        foreach ($line in $dnsLines) {
            if ($line.Length -gt $columnWidths.DNS_Servers) { $columnWidths.DNS_Servers = $line.Length }
        }
        # IPv4_Subnet - longest line (after we pad internally)
        $ipLines = $a.IPv4_Subnet -split "`n"
        foreach ($line in $ipLines) {
            # Strip ANSI if any (though we don't use ANSI anymore)
            $cleanLine = $line -replace '\x1B\[[0-9;]*m', ''
            if ($cleanLine.Length -gt $columnWidths.IPv4_Subnet) {
                $columnWidths.IPv4_Subnet = $cleanLine.Length
            }
        }
    }

    # ============================================================================
    # Pad IPv4_Subnet so slashes align (multi-line aware)
    # ============================================================================

    $maxIpPartLength = 0
    foreach ($a in $adapters) {
        $lines = $a.IPv4_Subnet -split "`n"
        foreach ($line in $lines) {
            if ($line -match '^([^/]+)') {
                $len = $Matches[1].Length
                if ($len -gt $maxIpPartLength) { $maxIpPartLength = $len }
            }
            elseif ($line.Length -gt $maxIpPartLength) {
                $maxIpPartLength = $line.Length
            }
        }
    }

    $adapters = $adapters | ForEach-Object {
        $lines = $_.IPv4_Subnet -split "`n"
        $padded = @()
        foreach ($line in $lines) {
            if ($line -match '^([^/]+)(/.*)?$') {
                $ip = $Matches[1]
                $rest = if ($Matches[2]) { $Matches[2] } else { '' }
                $pad = ' ' * ($maxIpPartLength - $ip.Length)
                $padded += $ip + $pad + $rest
            }
            else {
                $pad = ' ' * ($maxIpPartLength - $line.Length)
                $padded += $pad + $line
            }
        }
        $_.IPv4_Subnet = $padded -join "`n"
        $_
    }

    # ============================================================================
    # Output - Header + Data Rows
    # ============================================================================

    # Clear-Host
    Write-Host ""

    # Header
    Write-Host ("{0,-$($columnWidths.Name-1)} {1,-$($columnWidths.MAC-1)} {2,-$($columnWidths.Description-1)} {3,-$($columnWidths.Speed-1)} {4,-$($columnWidths.Lnk-1)} {5,-$($columnWidths.IPv4_Subnet-2)} {6,-$($columnWidths.AddrType-1)} {7,-$($columnWidths.Gateway-1)} {8}" -f 
        "Name", "MAC", "Description", "Speed", "Lnk", "IPv4_Subnet", "DHCP?", "Gateway", "DNS_Servers") `
        -ForegroundColor White

    Write-Host ("-" * ($columnWidths.Values | Measure-Object -Sum).Sum) -ForegroundColor DarkGray

    # Data
    foreach ($a in ($adapters | Sort-Object Description -Descending)) {
        Write-ColorLine -Adapter $a
        Write-Host ""
    }
}

Export-ModuleMember -Function Get-IP -Alias IP