Dieser Artikel erklärt, wie Sie IPP-Drucker auf macOS-Geräten mit Factorial IT konfigurieren. Dazu werden die im Netzwerk verfügbaren Drucker ermittelt, ihre IP-Adressen identifiziert und die Konfiguration über eine benutzerdefinierte MDM-Einstellung in Factorial IT importiert.
IPP-Drucker im Netzwerk scannen
Wenn Sie Ihre Druckerkonfiguration bereits kennen, können Sie diesen Abschnitt überspringen.
- Öffnen Sie das Terminal auf einem macOS-Gerät.
-
Führen Sie folgenden Befehl aus, um alle über das Internet Printing Protocol (IPP) verfügbaren Drucker zu ermitteln:
ippfind - Beachten Sie die Liste der gefundenen Drucker und deren IPP-URIs.
Ermitteln Sie die IP-Adressen der Drucker.
Wenn Sie Ihre Druckerkonfiguration bereits kennen, können Sie diesen Abschnitt überspringen.
- Führen Sie für jeden gefundenen Drucker einen Ping-Befehl aus, um seine Verfügbarkeit zu überprüfen und seine IP-Adresse zu ermitteln:
Ersetzen Sie [printer-hostname] durch den tatsächlichen Hostnamen, der von ippfind angezeigt wird.ping [printer-hostname] - Notieren Sie die IP-Adressen und die zugehörigen IPP-URIs.
Generieren Sie die mobileconfig-Datei
Falls Sie Hilfe beim Generieren der mobileconfig-Datei mit dem Befehl `ippfind` und `ping` benötigen, können Sie dieses Skript auf Ihrem Mac ausführen, während Sie mit Ihrem Büronetzwerk verbunden sind. Die mobileconfig-Datei wird dann in Ihrem Terminal angezeigt.
#!/bin/bash# macOS + bash 3.2 compatible# Discovers IPP printers and generates a .mobileconfig# Dependencies: ippfind, ipptool, uuidgen, ping, nc, plutil, arp# Usage:# ./gen_airprint_profile.sh [-o file.mobileconfig] [-i com.profile.id] [-s CIDR]# Example:# ./gen_airprint_profile.sh -o Factorial IT-AirPrint.mobileconfig -i com.getprimo.printer.airprint -s 192.168.1.0/24set -euo pipefailOUTPUT="AirPrint.mobileconfig"ROOT_ID="com.getprimo.printer.airprint"CIDR=""TIMEOUT_DISC=5PING_WAIT_MS=1000while getopts ":o:i:s:" opt; do case "$opt" in o) OUTPUT="$OPTARG" ;; i) ROOT_ID="$OPTARG" ;; s) CIDR="$OPTARG" ;; \?) echo "Invalid option: -$OPTARG" >&2; exit 2 ;; esacdoneneed() { command -v "$1" >/dev/null 2>&1 || { echo "Missing required tool: $1" >&2; exit 1; }; }need uuidgen; need ping; need plutil; need ipptool# ippfind and nc are recommended; without ippfind the script will fallback to CIDR/ARPcommand -v ippfind >/dev/null 2>&1 || echo "⚠️ ippfind not found: mDNS discovery will be skipped."command -v nc >/dev/null 2>&1 || { echo "nc (netcat) is required for the network fallback."; exit 1; }xml_escape() { sed -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g' \ -e 's/\"/\"/g' -e "s/'/\'/g"}# -------- mDNS discovery via ippfind ----------URIS=()discover_mdns() { [ -x "$(command -v ippfind)" ] || return 0 # --timeout varies across versions; try short IPv4 timeout when available local out if ippfind --help 2>/dev/null | grep -q -- '--timeout'; then out=$(ippfind --timeout ${TIMEOUT_DISC} _ipp._tcp,_print _ipps._tcp,_print -q 2>/dev/null || true) else out=$(ippfind _ipp._tcp _ipps._tcp -q 2>/dev/null || true) fi if [ -n "$out" ]; then while IFS= read -r line; do [ -n "$line" ] && URIS+=("$line") done <<< "$out" fi}# -------- Fallback without mDNS ----------# 1) Build candidate IPs: explicit CIDR (/24 only) or ARP tablecandidates_from_arp() { arp -an 2>/dev/null | awk '{print $2}' | tr -d '()' | grep -E '^[0-9.]+$' | sort -u}candidates_from_cidr() { # Minimal /24 generator (eg, 192.168.1.0/24); other masks are not supported here local cidr="$1" if ! echo "$cidr" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/24$'; then echo "⚠️ Unsupported CIDR for this mini-scanner (only /24): $cidr" >&2 return 1 fi local base="${cidr%/24}" local net=$(echo "$base" | awk -F. '{print $1"."$2"."$3"."}') local i for i in $(seq 1 254); do echo "${net}${i}"; done}# 2) Probe port 631 and try common IPP pathstry_make_uri() { local ip="$1" local path for path in "/ipp/print" "/.well-known/ipp" "/printers/print" "/ipp" "/printers/ipp"; do if ipptool -T 3 -q "ipp://$ip:631$path" get-printer-attributes.test >/dev/null 2>&1; then echo "ipp://$ip:631$path" return 0 fi done for path in "/ipp/print" "/.well-known/ipp" "/ipp"; do if ipptool -T 5 -q "ipps://$ip:631$path" get-printer-attributes.test >/dev/null 2>&1; then echo "ipps://$ip:631$path" return 0 fi done echo "" return 1}discover_fallback() { local candidates if [ -n "$CIDR" ]; then candidates=$(candidates_from_cidr "$CIDR" || true) else candidates=$(candidates_from_arp || true) fi [ -z "$candidates" ] && return 0 local ip uri while IFS= read -r ip; do [ -z "$ip" ] && continue if nc -G 1 -z "$ip" 631 2>/dev/null; then uri=$(try_make_uri "$ip") [ -n "$uri" ] && URIS+=("$uri") fi done <<< "$candidates"}# -------- Collect attributes for each URI ----------IPs=(); Ports=(); Paths=(); Names=(); Models=(); Locs=(); ForceTLS=()extract_components() { local uri="$1" scheme host port path ip name model loc scheme=$(printf '%s' "$uri" | sed -E 's#^([a-zA-Z0-9+.-]+)://.*#\1#') host=$(printf '%s' "$uri" | sed -E 's#^[a-zA-Z0-9+.-]+://([^/:]+).*#\1#') port=$(printf '%s' "$uri" | sed -E 's#^[a-zA-Z0-9+.-]+://[^/:]+:([0-9]+).*#\1#') path=$(printf '%s' "$uri" | sed -E 's#^[a-zA-Z0-9+.-]+://[^/]+(/.*)$#\1#') [ -z "${port:-}" ] && port=631 [ -z "${path:-}" ] && path="/ipp/print" ip=$(ping -c 1 -W ${PING_WAIT_MS} "$host" 2>/dev/null | sed -n '1s/.*(\([0-9.]*\)).*/\1/p') [ -z "${ip:-}" ] && ip="$host" name=""; model=""; loc="" if ipptool -T 5 -q "$uri" get-printer-attributes.test >/tmp/ipp.$$ 2>/dev/null; then name=$(sed -n 's/^printer-info[^=]*= //p' /tmp/ipp.$$ | head -n1) model=$(sed -n 's/^printer-make-and-model[^=]*= //p' /tmp/ipp.$$ | head -n1) loc=$(sed -n 's/^printer-location[^=]*= //p' /tmp/ipp.$$ | head -n1) rm -f /tmp/ipp.$$ fi [ -z "$name" ] && name="$host" [ -z "$model" ] && model="$name" IPs+=("$ip"); Ports+=("$port"); Paths+=("$path"); Names+=("$name"); Models+=("$model"); Locs+=("$loc"); if [ "$scheme" = "ipps" ]; then ForceTLS+=("true"); else ForceTLS+=("false"); fi}# --------- RUN ----------discover_mdnsif [ ${#URIS[@]} -eq 0 ]; then echo "ℹ️ No printer visible via mDNS (ippfind). Attempting network discovery…" discover_fallbackfiif [ ${#URIS[@]} -eq 0 ]; then echo "No IPP printer found" >&2 exit 1fi# Remove duplicates / keep stable ordertmp_uniq="$(mktemp)"printf "%s\n" "${URIS[@]}" | awk '!seen[$0]++' > "$tmp_uniq"URIS=()while IFS= read -r line; do [ -n "$line" ] && URIS+=("$line"); done < "$tmp_uniq"rm -f "$tmp_uniq"# Gather attributesi=0while [ $i -lt ${#URIS[@]} ]; do extract_components "${URIS[$i]}" i=$((i+1))done# --------- Generate .mobileconfig ----------PROFILE_UUID=$(uuidgen)AIRPRINT_UUID=$(uuidgen)MCX_UUID=$(uuidgen)TMP="$(mktemp /tmp/airprint.XXXXXX.mobileconfig)"{cat <<'XML'<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>PayloadContent</key> <array> <dict> <key>AirPrint</key> <array>XMLidx=0for uri in "${URIS[@]}"; do ft="${ForceTLS[$idx]}"; ip="${IPs[$idx]}"; port="${Ports[$idx]}"; path="${Paths[$idx]}" printf ' <dict>\n' printf ' <key>ForceTLS</key>\n' [ "$ft" = "true" ] && printf ' <true/>\n' || printf ' <false/>\n' printf ' <key>IPAddress</key>\n' printf ' <string>%s</string>\n' "$(printf '%s' "$ip" | xml_escape)" printf ' <key>Port</key>\n' printf ' <integer>%s</integer>\n' "$port" printf ' <key>ResourcePath</key>\n' printf ' <string>%s</string>\n' "$(printf '%s' "$path" | xml_escape)" printf ' </dict>\n' idx=$((idx+1))donecat <<XML </array> <key>PayloadDisplayName</key> <string>AirPrint</string> <key>PayloadIdentifier</key> <string>com.apple.airprint.${AIRPRINT_UUID}</string> <key>PayloadType</key> <string>com.apple.airprint</string> <key>PayloadUUID</key> <string>${AIRPRINT_UUID}</string> <key>PayloadVersion</key> <integer>1</integer> </dict> <dict> <key>DefaultPrinter</key> <dict> <key>DeviceURI</key> <string>$(printf '%s' "${URIS[0]}" | xml_escape)</string> <key>DisplayName</key> <string>$(printf '%s' "${Names[0]}" | xml_escape)</string> </dict> <key>PayloadDisplayName</key> <string>Printing</string> <key>PayloadIdentifier</key> <string>com.apple.mcxprinting.${MCX_UUID}</string> <key>PayloadType</key> <string>com.apple.mcxprinting</string> <key>PayloadUUID</key> <string>${MCX_UUID}</string> <key>PayloadVersion</key> <integer>1</integer> <key>UserPrinterList</key> <dict> <key>Printer</key> <array>XMLidx=0for uri in "${URIS[@]}"; do name="${Names[$idx]}"; model="${Models[$idx]}"; loc="${Locs[$idx]}" cat <<XML <dict> <key>DeviceURI</key> <string>$(printf '%s' "$uri" | xml_escape)</string> <key>DisplayName</key> <string>$(printf '%s' "$name" | xml_escape)</string> <key>Location</key> <string>$(printf '%s' "$loc" | xml_escape)</string> <key>Model</key> <string>$(printf '%s' "$model" | xml_escape)</string> <key>PPDURL</key> <string>file://localhost/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Resources/Generic.ppd</string> <key>PrinterLocked</key> <false/> </dict>XML idx=$((idx+1))donecat <<XML </array> </dict> </dict> </array> <key>PayloadDisplayName</key> <string>AirPrint</string> <key>PayloadIdentifier</key> <string>${ROOT_ID}</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>${PROFILE_UUID}</string> <key>PayloadVersion</key> <integer>1</integer></dict></plist>XML} > "$TMP"plutil -lint "$TMP" >/dev/nullplutil -convert xml1 -o "$OUTPUT" "$TMP"rm -f "$TMP"echo "✅ Profile generated: $OUTPUT"echo "🖨️ Default Printer: ${Names[0]} (${URIS[0]})"cat "$OUTPUT"Importieren Sie die Konfiguration in Factorial IT.
- Gehen Sie zu MDM > Profile. Wählen Sie das gewünschte Profil aus.
- Wählen Sie „Benutzerdefinierte MDM-Einstellung hinzufügen“.
- Laden Sie die folgende .mobileconfig- Datei hoch und ersetzen Sie die Platzhalter (IP, UUID usw.) durch die Konfigurationsdaten Ihres Druckers:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>PayloadContent</key> <array> <dict> <key>AirPrint</key> <array> <dict> <key>ForceTLS</key> <false/> <key>IPAddress</key> <string>[IP_ADDRESS]</string> <key>Port</key> <integer>631</integer> <key>ResourcePath</key> <string>[RESOURCE_PATH]</string> </dict> </array> <key>PayloadDisplayName</key> <string>AirPrint</string> <key>PayloadIdentifier</key> <string>com.apple.airprint.[UUID]</string> <key>PayloadType</key> <string>com.apple.airprint</string> <key>PayloadUUID</key> <string>[UUID]</string> <key>PayloadVersion</key> <integer>1</integer> </dict> <dict> <key>DefaultPrinter</key> <dict> <key>DeviceURI</key> <string>ipp://[IP_ADDRESS]/[RESOURCE_PATH]</string> <key>DisplayName</key> <string>[DISPLAY_NAME]</string> </dict> <key>PayloadDisplayName</key> <string>Printing</string> <key>PayloadIdentifier</key> <string>com.apple.mcxprinting.[UUID]</string> <key>PayloadType</key> <string>com.apple.mcxprinting</string> <key>PayloadUUID</key> <string>[UUID]</string> <key>PayloadVersion</key> <integer>1</integer> <key>UserPrinterList</key> <dict> <key>Printer</key> <array> <dict> <key>DeviceURI</key> <string>ipp://[IP_ADDRESS]/[RESOURCE_PATH]</string> <key>DisplayName</key> <string>[DISPLAY_NAME]</string> <key>Location</key> <string>[LOCATION]</string> <key>Model</key> <string>[MODEL]</string> <key>PPDURL</key> <string>file://localhost/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Resources/Generic.ppd</string> <key>PrinterLocked</key> <false/> </dict> </array> </dict> </dict> </array> <key>PayloadDisplayName</key> <string>AirPrint</string> <key>PayloadIdentifier</key> <string>com.getprimo.printer.airprint</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>[UUID]</string> <key>PayloadVersion</key> <integer>1</integer></dict></plist> - Profil speichern und bereitstellen .