Public/07_Printing_Shares/Get-VBPrintServerInventory.ps1

# ============================================================
# FUNCTION : Get-VBPrintServerInventory
# VERSION : 1.0.1
# CHANGED : 12-05-2026 -- Wrapped in function to prevent autorun on module import
# AUTHOR : Vibhu Bhatnagar
# PURPOSE : Collects all printer details from the local print server and
# produces a full inventory report plus a migration-ready CSV
# Main purpose of this script is to collect all the require info for printer migration
# ENCODING : UTF-8 with BOM
# RUN ON : Print server (local, elevated)
# ============================================================

#Requires -RunAsAdministrator
#Requires -Version 5.1

function Get-VBPrintServerInventory {
    [CmdletBinding()]
    param(
        [string]$OutputFolder = 'C:\Temp'
    )

    #region --- Setup ---

    if (-not (Test-Path $OutputFolder)) {
        New-Item -Path $OutputFolder -ItemType Directory -Force | Out-Null
    }

    $ServerName       = $env:COMPUTERNAME
    $Timestamp        = Get-Date -Format 'yyyyMMdd_HHmmss'
    $InventoryCsv     = Join-Path $OutputFolder "PrinterInventory_${ServerName}_${Timestamp}.csv"
    $MigrationCsv     = Join-Path $OutputFolder "PrinterMigration_${ServerName}_${Timestamp}.csv"
    $Results          = [System.Collections.Generic.List[object]]::new()

    Write-Host "`n Print Server Inventory -- $ServerName" -ForegroundColor Cyan
    Write-Host " $(Get-Date -Format 'dd-MM-yyyy HH:mm:ss')`n" -ForegroundColor Gray

    #endregion

    #region --- Collect Data ---

    Write-Host " Querying printers and ports..." -ForegroundColor Gray

    try {
        $AllPrinters = Get-Printer -ErrorAction Stop
    }
    catch {
        Write-Error "Failed to query printers: $_"
        return
    }

    $AllPorts = Get-PrinterPort -ErrorAction SilentlyContinue

    foreach ($Printer in $AllPrinters) {

        $Port      = $AllPorts | Where-Object { $_.Name -eq $Printer.PortName }
        $PortType  = 'Other'
        $IPAddress = $null
        $IPStatus  = 'Unresolved'

        # --- Determine port type and IP ---
        if ($Printer.PortName -match '^WSD-') {

            $PortType = 'WSD'

            # Attempt 1: DNS resolution of printer device name
            $IPAddress = try {
                [System.Net.Dns]::GetHostAddresses($Printer.Name) |
                    Where-Object { $_.AddressFamily -eq 'InterNetwork' } |
                    Select-Object -First 1 -ExpandProperty IPAddressToString
            }
            catch { $null }

            # Attempt 2: Ping and read IPv4 response
            if (-not $IPAddress) {
                $Ping = Test-Connection -ComputerName $Printer.Name -Count 1 -ErrorAction SilentlyContinue
                if ($Ping) {
                    $IPAddress = $Ping.IPV4Address.IPAddressToString
                }
            }

            $IPStatus = if ($IPAddress) { 'Resolved' } else { 'Unresolved -- assign static IP' }
        }
        elseif ($Port -and $Port.PrinterHostAddress) {
            $PortType  = 'TCP/IP'
            $IPAddress = $Port.PrinterHostAddress
            $IPStatus  = 'Resolved'
        }
        elseif ($Printer.PortName -match '^USB') {
            $PortType = 'USB'
            $IPStatus = 'N/A -- local port'
        }
        elseif ($Printer.PortName -match '^(LPT|COM)') {
            $PortType = 'Local'
            $IPStatus = 'N/A -- local port'
        }

        # --- Build UNC path ---
        $UNCPath = if ($Printer.Shared -and $Printer.ShareName) {
            "\\$ServerName\$($Printer.ShareName)"
        }
        elseif ($Printer.Shared) {
            "\\$ServerName\$($Printer.Name)"
        }
        else {
            'Not shared'
        }

        $Results.Add([PSCustomObject]@{
            ServerName   = $ServerName
            PrinterName  = $Printer.Name
            ShareName    = if ($Printer.ShareName) { $Printer.ShareName } else { '—' }
            UNCPath      = $UNCPath
            DriverName   = $Printer.DriverName
            PortName     = $Printer.PortName
            PortType     = $PortType
            IPAddress    = if ($IPAddress) { $IPAddress } else { '—' }
            IPStatus     = $IPStatus
            Shared       = $Printer.Shared
            Published    = $Printer.Published
            InfPath      = $Printer.InfPath
        })
    }

    #endregion

    #region --- Display Report ---

    Write-Host "`n ── Printer Inventory ────────────────────────────────────────────`n"

    $Results | Format-Table `
        @{ L = 'ShareName';   E = { $_.ShareName };   A = 'Left'   },
        @{ L = 'UNCPath';     E = { $_.UNCPath };      A = 'Left'   },
        @{ L = 'DriverName';  E = { $_.DriverName };   A = 'Left'   },
        @{ L = 'PortType';    E = { $_.PortType };      A = 'Center' },
        @{ L = 'IPAddress';   E = { $_.IPAddress };    A = 'Left'   },
        @{ L = 'IPStatus';    E = { $_.IPStatus };     A = 'Left'   },
        @{ L = 'Shared';      E = { $_.Shared };       A = 'Center' } `
        -AutoSize

    # --- Summary ---
    $Total      = $Results.Count
    $Shared     = @($Results | Where-Object { $_.Shared }).Count
    $Resolved   = @($Results | Where-Object { $_.IPStatus -eq 'Resolved' }).Count
    $Unresolved = @($Results | Where-Object { $_.IPStatus -like 'Unresolved*' }).Count

    Write-Host " Total printers : $Total"
    Write-Host " Shared : $Shared"
    Write-Host " IP Resolved : $Resolved" -ForegroundColor Green
    if ($Unresolved -gt 0) {
        Write-Host " IP Unresolved : $Unresolved ← assign static IPs before migration" -ForegroundColor Yellow
    }

    # --- Flag unresolved printers ---
    if ($Unresolved -gt 0) {
        Write-Host "`n ── Needs Attention (no IP found) ────────────────────────────────`n" -ForegroundColor Yellow
        $Results |
            Where-Object { $_.IPStatus -like 'Unresolved*' } |
            Format-Table PrinterName, ShareName, PortName, PortType -AutoSize
    }

    #endregion

    #region --- Export Files ---

    # Full inventory
    $Results | Export-Csv -Path $InventoryCsv -NoTypeInformation -Encoding UTF8
    Write-Host "`n Full inventory : $InventoryCsv" -ForegroundColor Cyan

    # Migration-ready CSV (shared + IP resolved only)
    $MigrationRows = $Results |
        Where-Object { $_.Shared -and $_.IPStatus -eq 'Resolved' } |
        Select-Object `
            @{ N = 'OldPath';    E = { $_.UNCPath } },
            @{ N = 'NewPath';    E = { $_.IPAddress } },
            @{ N = 'DriverName'; E = { $_.DriverName } }

    if ($MigrationRows) {
        $MigrationRows | Export-Csv -Path $MigrationCsv -NoTypeInformation -Encoding UTF8
        Write-Host " Migration CSV : $MigrationCsv" -ForegroundColor Green
        Write-Host "`n Migration CSV preview:`n"
        $MigrationRows | Format-Table -AutoSize
    }
    else {
        Write-Host "`n No migration-ready rows -- verify printer IPs and sharing." -ForegroundColor Yellow
    }

    Write-Host ""

    #endregion
}