diff --git a/samy.ps1 b/samy.ps1 index bd7cd1c..64c6ead 100644 --- a/samy.ps1 +++ b/samy.ps1 @@ -1770,72 +1770,11 @@ function Invoke-CleanupSVSMSP { #region Printer handlers -function Get-SamyDriverRootFolder { - [CmdletBinding()] - param() - $root = Join-Path $env:ProgramData 'SVS\Samy\Drivers' - if (-not (Test-Path $root)) { - try { - New-Item -Path $root -ItemType Directory -Force | Out-Null - Write-LogHybrid "Created driver root folder '$root'." Info Printers -LogToEvent - } catch { - Write-LogHybrid "Failed to create driver root folder '$root': $($_.Exception.Message)" Warning Printers -LogToEvent - } - } - return $root -} -function Get-SamyDriverFolderForProfile { - [CmdletBinding()] - param( - [Parameter(Mandatory)][pscustomobject]$Profile - ) - $root = Get-SamyDriverRootFolder - - # Optional override if you ever add DriverFolderName to the profile - if ($Profile.PSObject.Properties.Name -contains 'DriverFolderName' -and $Profile.DriverFolderName) { - $folderName = $Profile.DriverFolderName - } else { - $folderName = "$($Profile.ClientCode)_$($Profile.ProfileName)" - } - - $dest = Join-Path $root $folderName - - if (-not (Test-Path $dest)) { - try { - New-Item -Path $dest -ItemType Directory -Force | Out-Null - Write-LogHybrid "Created driver folder '$dest'." Info Printers -LogToEvent - } catch { - Write-LogHybrid "Failed to create driver folder '$dest': $($_.Exception.Message)" Warning Printers -LogToEvent - } - } - - return $dest -} - -function Get-SamyDriverPackageUrl { - [CmdletBinding()] - param( - [Parameter(Mandatory)][pscustomobject]$Profile - ) - - # If profile explicitly provides a full URL, prefer that - if ($Profile.PSObject.Properties.Name -contains 'DriverPackageUrl' -and $Profile.DriverPackageUrl) { - return $Profile.DriverPackageUrl - } - - # Otherwise build it from SamyRepoBase / SamyBranch and DriverPackagePath - if ($Profile.PSObject.Properties.Name -contains 'DriverPackagePath' -and $Profile.DriverPackagePath) { - # Example: https://git.../SAMY/raw/branch/beta/Drivers/.../package.zip?raw=1 - return "$Script:SamyRepoBase/$Script:SamyBranch/$($Profile.DriverPackagePath)?raw=1" - } - - return $null -} @@ -1890,10 +1829,10 @@ function Invoke-GetPrinters { # Always update local printers.json with latest from bananas # but don't wipe a good file when we got *nothing* back. try { - Update-SvsPrinterLocalConfig -PrinterProfiles $printers -SkipIfEmpty + Set-SvsPrinterLocalConfig -PrinterProfiles $printers -SkipIfEmpty } catch { - Write-LogHybrid "Update-SvsPrinterLocalConfig failed: $($_.Exception.Message)" Warning Printers -LogToEvent + Write-LogHybrid "Set-SvsPrinterLocalConfig failed: $($_.Exception.Message)" Warning Printers -LogToEvent } # Return raw objects as JSON; JS will filter/group @@ -2007,321 +1946,6 @@ function Invoke-InstallPrinters { $Script:Samy_PrinterProfiles = $null -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." - } - - # Already installed? - $existingDriver = Get-PrinterDriver -Name $driverName -ErrorAction SilentlyContinue - if ($existingDriver) { - Write-LogHybrid "Printer driver '$driverName' already installed." Info Printers -LogToEvent - return - } - - Write-LogHybrid "Printer driver '$driverName' not found. Preparing to install." Info Printers -LogToEvent - - # ----------------------------- - # 0) Decide where driver files live locally (per-profile) - # ----------------------------- - $localDriverRoot = Get-SamyDriverFolderForProfile -Profile $Profile - - - # ----------------------------- - # 1) Start with any static local INF path, if defined - # ----------------------------- - $infPath = $null - if ($Profile.PSObject.Properties.Name -contains 'DriverInfPath' -and $Profile.DriverInfPath) { - if (Test-Path $Profile.DriverInfPath) { - $infPath = $Profile.DriverInfPath - Write-LogHybrid "Using existing INF path '$infPath' for driver '$driverName'." Info Printers -LogToEvent - } else { - Write-LogHybrid "Configured DriverInfPath '$($Profile.DriverInfPath)' does not exist, will try repo download." Warning Printers -LogToEvent - } - } - - # ----------------------------- - # 2) Try downloading a driver package from repo (404 is *not* fatal) - # ----------------------------- - $packageDownloaded = $false - - if ($Profile.PSObject.Properties.Name -contains 'DriverPackagePath' -and $Profile.DriverPackagePath) { - $driverPackageUrl = "$Script:SamyRepoBase/$Script:SamyBranch/$($Profile.DriverPackagePath)?raw=1" - $localZip = Join-Path $localDriverRoot "package.zip" - - Write-LogHybrid "Attempting to download driver package from $driverPackageUrl." Info Printers -LogToEvent - - try { - Invoke-WebRequest -Uri $driverPackageUrl -OutFile $localZip -UseBasicParsing -ErrorAction Stop - Write-LogHybrid "Downloaded driver package from $driverPackageUrl to $localZip." Success Printers -LogToEvent - $packageDownloaded = $true - } - catch [System.Net.WebException] { - $response = $_.Exception.Response - $statusCode = $null - if ($response -and $response.StatusCode) { - $statusCode = [int]$response.StatusCode - } - - if ($statusCode -eq 404) { - # ★ This is the new behavior: warn, but do NOT throw. - Write-LogHybrid "Driver package not found at $driverPackageUrl (404). Falling back to INF-only install for '$($Profile.DisplayName)'." Warning Printers -LogToEvent - # We just continue - maybe a local INF exists or will exist. - } - else { - Write-LogHybrid "Driver package download failed ($statusCode) from $($driverPackageUrl): $($_.Exception.Message)" Error Printers -LogToEvent - throw "Failed to download driver package from $($driverPackageUrl): $($_.Exception.Message)" - } - } - catch { - Write-LogHybrid "Driver package download failed from $($driverPackageUrl): $($_.Exception.Message)" Error Printers -LogToEvent - throw "Failed to download driver package from $($driverPackageUrl): $($_.Exception.Message)" - } - } - else { - Write-LogHybrid "No DriverPackagePath defined for '$($Profile.DisplayName)'; will rely on local INF." Info Printers -LogToEvent - } - - # ----------------------------- - # 2b) If we *did* download a package, expand it and try to locate the INF - # ----------------------------- - if ($packageDownloaded) { - try { - Expand-Archive -Path $localZip -DestinationPath $localDriverRoot -Force - Write-LogHybrid "Expanded driver package to '$localDriverRoot'." Info Printers -LogToEvent - } - catch { - Write-LogHybrid "Failed to expand driver package '$localZip': $($_.Exception.Message)" Error Printers -LogToEvent - throw "Failed to expand driver package '$localZip': $($_.Exception.Message)" - } - - # If we don't yet have an INF path, try to derive it from DriverInfName - # If we don't yet have an INF path, try to derive it from DriverInfName - if (-not $infPath) { - if ($Profile.PSObject.Properties.Name -contains 'DriverInfName' -and $Profile.DriverInfName) { - - # 1) First try: directly under the destination root - $candidateInf = Join-Path $localDriverRoot $Profile.DriverInfName - if (Test-Path $candidateInf) { - $infPath = $candidateInf - Write-LogHybrid "Resolved INF from package as '$infPath' using DriverInfName '$($Profile.DriverInfName)' at root." Info Printers -LogToEvent - } - else { - Write-LogHybrid "Expected INF '$candidateInf' (from DriverInfName) not found at root; searching recursively..." Warning Printers -LogToEvent - - # 2) Second try: search subfolders for that INF name - $found = Get-ChildItem -Path $localDriverRoot -Recurse -Filter $Profile.DriverInfName -File -ErrorAction SilentlyContinue | - Select-Object -First 1 - - if ($found) { - $infPath = $found.FullName - Write-LogHybrid "Resolved INF from package as '$infPath' (found by recursive search for '$($Profile.DriverInfName)')." Info Printers -LogToEvent - } - else { - Write-LogHybrid "Could not find any '$($Profile.DriverInfName)' under '$localDriverRoot' after expanding package." Error Printers -LogToEvent - } - } - } - else { - Write-LogHybrid "DriverInfName not defined for profile '$($Profile.ProfileName)'; cannot auto-resolve INF from expanded package." Warning Printers -LogToEvent - } - } - - } - - - - # ----------------------------- - # 4) Still nothing? Hard fail with a clear message - # ----------------------------- - if (-not $infPath -or -not (Test-Path $infPath)) { - throw "Driver '$driverName' is not installed and no valid DriverInfPath or usable driver package is available for profile '$($Profile.ProfileName)'." - } - - Write-LogHybrid "Installing printer driver '$driverName' from '$infPath'." Info Printers -LogToEvent - - # 4a) Stage the driver package with pnputil - $pnputilCmd = "pnputil.exe /add-driver `"$infPath`" /install" - Write-LogHybrid "Running: $pnputilCmd" Info Printers -LogToEvent - - $pnputilOutput = & pnputil.exe /add-driver "$infPath" /install 2>&1 - $exitCode = $LASTEXITCODE - - Write-LogHybrid "pnputil exit code: $exitCode. Output:`n$pnputilOutput" Info Printers -LogToEvent - - if ($exitCode -ne 0) { - throw "pnputil failed with exit code $exitCode installing '$driverName' from '$infPath'." - } - - # 4b) Register the printer driver with Add-PrinterDriver - try { - Write-LogHybrid "Calling Add-PrinterDriver -Name '$driverName' -InfPath '$infPath'." Info Printers -LogToEvent - Add-PrinterDriver -Name $driverName -ErrorAction Stop - } - catch { - Write-LogHybrid "Add-PrinterDriver failed for '$driverName' using '$infPath': $($_.Exception.Message)" Error Printers -LogToEvent - throw "Add-PrinterDriver failed for '$driverName': $($_.Exception.Message)" - } - - # 4c) Final verification - Start-Sleep -Seconds 2 - - $existingDriver = Get-PrinterDriver -Name $driverName -ErrorAction SilentlyContinue - - if (-not $existingDriver) { - $sharpNames = (Get-PrinterDriver -ErrorAction SilentlyContinue | - Where-Object Name -like 'SHARP*' | - Select-Object -ExpandProperty Name) -join ', ' - - if (-not $sharpNames) { $sharpNames = '(none)' } - - Write-LogHybrid "After pnputil/Add-PrinterDriver, driver '$driverName' not found. Existing SHARP drivers: $sharpNames" Warning Printers -LogToEvent - throw "Failed to find printer driver '$driverName' after Add-PrinterDriver." - } - - Write-LogHybrid "Printer driver '$driverName' installed and detected successfully." Success Printers -LogToEvent -} - - - - - -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-SvsPrinterProfileLocal -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={0} Profile={1}: {2}" -f $ClientCode, $ProfileName, $_.Exception.Message - ) Error Printers -LogToEvent - throw - } -} - #endregion Printer core (local config + install)