ninja-one/add-ip-printer.ps1
|
<#
.SYNOPSIS Adds an IP printer as an "All User Printer". #> [CmdletBinding()] param ( [Parameter()] [String]$PrinterName, [Parameter()] [String]$Hostname, [Parameter()] [String]$PrinterModel, [Parameter()] [Switch]$Remove = [System.Convert]::ToBoolean($env:removePrinter) ) begin { # Check for required PowerShell version (7+) if (!($PSVersionTable.PSVersion.Major -ge 7)) { try { # Install PowerShell 7 if missing if (!(Test-Path "$env:SystemDrive\Program Files\PowerShell\7")) { Write-Output '[INFO] Installing PowerShell version 7...' Invoke-Expression "& { $( Invoke-RestMethod https://aka.ms/install-powershell.ps1 ) } -UseMSI -Quiet" } # Refresh PATH $env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') # Restart script in PowerShell 7 pwsh -File "`"$PSCommandPath`"" @PSBoundParameters } catch { Write-Output '[ERROR] PowerShell 7 was not installed. Update PowerShell and try again.' throw $Error } finally { exit $LASTEXITCODE } } else { $PSStyle.OutputRendering = 'PlainText' } if ($env:printerName -and $env:printerName -notlike "null") { $PrinterName = $env:printerName } if ($env:hostname -and $env:hostname -notlike "null") { $Hostname = $env:hostname } if ($env:printerModel -and $env:printerModel -notlike "null") { $PrinterModel = $env:printerModel } if (-not $PrinterName) { Write-Host "[Error] Please specify a Printer Name." exit 1 } if (-not $Hostname -and $Remove -eq $false) { Write-Host "[Error] Please specify a Hostname." exit 1 } if (-not $PrinterModel -and $Remove -eq $false) { Write-Host "[Error] Please specify a Printer Model." exit 1 } # Modify $PrinterModel as Ninja does not allow "-" in the name if ($PrinterModel -eq "Canon TX3000") { $PrinterModel = "Canon TX-3000" } elseif ($PrinterModel -eq "Oce PlotWave 350 WPD2") { $PrinterModel = "Oce PlotWave 350 - WPD2" } elseif ($PrinterModel -eq "Oce PlotWave 365 WPD2") { $PrinterModel = "Oce PlotWave 365 - WPD2" } # Create a dictionary to map driver names to driver locations $driverLocations = @{ "Kyocera CS 4053ci KX" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/KX_DRIVER.zip" "Kyocera TASKalfa 4052ci KX" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/KX_DRIVER.zip" "Kyocera CS 307ci KX" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/KX_DRIVER.zip" "Kyocera ECOSYS M2640idw KX" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/KX_DRIVER.zip" "Canon TX-3000" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Canon-TX-3000.zip" "Oce PlotWave 350 - WPD2" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Oce-Plotwave.zip" "Oce PlotWave 365 - WPD2" = "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Oce-Plotwave-365.zip" } # Create a dictionary of file hashes for the driver files where the key is the DriverLocation $driverHashes = @{ "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/KX_DRIVER.zip" = "AF0EF97F790CEECF324B45FBBCA21F70FCE1B43C4DF50BF2C958D7C42B5F2E1E" "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Canon-TX-3000.zip" = "BEB5B7C10F9BA3A46E26268DBB79E2B51FC0EAF60975F3332E79B7E18D852244" "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Oce-Plotwave.zip" = "5F8B3C4C8B2EDB8F3B75880852575444F968D824ACED9500F318FA52AD54E57B" "https://jreappstorage.blob.core.windows.net/public/PrintDrivers/Oce-Plotwave-365.zip" = "5E893E0267AE12A5CC8670204E4AC22807EAC8BB19685ADEEEA91BD20B296F87" } } process { try { # Ensure the print spooler service is running $spooler = Get-Service -Name "spooler" if ($spooler.Status -ne 'Running') { Start-Service -Name "spooler" -ErrorAction SilentlyContinue Write-Host "[INFO] Starting the print spooler service..." # Wait for up to 1 minute for the spooler service to start $timeout = 60 $interval = 5 $elapsed = 0 while ($spooler.Status -ne 'Running' -and $elapsed -lt $timeout) { Start-Sleep -Seconds $interval $spooler = Get-Service -Name "spooler" $elapsed += $interval } if ($spooler.Status -ne 'Running') { Write-Host "[Error] Print spooler service failed to start." exit 1 } Write-Host "[INFO] Print spooler service is running." } if ($Remove) { Remove-Printer -Name $PrinterName -ErrorAction Stop Write-Host "[INFO] Removed printer $PrinterName" exit 0 } $PortName = "IP_$Hostname" # Check if the printer already exists $existingPrinter = Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue if ($existingPrinter) { #check to see if the driver and port match, so that if they do not, we can replace the printer if ($existingPrinter.DriverName -ne $PrinterModel -or $existingPrinter.PortName -ne $PortName) { Remove-Printer -Name $PrinterName -ErrorAction Stop Write-Host "[INFO] Removing printer $PrinterName with new configuration." } else { Write-Host "[INFO] Printer $PrinterName is already configured correctly." exit 0 } } # check to make sure the computer can connect to the server if (-not (Test-Connection -ComputerName $Hostname -Count 1 -Quiet)) { Write-Host "[ERROR] Unable to connect to $Hostname." exit 1 } # check to see if the print driver is installed $driver = Get-PrinterDriver -Name $PrinterModel -PrinterEnvironment "Windows x64" -ErrorAction SilentlyContinue if ($driver) { Write-Host "[INFO] Printer driver $PrinterModel already exists." } else { Write-Host "[INFO] Printer driver $PrinterModel not found. Installing..." # Get the driver location from the dictionary $DriverLocation = $driverLocations[$PrinterModel] # if the driver location is not found, throw an error if (-not $DriverLocation) { Write-Host "[ERROR] Driver location not found for $PrinterModel." exit 1 } # check to see if the driver location is set if (-not $DriverLocation) { throw "[ERROR] Driver location not specified." } # Handle local or remote driver location if ($DriverLocation.StartsWith("http")) { # Download from web $fileName = Split-Path $DriverLocation -Leaf $zipPath = Join-Path "$env:TEMP" $fileName $extractPath = "$env:TEMP\$([System.IO.Path]::GetFileNameWithoutExtension($fileName))" # Download the driver Write-Host "[INFO] Downloading driver from $DriverLocation to $zipPath" Invoke-WebRequest -Uri $DriverLocation -OutFile $zipPath # Check if the filehash matches $fileHash = Get-FileHash -Path $zipPath -Algorithm SHA256 if ($fileHash.Hash -ne $driverHashes[$DriverLocation]) { Write-Host "[ERROR] File hash does not match. Downloaded file may be corrupted." exit 1 } else { Write-Host "[INFO] File hash matches." } # Unzip the driver Expand-Archive -Path $zipPath -DestinationPath $extractPath -Force Write-Host "[INFO] Unzipped driver to $extractPath" } else { Write-Host "[INFO] Using local driver path: $DriverLocation" # Use local path if (Test-Path $DriverLocation) { Write-Host "[INFO] Driver location exists, proceeding with installation." if ($DriverLocation.EndsWith(".zip")) { $extractPath = "$env:TEMP\$([System.IO.Path]::GetFileNameWithoutExtension($DriverLocation))" Expand-Archive -Path $DriverLocation -DestinationPath $extractPath -Force Write-Host "[INFO] Unzipped driver to $extractPath" } else { $extractPath = $DriverLocation } } else { Write-Error "[ERROR] Local driver path not found: $DriverLocation" exit 1 } } # Get the INF file $infFile = Get-ChildItem -Path $extractPath -Filter "*.inf" -Recurse | Select-Object -First 1 Write-Host "[DEBUG] INF file found: $($infFile.FullName)" # Run pnputil and capture the output $pnpOutput = & pnputil /add-driver $infFile.FullName | Out-String # Extract the Published Name (any .inf file) using regex if ($pnpOutput -match "Published Name:\s+(?<published>[^:\r\n]+\.inf)") { $publishedName = $matches['published'] Write-Host "[INFO] Published Name found: $publishedName" # Get the driver info from the driver store using the published name $driverInfo = Get-WindowsDriver -Online -All | Where-Object { $_.Driver -eq $publishedName } if ($driverInfo) { Write-Host "[INFO] Driver information found:" # Add the printer driver try { Add-PrinterDriver -Name $PrinterModel -infPath $driverInfo.OriginalFileName -PrinterEnvironment "Windows x64" -ErrorAction Stop Write-Host "[INFO] Printer driver added successfully" } catch { Write-Host "[ERROR] Failed to add printer driver: $_" exit 1 } } else { Write-Host "[ERROR] Driver not found in Windows driver store" exit 1 } } else { Write-Host "[ERROR] Could not extract Published Name from pnputil output" Write-Host "[DEBUG] pnputil output was: $pnpOutput" exit 1 } } try { # Add the printer port # Check if the printer port already exists $existingPort = Get-PrinterPort -Name $PortName -ErrorAction SilentlyContinue if ($existingPort) { Write-Host "[INFO] Printer port $PortName already exists." } else { Write-Host "[INFO] Printer port $PortName not found. Adding..." # Add the printer port if ($PrinterModel -eq "Oce PlotWave 350 - WPD2") { Add-PrinterPort -Name $PortName -LprHostAddress $Hostname -LprQueueName "PW350_WPD2" } elseif ($PrinterModel -eq "Oce PlotWave 365 - WPD2") { Add-PrinterPort -Name $PortName -LprHostAddress $Hostname -LprQueueName "PW365_WPD2" } else { Add-PrinterPort -Name $PortName -PrinterHostAddress $Hostname -SNMP $true -SNMPCommunity "public" } } } catch { Write-Error "[ERROR] Failed to add printer port: $_" exit 1 } try { Add-Printer -Name $PrinterName -DriverName $PrinterModel -PortName $PortName Write-Host "[INFO] Printer added successfully" } catch { Write-Error "[ERROR] Failed to add printer: $_" $ErrorLine = $_.InvocationInfo.ScriptLineNumber Write-Error "[ERROR] Line Number: $ErrorLine" exit 1 } } catch { Write-Error "[ERROR] Failed to add network printer: $_" $ErrorLine = $_.InvocationInfo.ScriptLineNumber Write-Error "[ERROR] Line Number: $ErrorLine" exit 1 } exit 0 } end { } |