All scripts
Microsoft 365 356

Universal Print Printer Inventory Report

Pulls every printer registered with Universal Print in the tenant, including connector, sharing, and online status, and flags any printer that is not currently showing as online.

Get-UniversalPrintPrinterReport.ps1
<#
.SYNOPSIS
    Reports on Universal Print printers registered in the tenant.

.DESCRIPTION
    Connects to Microsoft Graph and pulls every printer registered with
    Universal Print, along with its connector, sharing status, and whether
    it is currently online. Useful before a print rollout, or any time
    you need to find out which printers have gone quiet without walking
    the floor. Requires the Microsoft.Graph.Authentication module and an
    account or app registration with Printer.Read.All permission.

.EXAMPLE
    .\Get-UniversalPrintPrinterReport.ps1
    Connects to Graph, pulls all printers, and writes a CSV to the current folder.

.EXAMPLE
    .\Get-UniversalPrintPrinterReport.ps1 -OutputPath "C:\Reports\printers.csv"
    Same report, saved to a specific path.

.AUTHOR
    Shehryar Hassan
#>

param(
    [string]$OutputPath = ".\UniversalPrintPrinterReport.csv"
)

if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Authentication)) {
    Write-Host "Installing Microsoft.Graph.Authentication module..." -ForegroundColor Yellow
    Install-Module Microsoft.Graph.Authentication -Scope CurrentUser -Force
}

Import-Module Microsoft.Graph.Authentication

Connect-MgGraph -Scopes "Printer.Read.All" -NoWelcome

Write-Host "Pulling printer list from Universal Print..." -ForegroundColor Cyan

$printers = @()
$uri = "https://graph.microsoft.com/v1.0/print/printers?`$top=50"

while ($uri) {
    $response = Invoke-MgGraphRequest -Method GET -Uri $uri
    $printers += $response.value
    $uri = $response."@odata.nextLink"
}

if ($printers.Count -eq 0) {
    Write-Host "No printers found. Either none are registered yet, or this account does not have access." -ForegroundColor Yellow
    return
}

$report = foreach ($printer in $printers) {
    [PSCustomObject]@{
        DisplayName       = $printer.displayName
        Manufacturer      = $printer.manufacturer
        Model             = $printer.model
        IsShared          = $printer.isShared
        HasPhysicalDevice = $printer.hasPhysicalDevice
        ConnectorId       = $printer.connectorId
        Status            = $printer.status.state
        LastRegistered    = $printer.registrationDateTime
    }
}

$report | Sort-Object DisplayName | Export-Csv -Path $OutputPath -NoTypeInformation

Write-Host "Done. $($report.Count) printers written to $OutputPath" -ForegroundColor Green

$offline = $report | Where-Object { $_.Status -ne "online" }
if ($offline.Count -gt 0) {
    Write-Host ""
    Write-Host "$($offline.Count) printers are not showing as online:" -ForegroundColor Yellow
    $offline | Format-Table DisplayName, Status -AutoSize
}

Read it before you run it, and test in a safe tenant first.