Déployez une Zebra GX420t sans clics : création du port TCP 9100, ajout de la file d’impression et définition de la taille d’étiquette via ZPL/SGD, le tout en PowerShell, avec scripts prêts à l’emploi et bonnes pratiques de déploiement.
Contexte et objectif
Dans de nombreux environnements Windows, la configuration d’une imprimante d’étiquettes Zebra doit être reproductible, rapide et sans interface graphique. L’objectif ici est de :
- Créer automatiquement un port TCP Raw 9100 et une file d’impression pour une Zebra GX420t.
- Définir la taille des étiquettes (largeur et hauteur) sans passer par « Préférences de l’imprimante ».
- Garantir un déploiement idempotent (relancer le script ne casse rien), avec journalisation et tests de connectivité.
Pourquoi PrintManagement ne suffit pas
Le module PowerShell intégré PrintManagement (Add-Printer, Add-PrinterPort, etc.) gère la création de ports et de files d’impression, mais ne sait pas écrire dans les Printer Preferences (format d’étiquette, vitesse, densité, etc.). Aucune cmdlet Microsoft ne couvre ces réglages avancés sur les Zebra. Pour cela, on s’appuie sur le langage d’impression Zebra (ZPL) et sur les variables SGD (Set‑Get‑Do), envoyés directement à l’imprimante.
Principe technique : ZPL & SGD
Les imprimantes Zebra interprètent le ZPL. Pour définir un format, deux commandes suffisent généralement :
^PW{largeur_en_points}(Print Width)^LL{longueur_en_points}(Label Length)
Le tout est encapsulé entre ^XA (début) et ^XZ (fin). Exemple pour une étiquette 4″×6″ en 203 dpi : ^XA^PW812^LL1218^XZ.
Alternative lisible : SGD expose des paires clé‑valeur, par exemple :
! U1 setvar "media.type" "label"
! U1 setvar "zpl.label_length" "1218"
! U1 setvar "device.languages" "zpl"
Ces commandes (ZPL ou SGD) peuvent être envoyées :
- En direct sur le port TCP 9100 de l’imprimante (Raw).
- Via la file d’impression Windows, en écriture « raw » (utile en USB/COM).
Conversions de dimensions : mm, pouces et points
La largeur et la longueur attendues par ZPL/SGD sont en points (dots). La conversion est simple :
- pouces → points :
points = pouces × DPI - mm → points :
points = (mm ÷ 25,4) × DPI
La GX420t existe typiquement en 203 dpi. Si votre modèle est différent, adaptez le DPI dans les scripts.
Fonctions PowerShell réutilisables
Les blocs ci‑dessous constituent une boîte à outils. Copiez‑les tels quels, puis utilisez le « Script complet » plus bas.
Conversion vers des points Zebra
function ConvertTo-ZebraDots {
[CmdletBinding()]
param(
[Parameter(Mandatory)][double]$Value,
[ValidateSet('mm','in')][string]$Unit = 'mm',
[ValidateRange(100,600)][int]$Dpi = 203
)
switch ($Unit) {
'mm' { return [int][math]::Round(($Value / 25.4) * $Dpi) }
'in' { return [int][math]::Round($Value * $Dpi) }
}
}
Test de connectivité TCP 9100
function Test-ZebraTcp9100 {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$IPAddress,
[int]$TimeoutMs = 2500
)
$client = [System.Net.Sockets.TcpClient]::new()
$ar = $client.BeginConnect($IPAddress,9100,$null,$null)
$ok = $ar.AsyncWaitHandle.WaitOne($TimeoutMs)
if(-not $ok){ return $false }
try { $client.EndConnect($ar); return $true } catch { return $false }
finally { $client.Close() }
}
Création du port TCP et de la file d’impression
function New-ZebraTcpPort {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$IPAddress
)
# Le paramètre -PrinterHostAddress crée un port Standard TCP/IP Raw (par défaut 9100)
if(-not (Get-PrinterPort -ErrorAction SilentlyContinue | Where-Object {$_.PrinterHostAddress -eq $IPAddress})) {
Write-Verbose "Création du port TCP/IP pour $IPAddress (Raw 9100)"
Add-PrinterPort -PrinterHostAddress $IPAddress | Out-Null
}
# Retourne le nom du port (généralement 'IP_x.x.x.x')
(Get-PrinterPort | Where-Object {$_.PrinterHostAddress -eq $IPAddress}).Name
}
function Get-ZebraDriverName {
[CmdletBinding()]
param(
[string]$ModelPattern = 'GX420t'
)
$drv = Get-PrinterDriver -ErrorAction SilentlyContinue | Where-Object { $_.Name -match $ModelPattern } | Select-Object -First 1
if(-not $drv){
throw "Pilote pour '$ModelPattern' introuvable. Installez au préalable le pilote Zebra (ex. 'ZDesigner GX420t')."
}
$drv.Name
}
function New-ZebraPrinter {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$PrinterName,
[Parameter(Mandatory)][string]$PortName,
[Parameter(Mandatory)][string]$DriverName,
[string]$Location,
[string]$Comment
)
$existing = Get-Printer -Name $PrinterName -ErrorAction SilentlyContinue
if($existing){
Write-Verbose "La file '$PrinterName' existe déjà. Aucune création."
return $existing
}
Add-Printer -Name $PrinterName -DriverName $DriverName -PortName $PortName -Location $Location -Comment $Comment
Get-Printer -Name $PrinterName
}
Envoi de ZPL : TCP direct ou file d’impression
function Send-ZebraZplTcp {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$IPAddress,
[Parameter(Mandatory)][string]$Zpl
)
$bytes = [System.Text.Encoding]::ASCII.GetBytes($Zpl)
$client = [System.Net.Sockets.TcpClient]::new($IPAddress,9100)
try {
$stream = $client.GetStream()
$stream.Write($bytes,0,$bytes.Length)
$stream.Flush()
} finally {
if($stream){ $stream.Close() }
$client.Close()
}
}
# Envoi "raw" via la file Windows (utile en USB/COM)
Add-Type -TypeDefinition @"
using System;
using System.IO;
using System.Runtime.InteropServices;
public class RawPrinterHelper {
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class DOCINFOA { public string pDocName; public string pOutputFile; public string pDataType; }
[DllImport("winspool.Drv", EntryPoint="OpenPrinterA", SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint="ClosePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="StartDocPrinterA", SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint="EndDocPrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="StartPagePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="EndPagePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="WritePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
public static bool SendStringToPrinter(string printerName, string zpl) {
IntPtr pPrinter = IntPtr.Zero;
DOCINFOA di = new DOCINFOA();
di.pDocName = "RAW ZPL";
di.pDataType = "RAW";
if (!OpenPrinter(printerName, out pPrinter, IntPtr.Zero)) return false;
if (!StartDocPrinter(pPrinter, 1, di)) { ClosePrinter(pPrinter); return false; }
if (!StartPagePrinter(pPrinter)) { EndDocPrinter(pPrinter); ClosePrinter(pPrinter); return false; }
IntPtr pBytes = Marshal.StringToCoTaskMemAnsi(zpl);
int dwWritten = 0;
bool ok = WritePrinter(pPrinter, pBytes, zpl.Length, out dwWritten);
Marshal.FreeCoTaskMem(pBytes);
EndPagePrinter(pPrinter); EndDocPrinter(pPrinter); ClosePrinter(pPrinter);
return ok;
}
}
"@ -ErrorAction SilentlyContinue
function Send-ZebraZplQueue {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$PrinterName,
[Parameter(Mandatory)][string]$Zpl
)
$null = [RawPrinterHelper]::SendStringToPrinter($PrinterName, $Zpl)
}
Appliquer la taille d’étiquette et enregistrer
function Set-ZebraLabelSize {
[CmdletBinding()]
param(
[Parameter(Mandatory)][int]$WidthDots,
[Parameter(Mandatory)][int]$LengthDots,
[switch]$Persist, # ^JUS
[string]$Orientation = 'N' # N=Normal, R=L90, I=Inversé, B=L270 (si besoin)
)
# Ajoutez ^PO$Orientation si l’orientation doit être forcée
$jus = $Persist.IsPresent ? '^JUS' : ''
"^XA^PW$WidthDots^LL$LengthDots$jus^XZ"
}
Script complet d’installation
Ce script crée le port, ajoute la file d’impression, pousse le ZPL de format et, en option, enregistre la configuration en mémoire permanente de l’imprimante.
param(
[Parameter(Mandatory)][string]$PrinterName,
[Parameter(Mandatory)][string]$IPAddress,
[ValidateRange(100,600)][int]$Dpi = 203,
[ValidateSet('mm','in')][string]$Unit = 'mm',
[double]$LabelWidth = 101.6, # 4 pouces par défaut (en mm)
[double]$LabelHeight = 152.4, # 6 pouces par défaut (en mm)
[switch]$Persist, # ^JUS
[switch]$UseSpoolerRaw, # Envoi via la file au lieu du TCP 9100 direct
[string]$Location,
[string]$Comment = "Zebra GX420t - déploiement automatisé"
)
Write-Host "== Vérification de la connectivité TCP 9100 ==" -ForegroundColor Cyan
if(-not (Test-ZebraTcp9100 -IPAddress $IPAddress)){
Write-Warning "Impossible d’atteindre $IPAddress:9100. Vérifiez réseau/pare‑feu/alimentation."
}
Write-Host "== Création du port TCP/IP ==" -ForegroundColor Cyan
$portName = New-ZebraTcpPort -IPAddress $IPAddress
Write-Host "Port utilisé : $portName"
Write-Host "== Recherche du pilote Zebra ==" -ForegroundColor Cyan
$driverName = Get-ZebraDriverName -ModelPattern 'GX420t'
Write-Host "Pilote retenu : $driverName"
Write-Host "== Création de la file d’impression ==" -ForegroundColor Cyan
$printer = New-ZebraPrinter -PrinterName $PrinterName -PortName $portName -DriverName $driverName -Location $Location -Comment $Comment
Write-Host "File : $($printer.Name)"
Write-Host "== Conversion des dimensions ==" -ForegroundColor Cyan
$pw = ConvertTo-ZebraDots -Value $LabelWidth -Unit $Unit -Dpi $Dpi
$ll = ConvertTo-ZebraDots -Value $LabelHeight -Unit $Unit -Dpi $Dpi
Write-Host "Largeur (points): $pw | Longueur (points): $ll"
$zpl = Set-ZebraLabelSize -WidthDots $pw -LengthDots $ll -Persist:$Persist
Write-Host "== Envoi du ZPL de configuration ==" -ForegroundColor Cyan
if($UseSpoolerRaw){
Send-ZebraZplQueue -PrinterName $PrinterName -Zpl $zpl
} else {
Send-ZebraZplTcp -IPAddress $IPAddress -Zpl $zpl
}
# Optionnel : imprimer une étiquette de test
$test = "^XA^FO30,30^A0N,40,40^FDTest $PrinterName^FS^FO30,90^GB$pw,$ll,2^FS^XZ"
if($UseSpoolerRaw){
Send-ZebraZplQueue -PrinterName $PrinterName -Zpl $test
} else {
Send-ZebraZplTcp -IPAddress $IPAddress -Zpl $test
}
Write-Host "Configuration terminée." -ForegroundColor Green
Variante avec SGD (Set‑Get‑Do)
SGD permet des réglages lisibles et ciblés. Vous pouvez générer un « paquet » de variables et l’envoyer tel quel au port 9100 ou via la file.
function New-ZebraSgdPayload {
[CmdletBinding()]
param(
[Parameter(Mandatory)][int]$WidthDots,
[Parameter(Mandatory)][int]$LengthDots,
[switch]$Persist
)
@"
! U1 setvar "device.languages" "zpl"
! U1 setvar "media.type" "label"
! U1 setvar "zpl.print_width" "$WidthDots"
! U1 setvar "zpl.label_length" "$LengthDots"
$( if($Persist){'! U1 setvar "power.on_reset" "last_state"'} )
"@
}
# Exemple d’envoi
$payload = New-ZebraSgdPayload -WidthDots $pw -LengthDots $ll -Persist:$Persist
Send-ZebraZplTcp -IPAddress $IPAddress -Zpl $payload
Astuce : stockez le contenu SGD/ZPL dans un simple .txt et déployez‑le via GPO (Préférences > Fichier) vers un partage, puis utilisez PowerShell pour l’expédier au moment opportun.
Tableau pratique : formats courants en points
Référence rapide pour les tailles les plus utilisées. Les valeurs sont arrondies au point le plus proche.
| Format (pouces) | Largeur x Longueur | 203 dpi (^PW / ^LL) | 300 dpi (^PW / ^LL) | Remarques |
|---|---|---|---|---|
| 4″ × 6″ | 101,6 mm × 152,4 mm | 812 / 1218 | 1200 / 1800 | Expédition standard |
| 4″ × 4″ | 101,6 mm × 101,6 mm | 812 / 812 | 1200 / 1200 | Inventaire |
| 4″ × 2″ | 101,6 mm × 50,8 mm | 812 / 406 | 1200 / 600 | Codes‑barres |
| 3″ × 2″ | 76,2 mm × 50,8 mm | 609 / 406 | 900 / 600 | Petites étiquettes |
| 2″ × 1″ | 50,8 mm × 25,4 mm | 406 / 203 | 600 / 300 | Actifs/IT |
Bonnes pratiques de déploiement
- Idempotence : testez l’existence du port et de la file avant de créer. Le script ci‑dessus le fait.
- Drivers : pré‑installez les pilotes Zebra (package signé) sur vos masters ou via un outil de gestion.
- Réseau : ouvrez TCP 9100 sur le pare‑feu des imprimantes et segmentez (VLAN) si nécessaire.
- Journalisation : consignez les paramètres envoyés (PW/LL, DPI) pour diagnostiquer facilement.
- Group Policy : distribuez les files aux postes via GPP « Imprimantes » et poussez ZPL/SGD via GPP « Fichier » + Script.
- Firmware : gardez vos imprimantes à jour. Certaines fonctions (ex. auto‑sizing type
^SZ) n’existent qu’à partir d’un certain microprogramme.
Vérifications et tests
Après configuration, validez :
- La file imprime bien en « RAW » sans transformation (évitez le rendu GDI pour le ZPL pur).
- La largeur et la longueur correspondent à la réalité (pas de rognage, pas de saut intempestif).
- La détection de support est correcte (gap vs black mark). Si besoin, lancez une calibration.
Étiquette de test simple :
^XA
^CF0,40
^FO20,20^FDZebra GX420t^FS
^FO20,70^GB200,2,2^FS
^FO20,90^A0N,28,28^FDTaille: ^PW=812 ^LL=1218^FS
^XZ
Calibration et réglages complémentaires
- Calibration : certaines séries acceptent
^XA^JUS^XZ(sauvegarde),^XA^JC^XZ(calibration). Lancer une calibration peut résoudre les détections de fin d’étiquette. - Orientation : si vous devez tourner l’impression, ajoutez
^PO(N, R, I, B). Cela n’affecte pas la largeur/longueur physique. - Densité/Vitesse : réglez‑les via ZPL (
^MDpour la densité,^PRpour la vitesse) ou via des variables SGD ciblées.
Troubleshooting
Quelques symptômes fréquents et leurs pistes :
- Étiquette tronquée en bas : augmentez
^LL(longueur), vérifiez le DPI utilisé dans la conversion. - Impression décalée : ajustez l’offset haut
^LTou la position de départ (^FOdans vos modèles). - Deux étiquettes pour un seul job : l’imprimante peut considérer
^XZcomme fin et passer à l’étiquette suivante. Vérifiez la longueur et la détection de gap/mark. - Caractères imprimés au lieu de code‑barres : vous n’êtes pas en mode ZPL. Forcer
! U1 setvar "device.languages" "zpl". - Pas de sortie : testez TCP 9100, câble, alimentation. Vérifiez que le pilote n’interprète pas le flux (préférez RAW).
- Modèle 300 dpi : recalculer PW/LL avec
DPI=300. Des valeurs 203 dpi donnent un format erroné.
Exemple : déploiement massif
Pour déployer sur des dizaines de sites :
- Centralisez un CSV
Nom;IP;Largeur;Hauteur;Unite;DPI. - Créez un script qui boucle sur les lignes, appelle
New-ZebraTcpPort,New-ZebraPrinter, puis envoie ZPL/SGD. - Exécutez depuis un compte disposant des droits d’ajout de pilotes et d’imprimantes.
Import-Csv .\zebra.csv -Delimiter ';' | ForEach-Object {
$pw = ConvertTo-ZebraDots -Value $_.Largeur -Unit $_.Unite -Dpi $_.DPI
$ll = ConvertTo-ZebraDots -Value $_.Hauteur -Unit $_.Unite -Dpi $_.DPI
$port = New-ZebraTcpPort -IPAddress $_.IP
$drv = Get-ZebraDriverName -ModelPattern 'GX420t'
$prn = New-ZebraPrinter -PrinterName $_.Nom -PortName $port -DriverName $drv
$zpl = Set-ZebraLabelSize -WidthDots $pw -LengthDots $ll -Persist
Send-ZebraZplTcp -IPAddress $_.IP -Zpl $zpl
}
Sécurité, gouvernance et réversibilité
- Traçabilité : journalisez le ZPL envoyé (sans données sensibles). Conservez un hash/version.
- Change management : validez en pré‑production avec quelques imprimantes avant un déploiement global.
- Réversibilité : conservez un « profil d’usine » (jeu de commandes) pour revenir aux valeurs par défaut si nécessaire.
FAQ rapide
Faut‑il envoyer le ZPL via le port 9100 ou via la file ? En réseau, 9100 est simple et direct. En USB/COM, utilisez la file avec envoi RAW (fonction Send-ZebraZplQueue ci‑dessus).
Où définir la détection du média (gap/mark) ? Utilisez SGD media.type (label, continuous) et lancez une calibration si besoin.
Le format change après redémarrage ? Ajoutez la sauvegarde ^JUS ou les variables SGD pertinentes, et vérifiez que l’imprimante conserve son « last state ».
Conclusion
Sous Windows, la méthode réellement scriptable pour fixer la taille d’étiquette d’une Zebra GX420t consiste à envoyer des commandes ZPL/SGD directement à l’imprimante. Combinez Add-PrinterPort et Add-Printer pour créer la file, puis poussez le ZPL de format (^PW, ^LL) — éventuellement persisté avec ^JUS. Le résultat : un déploiement rapide, reproductible, documenté et compatible avec les déploiements massifs.
Annexe : snippets prêts à copier
Envoi ZPL minimal en TCP
$zpl = "^XA^PW812^LL1218^XZ"
$bytes = [System.Text.Encoding]::ASCII.GetBytes($zpl)
$client = [System.Net.Sockets.TcpClient]::new("192.0.2.10",9100)
$stream = $client.GetStream()
$stream.Write($bytes,0,$bytes.Length)
$stream.Close(); $client.Close()
Bloc SGD type
! U1 setvar "device.languages" "zpl"
! U1 setvar "media.type" "label"
! U1 setvar "zpl.print_width" "812"
! U1 setvar "zpl.label_length" "1218"
Création simple d’un port + file
Add-PrinterPort -PrinterHostAddress 192.0.2.10 # Raw 9100 par défaut
Add-Printer -Name "Zebra-GX420t-Expé" -DriverName "ZDesigner GX420t" -PortName "IP_192.0.2.10"
Étiquette de test encadrée
^XA^FO20,20^A0N,30,30^FDHello Zebra^FS^FO10,10^GB780,1180,2^FS^XZ
Note firmware : selon la révision, certaines options comme l’auto‑dimensionnement (^SZ) peuvent ne pas être disponibles. Vérifiez la version et harmonisez‑la lors des déploiements.

