diff --git a/New-SamyPrinterProfileJson.ps1 b/New-SamyPrinterProfileJson.ps1 new file mode 100644 index 0000000..30ba6da --- /dev/null +++ b/New-SamyPrinterProfileJson.ps1 @@ -0,0 +1,280 @@ +function New-SamyPrinterProfileJson { +<# +.SYNOPSIS + Generates a SAMY printer profile JSON template from existing printers + and optionally uploads it to a Git (Gitea) repository. + +.DESCRIPTION + Enumerates local printers via Get-Printer, maps them into SAMY printer + profile objects, and writes them to a JSON file. The JSON is intended + as a starting point / template for building printers.json used by SAMY. + + Each profile includes: + - ClientCode (from parameter) + - Location (from parameter) + - ProfileName (defaults to printer Name) + - DisplayName (printer Name) + - Type (TcpIp or Shared, best-effort guess) + - Address (for TCP/IP printers) + - PrintServer (for shared printers) + - ShareName (for shared printers) + - DriverName (printer DriverName) + - DriverInfPath, DriverPackagePath, DriverInfName (empty placeholders) + - IsDefault (true if this printer is default) + + Optionally, the generated JSON can be uploaded to a Git repo using + a personal access token (PAT) passed as a SecureString. + +.PARAMETER ClientCode + MSP/client code to stamp into each profile (for example "SVS"). + +.PARAMETER Location + Human-friendly location (for example "Embrun"). Used both as a field in + each profile and as part of the default JSON file name. + +.PARAMETER OutputPath + Folder where the JSON file will be saved. Default is: + C:\ProgramData\SVS\Samy\Printers + +.PARAMETER UploadToGit + When set, the function will attempt to upload the generated JSON file + to the specified Git (Gitea) repository and path. + +.PARAMETER GitApiBase + Base URL for the Git API, for example: + https://git.svstools.ca/api/v1 + +.PARAMETER GitRepo + Repository identifier in the form "Owner/Repo", for example: + SVS_Public_Repo/SAMY + +.PARAMETER GitBranch + Branch name to write to. Default is "beta". + +.PARAMETER GitPath + Path inside the repo where the JSON should be written, for example: + Printers/SVS/Embrun/printers.json + +.PARAMETER GitToken + Personal access token as a SecureString. Recommended source: + a secret environment variable (for example $env:GIT_PAT) converted via + ConvertTo-SecureString. + +.EXAMPLE + New-SamyPrinterProfileJson -ClientCode "SVS" -Location "Embrun" + + Generates a printers_SVS_Embrun.json in: + C:\ProgramData\SVS\Samy\Printers + +.EXAMPLE + $secureToken = ConvertTo-SecureString $env:GIT_PAT -AsPlainText -Force + + New-SamyPrinterProfileJson ` + -ClientCode "SVS" ` + -Location "Embrun" ` + -UploadToGit ` + -GitApiBase "https://git.svstools.ca/api/v1" ` + -GitRepo "SVS_Public_Repo/SAMY" ` + -GitBranch "beta" ` + -GitPath "Printers/SVS/Embrun/printers.json" ` + -GitToken $secureToken + + Generates the JSON locally and uploads it to the specified path + in the Git repository. +#> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$ClientCode, + + [Parameter(Mandatory = $true)] + [string]$Location, + + [string]$OutputPath = "C:\ProgramData\SVS\Samy\Printers", + + [switch]$UploadToGit, + + [string]$GitApiBase, + [string]$GitRepo, + [string]$GitBranch = "beta", + [string]$GitPath, + [SecureString]$GitToken + ) + + # Helper: safe logging that prefers Write-LogHybrid if available + function _WriteLog { + param( + [string]$Message, + [string]$Level = "Info", + [string]$Task = "PrinterJson" + ) + + if (Get-Command Write-LogHybrid -ErrorAction SilentlyContinue) { + Write-LogHybrid $Message $Level $Task + } else { + Write-Host "[$Level] [$Task] $Message" + } + } + + try { + _WriteLog "Starting New-SamyPrinterProfileJson for ClientCode='$ClientCode' Location='$Location'." "Info" + + # ------------------------------------------------------------------ + # 1) Ensure output folder exists and build a safe file name + # ------------------------------------------------------------------ + if (-not (Test-Path $OutputPath)) { + _WriteLog "Creating output folder '$OutputPath'." "Info" + New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null + } + + $safeLocation = $Location -replace '[^A-Za-z0-9_-]', '_' + $fileName = "printers_{0}_{1}.json" -f $ClientCode, $safeLocation + $filePath = Join-Path $OutputPath $fileName + + # ------------------------------------------------------------------ + # 2) Enumerate printers and build profile objects + # ------------------------------------------------------------------ + $printers = Get-Printer -ErrorAction SilentlyContinue + + if (-not $printers) { + _WriteLog "No printers found on this system. JSON will be empty." "Warning" + } else { + _WriteLog ("Found {0} printer(s)." -f $printers.Count) "Info" + } + + $profiles = @() + + foreach ($p in $printers) { + $profileName = $p.Name + $displayName = $p.Name + $driverName = $p.DriverName + $portName = $p.PortName + $isDefault = $p.Shared -eq $false -and $p.Default -eq $true + + # Try to resolve port details + $port = $null + if ($portName) { + $port = Get-PrinterPort -Name $portName -ErrorAction SilentlyContinue + } + + $type = "TcpIp" + $address = $null + $printServer = $null + $shareName = $null + + if ($port -and $port.PrinterHostAddress) { + # Standard TCP/IP port + $type = "TcpIp" + $address = $port.PrinterHostAddress + } + elseif ($p.Shared -and $p.ShareName) { + # Best guess at a shared printer + $type = "Shared" + $shareName = $p.ShareName + $printServer = $env:COMPUTERNAME + } + + $profiles += [PSCustomObject]@{ + ClientCode = $ClientCode + Location = $Location + + ProfileName = $profileName + DisplayName = $displayName + + Type = $type + Address = $address + PrintServer = $printServer + ShareName = $shareName + + DriverName = $driverName + + DriverInfPath = "" + DriverPackagePath = "" + DriverInfName = "" + + IsDefault = $isDefault + + _comment1 = "Review Type/Address/PrintServer/ShareName before use." + _comment2 = "Fill DriverPackagePath and DriverInfName for repo-based install." + } + } + + # ------------------------------------------------------------------ + # 3) Write JSON to disk + # ------------------------------------------------------------------ + $json = $profiles | ConvertTo-Json -Depth 5 + + $json | Set-Content -Path $filePath -Encoding UTF8 + _WriteLog ("Wrote {0} profile(s) to '{1}'." -f $profiles.Count, $filePath) "Success" + + # ------------------------------------------------------------------ + # 4) Optional: upload to Git (Gitea) + # ------------------------------------------------------------------ + if ($UploadToGit) { + if (-not $GitApiBase -or -not $GitRepo -or -not $GitPath -or -not $GitToken) { + _WriteLog "UploadToGit requested but GitApiBase, GitRepo, GitPath, or GitToken is missing. Skipping upload." "Warning" + } + else { + _WriteLog "Uploading JSON to Git repo '$GitRepo' (branch '$GitBranch', path '$GitPath')." "Info" + + # Convert SecureString token to plain text (in memory only) + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($GitToken) + try { + $plainToken = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) + } + finally { + if ($bstr -ne [IntPtr]::Zero) { + [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) + } + } + + # Prepare API URL and content + $apiUrl = "{0}/repos/{1}/contents/{2}" -f $GitApiBase.TrimEnd('/'), $GitRepo, $GitPath + $contentB64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($json)) + + $headers = @{ + Authorization = "token $plainToken" + } + + # Try to see if file already exists to retrieve its SHA + $existingSha = $null + try { + $existing = Invoke-RestMethod -Uri ($apiUrl + "?ref=$GitBranch") -Headers $headers -Method Get -ErrorAction Stop + if ($existing.sha) { + $existingSha = $existing.sha + } + } + catch { + # 404 is fine (file does not exist yet), anything else we log + if ($_.Exception.Response.StatusCode.Value__ -ne 404) { + _WriteLog ("Git pre-check failed: {0}" -f $_.Exception.Message) "Warning" + } + } + + $body = @{ + message = "Update printers for $ClientCode / $Location" + branch = $GitBranch + content = $contentB64 + } + if ($existingSha) { + $body.sha = $existingSha + } + + try { + $bodyJson = $body | ConvertTo-Json -Depth 5 + $null = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Put -Body $bodyJson -ContentType "application/json" -ErrorAction Stop + _WriteLog "Git upload completed successfully." "Success" + } + catch { + _WriteLog ("Git upload failed: {0}" -f $_.Exception.Message) "Error" + } + } + } + + return $filePath + } + catch { + _WriteLog ("New-SamyPrinterProfileJson failed: {0}" -f $_.Exception.Message) "Error" + throw + } +}