Where-Object liefert bei einem Treffer ein Einzelobjekt. Ist das eine Hashtable
(PS7 ConvertFrom-Json -AsHashtable, wie im Docker-Container), war $sameType[0]
eine Schluessel-Suche nach Key 0 (=> $null) statt Array-Index -> Presentation
wurde als "nicht zuordenbar" gewertet und die Einstellung uebersprungen. Unter
Windows PowerShell 5.1 (PSCustomObjects) trat der Fehler nicht auf.
Fix: Where-Object-Ergebnis vor dem Indexieren in @() zwingen. Verifiziert per
Simulation gegen die realen Firefox-ADMX-Exportdaten (Default Search Engine,
URL for Home page).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die "nicht zuordenbar"-Meldung listet jetzt Quell- und Ziel-Presentations
(Typ + Label) auf, damit echte ADMX-Versionsunterschiede sofort sichtbar sind.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- @odata.type-Vergleich normalisiert (fuehrendes '#' egal) -> Text-Presentations
wurden sonst wegen Formatunterschied nicht zugeordnet.
- Zusaetzlicher Fallback: hat die Ziel-Definition genau eine Presentation, wird
sie genutzt (deckt Ein-Feld-Settings wie Textboxen ab).
- Definitions-Auflösung: classType zuerst (User/Device nicht verwechseln), dann
categoryPath bevorzugen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bei ingesteten ADMX mit abweichender Ziel-Version ließ sich eine Presentation
teils nicht zuordnen; bisher wurde die Einstellung dennoch (unvollständig)
gepostet -> 400 BadRequest. Jetzt wird die ganze Einstellung mit klarer Meldung
übersprungen, statt einen kaputten Body zu senden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Custom-ADMX-Definitionen (policyType 'admxIngested') haben tenant-spezifische
IDs -> Binding per Export-Id scheiterte im Ziel-Tenant mit 404. Import löst
solche Definitionen jetzt im Ziel über displayName/classType/categoryPath neu
auf und bindet an die dortige Id; Presentations werden per label/@odata.type
(Fallback: Reihenfolge je Typ) zugeordnet. Eingebaute Vorlagen (admxBacked)
unverändert per stabiler Id. categoryPath wird dafür mitexportiert.
Voraussetzung: dieselbe ADMX ist im Ziel-Tenant importiert; fehlt sie, wird die
betroffene Einstellung mit klarer Meldung übersprungen (Rest wird angelegt).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Graph lehnt definitionValues?$expand=...,presentationValues($expand=presentation)
mit 400 ab ("$expand path too deep, max 1"). Jetzt definitionValues nur mit
'definition' expandieren (Tiefe 1) und presentationValues je definitionValue
separat mit 'presentation' nachladen (jeweils Tiefe 1). Liefert dieselben Daten
für den Re-Import (definition.id, presentation.id, value/values).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Get-GraphPolicyList: $expand=assignments pro Typ absichern. groupPolicyConfigurations
(Administrative Vorlagen) lehnt den Expand teils mit 400 ab -> dann scheiterte das
Laden und der Export ließ die Policies still weg. Jetzt Fallback auf Laden ohne
Zuweisungen, damit der Typ erscheint und exportierbar bleibt.
- Export-PoliciesEndpoint: Detail-Fehler nicht mehr verschlucken, sondern pro Policy
in 'errors' zurückgeben (+ Log).
- Frontend: Export-Fehler werden im Toast gemeldet (kein stiller Teil-Export mehr).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ursache des 404 bei Zugriff über IP/Proxy: .NET-HttpListener bedient den Prefix
http://localhost:8077/ nur bei Host: localhost. socat (L4) reicht den originalen
Host-Header durch -> 404. Jetzt sitzt ein winziger nginx im Container davor, der
den Host-Header auf localhost umschreibt (Upstream [::1]:8077, IPv4 als Fallback).
App-Code bleibt unverändert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
.NET-HttpListener bindet den Prefix "localhost" im Container auf IPv6 ::1, socat
verband aber auf 127.0.0.1 -> "Connection refused". Entrypoint startet die App
jetzt zuerst, erkennt ob IPv4 oder IPv6 antwortet und richtet socat darauf aus.
Kein Eingriff in den App-Code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Ordner docker/ (Dockerfile, docker-entrypoint.sh, docker-compose.yml, README).
Der bestehende App-/Client-Teil (Start.ps1, src/, www/) bleibt unverändert und wird
nur ins Image kopiert. Container-Spezifika laufen ohne Codeeingriff:
- socat-Bridge 0.0.0.0:8080 -> 127.0.0.1:8077 (App bindet weiter nur loopback)
- Datenpfad via XDG_CONFIG_HOME=/data (Volume) - Get-AppDataDir nutzt das auf Linux
- Login über den vorhandenen Device-Code-Flow (WAM/Loopback geht im Container nicht)
Kein Caddy: der vorhandene Reverse-Proxy zieht Port 8080 an.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Staging schließt jetzt start-macos.command, tests/ und .gitattributes aus, damit
sie nicht im Windows-MSI landen. WiX-Harvest ist ohnehin dynamisch — der Build
funktioniert unverändert, das Paket wird nur sauberer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bequemer Launcher für den Mac: prüft pwsh, installiert bei Bedarf einmalig
Microsoft.Graph.Authentication, gibt einen belegten Port frei (auf macOS kein
Auto-Kill) und startet Start.ps1; Argumente (-Port/-NoBrowser) werden
durchgereicht. .gitattributes erzwingt LF für *.sh/*.command, damit der Shebang
auf macOS nicht durch CRLF zerschossen wird.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auf macOS/Linux nutzt Connect-MgGraph den interaktiven Loopback-Browser-Flow
(http://localhost:<zufälliger Port>). Ohne registrierte Loopback-URI scheitert
der Login mit AADSTS50011. Setup-AppRegistration.ps1 legt jetzt zusätzlich
http://localhost an (portagnostisch); App-Registration.md dokumentiert es.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Windows-Verhalten bleibt identisch (Pfade/Temp verifiziert). Portable Anpassungen:
- Get-AppDataDir/Test-IsWindows (Models.ps1): App-Daten unter macOS in
~/Library/Application Support, Linux in $XDG_CONFIG_HOME/~/.config;
auf Windows unveraendert %APPDATA%. Settings- und Policy-Export-Pfad nutzen ihn.
- ReportDir ueber [IO.Path]::GetTempPath() statt $env:TEMP (auf macOS/Linux leer).
- Start.ps1: Browser plattformneutral oeffnen (open/xdg-open/Start-Process);
WMI-Stale-Instanz-Erkennung nur noch auf Windows.
- Datei-/Ordner-Dialog: macOS-nativer osascript-Chooser statt System.Windows.Forms;
auf nicht unterstuetzten Plattformen klare Fehlermeldung.
Auth (Device-Code-Flow) und HttpListener sind bereits plattformneutral. Test auf
echtem macOS steht aus; Packaging (.app/.dmg) folgt separat.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- #1 Spalte "Zuweisungen" in der Policy-Liste (Anzahl); Klick öffnet eine
Detailansicht mit den konkreten Include-/Exclude-Gruppen und Alle Geräte/
Benutzer. Get-GraphPolicyList lädt jetzt $expand=assignments und löst
Gruppennamen in einem Bulk-Lookup (Resolve-GroupNamesBulk) auf.
- #4 Bulk-Zuweisung zeigt statt nur eines Toasts einen Ergebnis-Report pro
Policy (zugewiesen / übersprungen / Fehler) und lädt die Liste neu.
- #5 Post-Import-Zuweisung erhält Alle Geräte/Alle Benutzer (Parität zur
Bulk-Zuweisung) und nutzt dieselbe Ergebnisansicht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
help.md dokumentierte bisher nur App-Management. Neue Abschnitte für den
Geräte-Tab (inkl. Verwaltungsart, Autopilot-Status), Policies (inkl.
Bulk-Gruppenzuweisung mit Add/Replace) und Offboarding (inkl.
Autopilot-Suche); Tab-Übersicht ergänzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deckt die Array-Normalisierung (Repair-SettingsCatalogArrays) inkl.
choiceSettingCollectionValue sowie Remove-PolicyNullProps ab — genau die
Bug-Klasse (PS-5.1-JSON-Roundtrip skalarisiert Ein-Element-Arrays), die uns
mehrfach getroffen hat. 9 Tests, klassische Pester-3/4-Syntax.
Ausführen: Invoke-Pester .\tests
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Autopilot-Status im Geräte-Detail (Profil-Zuweisung / letzter Kontakt)
braucht DeviceManagementServiceConfig.Read.All. Das Flag -IncludeDeviceActions
fügt den Scope jetzt hinzu (Read/Write und Read-Only). Ist ohnehin Offboarding
aktiv, wird die ReadWrite-Variante bevorzugt und die Read-Variante entfernt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
README: Berechtigungstabelle nach Bereich gruppiert (Kern, Geräte-Tab,
Offboarding, Read-Only) inkl. der neuen Abhängigkeiten
DeviceManagementServiceConfig.* (Autopilot-Status im Geräte-Detail,
Autopilot-Suche im Offboarding). App-Registration.md entsprechend ergänzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Offboarding-Suche fand bisher nur managedDevices (Intune). Reine
Autopilot-Geräte (registriert, aber nicht/nicht mehr in Intune enrolled)
tauchten nie auf. Jetzt wird zusätzlich windowsAutopilotDeviceIdentities
durchsucht (Serial: contains(serialNumber), Name: startswith(displayName),
Fehler still ignoriert) und die Treffer werden — dedupliziert per Serial/
Autopilot-Id — gemergt. Für Autopilot-only-Treffer wird das Entra-Objekt per
azureAdDeviceId nachgeladen. offKey nutzt jetzt eine Fallback-Kette, da
Autopilot-only-Geräte keine intuneDeviceId haben.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Policies-Tab: neuer Abschnitt "Gruppen zuweisen (Bulk)" (Add/Replace,
Alle Geräte/Benutzer), Tabs-Übersicht und REST-API-Tabelle ergänzt.
- Geräte-Tab: Verwaltungs-Spalte (Intune/Co-Managed) und Autopilot-Status
im Detail-Panel dokumentiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neuer Toolbar-Button "Gruppen zuweisen" im Policy-Tab: mehreren
ausgewählten Policies (typübergreifend) in einem Schritt dieselben
Include-/Exclude-Gruppen zuweisen.
- Zwei Modi: "Hinzufügen" (bestehende Zuweisungen werden gelesen und
gemergt, da Graph /assign Full-Replace ist) und "Ersetzen".
- Integrierte Include-Ziele "Alle Geräte" (allDevicesAssignmentTarget)
und "Alle Benutzer" (allLicensedUsersAssignmentTarget), dedupliziert
und mit Exclude-Gruppen kombinierbar.
- Invoke-PolicyAssignEndpoint um mode/allDevices/allUsers erweitert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
choiceSettingCollectionValue fehlte in der Array-Key-Liste von
Repair-SettingsCatalogArrays. Beim PS-5.1-JSON-Roundtrip wurde ein
Ein-Element-choiceSettingCollectionValue zum Einzelobjekt entpackt, worauf
Graph den Import mit 400 "Property choiceSettingCollectionValue in payload has
a value that does not match schema" ablehnte (z. B. Default Defender Antivirus
Policy). Jetzt analog zu group-/simpleSettingCollectionValue behandelt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hinter authentifizierten Unternehmens-Proxys (NTLM/Kerberos) scheiterte der
Update-Check mit HTTP 407, weil Invoke-RestMethod keine Anmeldeinformationen
an den Proxy sendet. Jetzt werden die angemeldeten Windows-Credentials an den
System-Proxy durchgereicht; optionaler expliziter Proxy via settings.json ->
update.proxy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neue Spalte "Verwaltung" (Intune vs. Co-Managed) in der Geräteliste,
abgeleitet aus managementAgent; farbige Badges, sortierbar, im CSV-Export
und im Detail-Panel.
- Detail-Panel zeigt Autopilot-Daten (Registriert, Profil zugewiesen am,
letzter Kontakt) per Lookup über die Seriennummer. Ein echtes Importdatum
liefert Graph nicht; verfügbar sind nur diese Zeitstempel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Offboarding: HTML-Report pro Geraet (New-OffboardHtmlReport) + reportUrl;
Dialog-Ergebnis pro Geraet gruppiert + Report-Link
- Update-Check: GET /api/update/check (Gitea releases/latest, Compare-SemVer);
Kopfzeilen-Badge bei neuer Version, Link zur Release-Seite; optionaler read-only Token
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bulk-Offboarding aus dem Geraete-Tab (Checkboxen + Alle, POST /api/offboard/resolve)
- Fix "Geraete konnten nicht geladen werden" (400): managementState raus dem $select,
$orderby entfernt, Namensfilter-Fallback auf deviceName, beta-Endpoint
- Bessere Graph-Fehler-Diagnose (Graph-Body an die Meldung anhaengen)
- Offboard: Grund fuer nicht gefundene Autopilot-Zuordnung sichtbar (autopilotNote)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Policies zusammenfuehren (Settings Catalog -> eine neue Policy, Konfliktaufloesung)
- Geraete-Tab: Gruppen-Filter (Live-Suche) + CSV-Export der angezeigten Liste
- Group Management: bestehende Gruppen als Mitglied hinzufuegen (verschachtelt)
- Fix: Geraete "Invalid Date" (ISO-Normalisierung) + Datums-/Spalten-Sortierung
- Doku (README/CHANGELOG) + Version-Bump 0.1.31
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bulk-Import von Policies (Batches + Fortschritt, Fehler-Isolierung)
- Export/Import-Treue via Raw-JSON (-OutputType Json), null-Collections-Strip,
Settings-Catalog-Reparatur + Korruptions-Erkennung, Git-Resolver
- macOS-Apps in Liste/Suche + Plattform-Filter
- "Gruppe"-Tab durchsucht alle Gruppen (Live-Suche) statt nur Praefix-Gruppen
- Bestehende Gruppe(n) direkt an Apps zuweisen inkl. Mehrfachauswahl
- Fix: Add-GraphAppAssignment merged bestehende Zuweisungen (/assign ersetzt sonst
die komplette Liste) -> kein Ueberschreiben mehr, ein Request fuer alle Ziele
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neu:
- Umbenennen beim Import: Policy-Name vor dem Anlegen anpassbar
(Dialog "Policies importieren"), richtiges Namensfeld je Typ
Behoben:
- Geraete-Export im App Report: entfernter sync-Endpoint
getDeviceInstallStatusReport (400) -> async Export-Job
DeviceInstallStatusByApp; ZIP/CSV-Logik in Get-IntuneReportRows
- Darkmode-Kontrast im Zuweisungs-Dialog (Theme-Variablen statt fester Farben)
- Dialog-Breite: lange Policy-Namen brechen um statt H-Scroll
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docs/App-Registration.md: alle benoetigten Graph-Berechtigungen
(Kern, Geraete-Tab, Read-Only) + Auth-Konfiguration
- docs/Setup-AppRegistration.ps1: legt die App-Registrierung automatisch an
(Rechte, Public-Client-Flow, Redirect-URIs, optional Admin-Consent);
Berechtigungs-IDs werden live aufgeloest
- README/CHANGELOG verlinkt, ToolVersion + build-local auf 0.1.27
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Schritt in release.yml lädt die MSI nach dem GitHub-Release per Gitea-API
(Release per Tag holen/anlegen, gleichnamiges Asset ersetzen, hochladen).
Benoetigt GitHub-Secret GITEA_TOKEN; ohne Token ueberspringt sich der Schritt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bei mehreren ausgewaehlten Policies wird jede als eigene JSON-Datei
heruntergeladen (statt einer gebuendelten Datei). 150ms Pause zwischen den
Downloads gegen verschluckte Browser-Downloads; Dateinamen bei gleichem
Anzeigenamen automatisch eindeutig. Import liest alte Bundles weiterhin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Tab "Policies" zum Sichern und Wiederherstellen von Intune-Policies.
- Backend src/PolicyIO.ps1: typ-getrieben fuer configurationPolicies
(Settings Catalog), deviceCompliancePolicies und deviceConfigurations
- Export als JSON-Download (einzeln/Bundle) + Server-Archiv unter %APPDATA%
- Import per Datei-Upload, immer Neuanlage (nie ueberschreiben), robust fuer
Hashtable (PS7) und PSCustomObject (PS5.1); im Read-Only-Modus ausgeblendet
- Routen in src/Api.ps1; Config-Scope DeviceManagementConfiguration.* auch
nach Settings-Save sichergestellt
- Frontend: Tab + View, Suche/Typ-Filter/Sortierung, Auswahl, Download/Upload
- Version 0.1.25 (Start.ps1, CHANGELOG, README)
- build-local.ps1: x64-.NET-Runtime fuer wix auf ARM64-Windows + echter
Desktop-Pfad
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Suche ruft bei jeder Eingabe die API auf statt lokal zu filtern.
Seriennummer wird per exaktem eq-Filter parallel gesucht und mit
Namens-Treffern zusammengeführt (Graph unterstützt kein startswith
auf serialNumber).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
margin/padding-right überschrieben damit das Eingabefeld korrekt
dargestellt wird und Texteingabe sichtbar ist.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wipe-Button mit eigenem Modal: Checkbox ob Benutzerdaten behalten werden
(keepUserData). Suchfeld auf max-width 600px vergrößert.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Windows Autopilot Reset via wipe mit keepEnrollmentData:true.
Button nur bei Windows-Geräten sichtbar, separate Warnmeldung.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neuer Haupttab "Geräte" mit Geräteliste (filterbar nach OS/Compliance),
Detail-Panel mit vollständigen Gerätedaten und Aktions-Buttons:
Sync, Neustart, Sperren, Diagnose, BitLocker-Rotation, Retire.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Neuer Tab "Benutzer" im Group Management: Benutzer suchen und alle
Gruppen anzeigen, in denen dieser Mitglied ist (transitiveMemberOf).
Gruppen filterbar, mit Typ-Badge (Sicherheitsgruppe/M365/Verteiler).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- App Report: Zahlen per AppInstallStatusAggregate Export Job (ZIP/CSV)
- Geräte-Export: getDeviceInstallStatusReport statt deviceStatuses
- Benutzersuche: ConsistencyLevel+$count für Umlaut-Kompatibilität
- Gruppen: Mitglieder entfernen in modalMembers und Group Explorer (gex)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- WiX auf Version 4.0.6 festgenagelt (keine OSMF-EULA-Pflicht wie bei v7)
- harvest-Subcommand entfernt (nicht in 4.0.6 verfügbar)
- Fragment-Generierung (AppFiles.wxs) direkt via PowerShell XML-API
- Extension auf WixToolset.UI.wixext/4.0.6 fixiert
- build-local.ps1 für lokale Tests in der Windows-VM
- Lokaler Build erfolgreich getestet: 1.5 MB MSI, Installer-Wizard OK
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- .github/workflows/release.yml: baut bei v*-Tags ein MSI und veröffentlicht es als GitHub Release
- installer/Intune-Manager.wxs: WiX v4 Package-Definition (Program Files, Startmenü-Shortcut)
- installer/License.rtf: Lizenztext für den Installer-Dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>