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 } }