From 49b61047413ed08330432d150a4ae6bf1de78b62 Mon Sep 17 00:00:00 2001 From: Stephan Yelle Date: Fri, 5 Dec 2025 15:20:12 -0500 Subject: [PATCH] Update samy.ps1 --- samy.ps1 | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 2 deletions(-) diff --git a/samy.ps1 b/samy.ps1 index 7f5770d..9bd6b4e 100644 --- a/samy.ps1 +++ b/samy.ps1 @@ -1795,8 +1795,6 @@ function Get-SamyClientListFromServer { } } - - function Invoke-GetPrinters { param($Context) @@ -1946,6 +1944,261 @@ function Invoke-InstallPrinters { } } +#region Printer core (local config + install) + +function Get-SamyPrinterLocalConfigPath { + [CmdletBinding()] + param() + + # Use a stable location on every machine + $configDir = Join-Path $env:ProgramData 'SVS\Samy\Printers' + + if (-not (Test-Path $configDir)) { + try { + New-Item -Path $configDir -ItemType Directory -Force | Out-Null + Write-LogHybrid "Created printer config folder at '$configDir'." Info Printers -LogToEvent + } + catch { + Write-LogHybrid "Failed to create printer config folder '$configDir': $($_.Exception.Message)" Warning Printers -LogToEvent + } + } + + return (Join-Path $configDir 'printers.json') +} + +function Get-SamyPrinterConfigFromFile { + [CmdletBinding()] + param() + + $path = Get-SamyPrinterLocalConfigPath + + if (-not (Test-Path $path)) { + throw "Local printer config file not found at '$path'. Create or update printers.json first." + } + + $json = Get-Content -Path $path -Raw -ErrorAction Stop + $profiles = $json | ConvertFrom-Json + + if (-not $profiles) { + throw "Printer config file '$path' is empty or invalid JSON." + } + + return $profiles +} + +# Per-session cache +$Script:Samy_PrinterProfiles = $null + +function Get-SamyPrinterProfiles { + <# + .SYNOPSIS + Returns all printer profiles, optionally filtered by ClientCode. + #> + [CmdletBinding()] + param( + [string]$ClientCode + ) + + if (-not $Script:Samy_PrinterProfiles) { + $Script:Samy_PrinterProfiles = Get-SamyPrinterConfigFromFile + } + + $result = $Script:Samy_PrinterProfiles + + if ($PSBoundParameters.ContainsKey('ClientCode') -and $ClientCode) { + $result = $result | Where-Object { $_.ClientCode -eq $ClientCode } + } + + return $result +} + +function Get-SamyPrinterProfile { + <# + .SYNOPSIS + Returns a single printer profile for a given ClientCode and ProfileName. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)][string]$ClientCode, + [Parameter(Mandatory)][string]$ProfileName + ) + + $profiles = Get-SamyPrinterProfiles -ClientCode $ClientCode + $match = $profiles | Where-Object { $_.ProfileName -eq $ProfileName } + + if (-not $match) { + throw "No printer profile found for ClientCode '$ClientCode' and ProfileName '$ProfileName'." + } + + if ($match.Count -gt 1) { + throw "Multiple printer profiles found for ClientCode '$ClientCode' and ProfileName '$ProfileName'. De-duplicate in printers.json." + } + + return $match +} + +function Ensure-SamyPrinterDriver { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [pscustomobject]$Profile + ) + + $driverName = $Profile.DriverName + if (-not $driverName) { + throw "Profile '$($Profile.ProfileName)' has no DriverName defined in printer config." + } + + $existingDriver = Get-PrinterDriver -Name $driverName -ErrorAction SilentlyContinue + if ($existingDriver) { + Write-Verbose "Printer driver '$driverName' already installed." + return + } + + if (-not $Profile.DriverInfPath) { + throw "Driver '$driverName' is not installed and no DriverInfPath is defined for profile '$($Profile.ProfileName)'." + } + + $infPath = $Profile.DriverInfPath + Write-Verbose "Installing printer driver '$driverName' from '$infPath'." + + pnputil.exe /add-driver "`"$infPath`"" /install | Out-Null + + $existingDriver = Get-PrinterDriver -Name $driverName -ErrorAction SilentlyContinue + if (-not $existingDriver) { + throw "Failed to install printer driver '$driverName' from '$infPath'." + } +} + +function Install-SamyTcpIpPrinter { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [pscustomobject]$Profile, + + [switch]$SetAsDefault + ) + + $portName = $Profile.Address + $printerName = $Profile.DisplayName + + if (-not $portName) { + throw "TCP/IP printer profile '$($Profile.ProfileName)' is missing Address in printer config." + } + + if (-not (Get-PrinterPort -Name $portName -ErrorAction SilentlyContinue)) { + Write-Verbose "Creating TCP/IP port '$portName'." + Add-PrinterPort -Name $portName -PrinterHostAddress $Profile.Address + } + else { + Write-Verbose "TCP/IP port '$portName' already exists." + } + + $existingPrinter = Get-Printer -Name $printerName -ErrorAction SilentlyContinue + if ($existingPrinter) { + Write-Verbose "Printer '$printerName' already exists. Skipping creation." + } + else { + Write-Verbose "Creating printer '$printerName' on port '$portName' using driver '$($Profile.DriverName)'." + Add-Printer -Name $printerName -PortName $portName -DriverName $Profile.DriverName + } + + if ($SetAsDefault -or $Profile.IsDefault) { + Write-Verbose "Setting '$printerName' as default printer." + (New-Object -ComObject WScript.Network).SetDefaultPrinter($printerName) + } +} + +function Install-SamySharedPrinter { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [pscustomobject]$Profile, + + [switch]$SetAsDefault + ) + + if (-not $Profile.PrintServer -or -not $Profile.ShareName) { + throw "Shared printer profile '$($Profile.ProfileName)' is missing PrintServer or ShareName in printer config." + } + + $connectionName = "\\$($Profile.PrintServer)\$($Profile.ShareName)" + + $existing = Get-Printer -ErrorAction SilentlyContinue | + Where-Object { + $_.Name -eq $Profile.DisplayName -or + $_.ShareName -eq $Profile.ShareName + } + + if ($existing) { + Write-Verbose "Shared printer '$($Profile.DisplayName)' already connected as '$($existing.Name)'." + $printerName = $existing.Name + } + else { + Write-Verbose "Adding shared printer connection '$connectionName'." + Add-Printer -ConnectionName $connectionName + + $printerName = (Get-Printer | + Where-Object { $_.Name -like "*$($Profile.ShareName)*" } | + Select-Object -First 1 + ).Name + } + + if ($SetAsDefault -or $Profile.IsDefault) { + Write-Verbose "Setting '$printerName' as default printer." + (New-Object -ComObject WScript.Network).SetDefaultPrinter($printerName) + } +} + +function Invoke-SamyPrinterInstall { + <# + .SYNOPSIS + Installs a printer based on a JSON-defined profile (supports -WhatIf). + #> + [CmdletBinding(SupportsShouldProcess = $true)] + param( + [Parameter(Mandatory)] + [string]$ClientCode, + + [Parameter(Mandatory)] + [string]$ProfileName, + + [switch]$SetAsDefault + ) + + try { + $profile = Get-SamyPrinterProfile -ClientCode $ClientCode -ProfileName $ProfileName + $targetName = $profile.DisplayName + + if ($PSCmdlet.ShouldProcess($targetName, "Install printer")) { + + Write-LogHybrid "Installing printer profile '$($profile.ProfileName)' for client '$ClientCode' (WhatIf=$WhatIfPreference)." Info Printers -LogToEvent + + Ensure-SamyPrinterDriver -Profile $profile + + switch ($profile.Type) { + 'TcpIp' { + Install-SamyTcpIpPrinter -Profile $profile -SetAsDefault:$SetAsDefault + } + 'Shared' { + Install-SamySharedPrinter -Profile $profile -SetAsDefault:$SetAsDefault + } + default { + throw "Unsupported printer Type '$($profile.Type)' in profile '$($profile.ProfileName)'. Use 'TcpIp' or 'Shared'." + } + } + + Write-LogHybrid "Installed printer '$($profile.DisplayName)' (Client=$ClientCode Profile=$ProfileName)." Info Printers -LogToEvent + } + } + catch { + Write-LogHybrid "Printer install failed for Client=$ClientCode Profile=$ProfileName: $($_.Exception.Message)" Error Printers -LogToEvent + throw + } +} + +#endregion Printer core (local config + install) + #endregion Printer handlers