Products / Workplace IT

DYMO Ticket Bridge

A cloud-to-hardware bridge that auto-prints IT support tickets to a physical label printer at a school loan desk. Cloud API at one end, a secured switch port and a real patch panel at the other.

PowerShell Zoho Desk API OAuth 2.0 Power Automate DYMO Connect Cisco IOS VLAN / DHCP Structured cabling
Live · deployed at the loan desk

The full-stack-to-the-wall-jack job. Anyone can wire a script to an API. Far fewer can also stand up the VLAN, secure the switch port, reserve the address, and physically trace a dead cable across a building. This build spans both, and the infrastructure half is the part AI literally cannot perform.

// the problem

Getting a cloud ticket onto a physical label

The school already had a working intake: a Microsoft Form fires Power Automate, which opens a Zoho Desk ticket. The IT Manager wanted each ticket to also print a physical label at the loan desk, so whoever's on shift just grabs it and goes, but was blocked by Zoho's thin docs. The key insight: no cloud service can reach a local printer directly. You need a small local agent as a bridge, which reframes it from "a Zoho feature" to "a tiny, secure local program."

CLOUD: MS Form -> Power Automate -> Zoho Desk <-- outbound HTTPS poll (~30s) | LOAN-DESK PC (Windows): | Bridge (PowerShell) --------------------- + |- state.json (printed IDs + watermark) |- config.json (Zoho keys, dept + view ID) +- DYMO Connect (localhost:41951) --USB--> DYMO LabelWriter

Outbound only. The PC reaches out to Zoho like a browser. Nothing on the internet connects in, no open ports, no tunnel, no firewall changes. That security posture is what made it an easy IT sign-off.

// the software

The bridge, and why it never double-prints

Poll the exact staff View, not a filter

The bridge fetches a specific saved Zoho Desk View by viewId + departmentId, mirroring exactly what staff see in the UI, rather than reconstructing a department+status filter that could subtly drift from it.

Watermark de-dupe

One integer (the highest ticket number printed) makes the whole thing idempotent: any returned ticket above the watermark is new, gets printed, and the watermark advances. No growing state, no double-prints. Print first, then save state, so a crash risks one duplicate, never a missed label.

Least-privilege, revocable auth

Outbound-only OAuth 2.0 scoped to Desk.tickets.READ only, via a refresh token that can be revoked instantly if the PC is ever compromised. Credit-optimised polling (filter by modified time) means most polls are one cheap call, well inside the API credit budget.

Self-healing service

A system-tray controller (Start/Stop/Restart) with hidden auto-start at logon via Task Scheduler. The label prints three fields landscape: ticket number, student name, and username only (everything before the @) so a full email is never printed.

// the half that's all me

Networking & infrastructure

This is the clearest "human covers for AI" work in the build. AI wrote the PowerShell to my spec; none of the below is something it can do.

Switch port config (Cisco IOS)

Configured the access port for the printer on the distribution switch: switchport mode access, access VLAN 50 (the printer VLAN), locked down with port-security + sticky MAC and a restrict violation mode so only the printer's MAC can use the port. Final home: GigabitEthernet1/0/36.

DHCP reservation

Rather than a fragile device-side static IP, pulled the printer's MAC from the switch (show mac address-table) and created a reservation on the DHCP server so it always gets the same address on VLAN 50, stable and surviving firmware resets. Then added it over TCP/IP to other machines so it's shared.

Physical layer / LAN tools

When the port came up notconnect and a laptop wouldn't link, I diagnosed it as physical. A Fluke IntelliTone Pro 200 toner + probe traced the run and revealed the patch panel was mislabelled (marked 150, actually terminated on 152). Re-patched to a live switch port and brought it online. Classic "the config was never the problem" cable fault.

// honest scoring

The duo split — 50% AI · 50% me

In raw "who typed the code," AI did more, it wrote all the PowerShell (bridge, auth, tray controller, task installer) and the label template. But a whole second discipline, network engineering right down to a physical patch panel, is entirely mine, and it's the half AI literally cannot perform. That pulls an AI-led software project back to an even, true-duo build. My domain knowledge also stopped it being subtly wrong: I knew the target was a saved View, not a department+status filter, and I diagnosed the killers (the label saved as .dymo not .label, and the empty-$PSScriptRoot crash that only hit when auto-launched).

// updates

Project Log

On the network, shared, and printing

Moved the printer off USB: configured the Cisco switch port on VLAN 50 with sticky-MAC security, reserved its IP in DHCP, toned out a mislabelled cable to get the run live, and shared it to other PCs over TCP/IP. Deployed and printing at the loan desk.

The two bugs that mattered

The label had been saved as .dymo not .label, so a redesign never actually took effect. Then the big one: $PSScriptRoot came back empty when auto-launched, crashing the bridge before it could even log, which is why it "only worked when typed by hand." Fixed with robust path resolution.

Bridge, auth and hardening

Polling design over webhooks (my call, for the no-inbound-ports security win), the watermark de-dupe, OAuth Self Client into a least-privilege refresh token, DYMO Connect's local service with a token-substituted label, a tray controller, and hidden auto-start. A fun, fast build with a real deployment at the end of it.