Files
Intune-Manager/CHANGELOG.md
T
marcoandClaude Opus 4.8 32e1506be9
Build & Release MSI / build-msi (push) Canceled after 0s
v0.1.36 — Bulk-Gruppenzuweisung für Policies und Autopilot im Offboarding
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-16 12:01:45 +02:00

467 lines
35 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
Format orientiert an [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
Versionierung folgt [Semantic Versioning](https://semver.org/lang/de/) — solange das Tool noch in der `0.x.y`-Phase ist, sind Breaking Changes erlaubt.
---
## [0.1.36] - 2026-09-16
Bulk-Gruppenzuweisung für Policies und Autopilot im Offboarding.
### Neu
- **Gruppen zuweisen (Bulk)** im Policies-Tab: mehreren ausgewählten Policies (typübergreifend) in einem Schritt dieselben **Include-/Exclude-Gruppen** zuweisen — plus die integrierten Ziele **Alle Geräte** und **Alle Benutzer**. Zwei Modi: **Hinzufügen** (bestehende Zuweisungen bleiben erhalten und werden gemergt, da Graph `/assign` die komplette Liste ersetzt) und **Ersetzen**. Neuer Parameter `mode`/`allDevices`/`allUsers` an `POST /api/policies/assign`.
- **Offboarding durchsucht jetzt auch Autopilot**: Reine Autopilot-Geräte (registriert, aber nicht/nicht mehr in Intune enrolled) tauchten bisher nicht auf. Die Suche fragt zusätzlich `windowsAutopilotDeviceIdentities` ab (Seriennummer bzw. Anzeigename), dedupliziert gegen die Intune-Treffer und lädt für Autopilot-only-Geräte das Entra-Objekt per `azureAdDeviceId` nach.
### Doku
- README: vollständige Graph-Berechtigungen für den vollen Funktionsumfang, nach Bereich gruppiert (Kern, Geräte-Tab, Offboarding, Read-Only) — inkl. `DeviceManagementServiceConfig.*` (Autopilot-Status im Geräte-Detail, Autopilot-Suche im Offboarding). `docs/App-Registration.md` und `docs/Setup-AppRegistration.ps1` (`-IncludeDeviceActions`) entsprechend ergänzt.
---
## [0.1.35] - 2026-09-15
Settings-Catalog-Import-Fix und Update-Check hinter Proxy.
### Behoben
- **Settings-Catalog-Import** (400 „Property choiceSettingCollectionValue … does not match schema"): `choiceSettingCollectionValue` fehlte in der Array-Normalisierung. Beim JSON-Roundtrip unter PowerShell 5.1 wurde ein Ein-Element-`choiceSettingCollectionValue` zum Einzelobjekt entpackt und von Graph abgelehnt (z. B. „Default Defender Antivirus Policy"). Wird jetzt wie `group-`/`simpleSettingCollectionValue` behandelt.
- **Update-Check hinter authentifiziertem Proxy** (HTTP 407): Der Versions-Check schlug hinter Unternehmens-Proxys (NTLM/Kerberos) still fehl, weil `Invoke-RestMethod` keine Anmeldeinformationen an den Proxy sendete. Die angemeldeten Windows-Credentials werden jetzt an den System-Proxy durchgereicht; optionaler expliziter Proxy über `settings.json → update.proxy`.
---
## [0.1.34] - 2026-09-14
Verwaltungsart in der Geräteliste, Autopilot-Zeitstempel im Detail.
### Neu
- **Spalte „Verwaltung"** in der Geräteliste: zeigt je Gerät, ob es **Intune** (reines MDM) oder **Co-Managed** (ConfigMgr + Intune) ist — abgeleitet aus `managementAgent`. Farbige Badges, sortierbar, auch im CSV-Export und im Detail-Panel.
- **Autopilot-Infos im Geräte-Detail**: Beim Auswählen eines Windows-Geräts wird die Autopilot-Identity per Seriennummer nachgeladen und zeigt **Registrierungsstatus**, **Profil zugewiesen am** (`deploymentProfileAssignedDateTime`) und **letzter Autopilot-Kontakt** (`lastContactedDateTime`). Hinweis: Ein exaktes Autopilot-Importdatum liefert Microsoft Graph nicht; angezeigt werden die verfügbaren Zeitstempel. Kein Performance-Einfluss auf die Liste (Lookup nur pro ausgewähltem Gerät), keine neue Berechtigung nötig.
---
## [0.1.33] - 2026-09-13
Offboarding-Report und Update-Hinweis.
### Neu
- **Offboarding-Report**: Nach dem Ausführen erzeugt das Offboarding einen **HTML-Report** (`/reports/offboard-report-<zeit>.html`) im Stil des Zuweisungs-Reports — mit KPIs (Geräte / Aktionen / Erfolg / Fehler) und **pro Gerät** einer Tabelle der ausgeführten Löschungen (Dienst · Aktion · Status · Meldung). Das Ergebnis im Dialog ist jetzt ebenfalls **pro Gerät gruppiert**, plus ein Button „HTML-Report öffnen".
- **Update-Hinweis**: Beim Start prüft die App (nicht-blockierend) die neueste Release-Version über **Gitea** und zeigt bei einer neueren Version ein **Badge in der Kopfzeile** mit Link zur Release-Seite (dort MSI herunterladen → In-Place-Upgrade). Nur Lesezugriff; optionaler read-only Token via `settings.json → update.token`, falls das Repo privat ist. Neuer Endpoint `GET /api/update/check`.
---
## [0.1.32] - 2026-09-11
Bulk-Offboarding aus dem Geräte-Tab, Geräte-Ladefehler behoben, bessere Graph-Diagnose.
### Neu
- **Bulk-Offboarding aus dem Geräte-Tab**: Geräte per Checkbox (inkl. „Alle sichtbaren") auswählen und über den Button **„Offboarden"** direkt in den Offboard-Dialog übergeben — kombinierbar mit dem Gruppen-Filter (z. B. alle Geräte einer Gruppe). Die Auswahl wird server-seitig zu vollständigen Offboard-Objekten aufgelöst (Entra-Object-Id + Autopilot-Id nachgeladen). Neuer Endpoint `POST /api/offboard/resolve`. Im Read-Only-Modus ausgeblendet.
### Behoben
- **„Geräte konnten nicht geladen werden" (400 BadRequest)**: Intunes DeviceFE-Backend lehnte die Abfrage ab. Ursachen entfernt: `managementState` ist kein gültiges `$select`-Feld (raus), `$orderby` wird nicht mehr gesendet (Sortierung macht das Frontend), und der Namensfilter fällt bei nicht unterstütztem `startswith` automatisch auf `deviceName`-only zurück. Geräte-Endpoints nutzen jetzt `beta` (wie der Offboard-Abruf).
- **Bessere Graph-Fehler-Diagnose**: Bei Nicht-Retry-Fehlern wird der **Graph-Fehler-Body** an die Meldung gehängt (statt nur „BadRequest") — die eigentliche Ursache steht jetzt im Log/Toast.
- **Offboarding**: Wird eine Autopilot-Zuordnung nicht gefunden, zeigt der Dialog jetzt den **Grund** (fehlende Berechtigung vs. kein Seriennummer-Treffer), statt kommentarlos „Autopilot: –".
---
## [0.1.31] - 2026-09-11
Policy-Konsolidierung, Geräte-Export nach Gruppe, Gruppen-in-Gruppen, Geräte-Fixes.
### Neu
- **Policies zusammenführen** (Settings Catalog): Mehrere Settings-Catalog-Policies zu **einer neuen** Policy vereinen. Gleiche Einstellungen werden einmal übernommen, **Konflikte** (gleiche `settingDefinitionId`, anderer Wert) werden vor dem Anlegen angezeigt und pro Konflikt aufgelöst. Button „Konsolidieren" im Policies-Tab (ab 2 gewählten Settings-Catalog-Policies). Neuer Endpoint `POST /api/policies/consolidate`.
- **Geräte nach Gruppe exportieren**: Im **Geräte**-Tab neuer **Gruppen-Filter** (Live-Suche) — die Liste zeigt nur die Geräte der Gruppen-User (inkl. verschachtelter Gruppen) — plus **CSV-Export** der aktuell angezeigten Liste. Kombinierbar mit Suche/OS/Compliance. Neuer Endpoint `GET /api/groups/{id}/devices/export`.
- **Gruppen zu Gruppen hinzufügen**: Im Group-Management-Tab „Benutzer | Gruppen hinzufügen" ein Umschalter **Benutzer / Gruppen** — eine bestehende Gruppe als Mitglied (verschachtelte Gruppe) zur gewählten Gruppe hinzufügen.
### Behoben
- **Geräte „Invalid Date"**: `lastSyncDateTime`/`enrolledDateTime` werden jetzt server-seitig als ISO 8601 normalisiert (`ConvertTo-IsoDate`) — vorher kam unter PowerShell 5.1 ein nicht parsbares Format an. Anzeige zusätzlich robust (ungültig → „—").
- **Geräte-Sortierung**: Die Spalten-Sortierung war komplett wirkungslos (Header-Feldnamen ≠ Item-Properties). Jetzt sortieren alle Spalten korrekt, **Datums-Spalten numerisch** nach Zeitstempel (Klick auf „Letzter Sync" / „Eingeschrieben").
---
## [0.1.30] - 2026-09-03
Policy-Bulk-Import gehärtet, macOS-Apps, Gruppen-Suche & Direkt-Zuweisung an Apps.
### Neu
- **Bulk-Import von Policies**: Mehrere Policy-Dateien (oder eine Bundle-Datei) auf einmal importieren. Läuft server-seitig in Batches à 5 mit Fortschrittsanzeige und Fehler-Isolierung pro Batch — umgeht das 180-s-Timeout einzelner Requests.
- **macOS-Apps** erscheinen jetzt in App-Liste und -Suche (DMG, PKG, LOB, Defender, Edge, M365, VPP) mit eigenen Typ-Labels. Neuer **Plattform-Filter** (Alle / Windows / macOS).
- **Gruppen-Suche** im Ziel-Panel: Der frühere „Abteilung"-Tab heißt jetzt **„Gruppe"** und durchsucht per Live-Suche **alle** Tenant-Gruppen (statt nur Präfix-Gruppen). Auswahl bleibt über mehrere Suchen erhalten.
- **Bestehende Gruppe(n) direkt einer App zuweisen**: Im Dialog „Zuweisung hinzufügen" neue Option „Bestehende Gruppe" (Required/Available) mit Gruppensuche und **Mehrfachauswahl** (Chips).
### Behoben
- **App-Zuweisung überschrieb bestehende Zuweisungen**: `Add-GraphAppAssignment` nutzte die `/assign`-Action mit nur einer Zuweisung — diese ersetzt aber die komplette Liste. Jetzt werden bestehende Zuweisungen geladen, neue gemergt (Duplikate übersprungen) und in **einem** Request geschickt. Behebt sowohl die Mehrfach-Zuweisung als auch stillen Verlust vorhandener Zuweisungen beim Einzel-Hinzufügen.
- **Policy-Export/-Import-Treue** (Windows PowerShell 5.1): Policy-Details werden als **rohes JSON** von Graph geholt (`-OutputType Json`), sonst skalarisierte der Hashtable-Modus Ein-Element-Collections (z. B. `printerNames`) → 400 beim Re-Import.
- **Configuration-Profile-Import**: `null`-Werte für nicht-nullbare Collections werden entfernt (400 `ModelValidationFailure`).
- **Settings-Catalog-Import**: Reparatur leerer/verstümmelter Collections (`[""]`, `{}`), Rettung stringifizierter `*TemplateReference`-Felder und **klarer Abbruch** bei irreparabel beschädigten Quelldateien (alte Exporte mit zu geringer JSON-Tiefe).
- **Git-Snapshot**: `git` wird jetzt auch über bekannte Installationsorte gefunden, falls es nicht im (veralteten) PATH des Server-Prozesses liegt.
---
## [0.1.29] - 2026-08-24
Geräte-Offboarding (v1).
### Neu
- **Geräte-Offboarding** als neue Ansicht: Geräte über **Intune, Autopilot und Entra ID** hinweg entfernen (Decommissioning). Portiert aus dem [Device Offboarding Manager](https://github.com/ugurkocde/DeviceOffboardingManager) von Ugur Koc (MIT-Lizenz).
- Suche per Gerätename/Seriennummer, Auflösung der IDs über alle drei Dienste (`$batch`)
- **Recovery-Keys vor dem Löschen**: BitLocker/FileVault und LAPS-Passwörter werden angezeigt
- Bestätigungs-Dialog mit Dienst-Auswahl (Entra löschen/deaktivieren, Intune, Autopilot), Pflicht-Bestätigung und Ergebnis-Liste; **403/Multi-Admin-Approval** wird abgefangen
- Im **Read-Only-Modus gesperrt**
- Neue Endpoints: `GET /api/offboard/search`, `POST /api/offboard/keys`, `POST /api/offboard/execute` (neues Modul `src/Offboard.ps1`)
- Zusätzliche Berechtigungen dokumentiert; Setup-Skript-Schalter `-IncludeOffboarding`. (MDE-Offboarding bewusst nicht in v1.)
---
## [0.1.28] - 2026-08-24
Umbenennen beim Import, UI-Fixes, Geräte-Export repariert.
### Neu
- **Umbenennen beim Import**: Vor dem Anlegen kann jeder importierten Policy im neuen Dialog „Policies importieren" ein anderer Name gegeben werden (das richtige Namensfeld je Typ — `name`/`displayName` — wird gesetzt).
### Behoben
- **Geräte-Export im App Report**: Der von Graph entfernte synchrone Endpoint `getDeviceInstallStatusReport` (400 „Resource not found for the segment") ist durch den asynchronen Export-Job **`DeviceInstallStatusByApp`** ersetzt (ZIP/CSV-Auswertung, tolerantes Spalten-Mapping). ZIP/CSV-Logik in `Get-IntuneReportRows` ausgelagert.
- **Darkmode-Kontrast** im Zuweisungs-Dialog: Gruppen-Chips nutzen jetzt die Theme-Variablen (`--surface-strong`/`--ink` statt fester heller Farben) — heller Text auf hellem Chip behoben.
- **Dialog-Breite**: Lange Policy-Namen im Zuweisungs-/Import-Dialog brechen jetzt um (`overflow-wrap`/`flex-wrap`) statt horizontal zu scrollen; das Fenster passt sich der Breite an.
---
## [0.1.27] - 2026-08-23
Policy-Import härter, Administrative Vorlagen, Zuweisung nach Import, Git-Snapshot, App-Registrierungs-Doku.
### Neu
- **Administrative Vorlagen (ADMX / `groupPolicyConfigurations`)** als vierter Policy-Typ für Export und Import. Beim Import wird die Konfigurations-Hülle angelegt und jede Einstellung einzeln über `definition@odata.bind` / `presentation@odata.bind` angehängt (eingebaute ADMX-Definitionen sind tenantübergreifend gültig). Neuer Endpoint `GET /api/policies/administrativetemplate`.
- **Zuweisung direkt nach Import**: Dialog listet die neu angelegten Policies und lässt **pro Policy Include-/Exclude-Gruppen** im Ziel-Tenant zuweisen (Typeahead über die vorhandene Gruppensuche). Neuer Endpoint `POST /api/policies/assign` (nutzt die typ-spezifische `/assign`-Action für alle vier Typen).
- **Git-Snapshot (versioniertes Policy-Backup)**: Button „Git-Snapshot" schreibt alle Policies aller Typen als JSON in einen konfigurierten lokalen Git-Ordner und committet sie (optional `git push` über den vorhandenen Credential-Helper). Stabile Dateinamen + deterministische, zeitstempel-freie Ausgabe → saubere Diffs. Neue Settings-Sektion `policyBackup` (`gitRepoPath`, `push`).
- Import akzeptiert jetzt auch **Git-Snapshot-Dateien** (Feld `policyType` zusätzlich zu `exportType`).
- **Doku + Provisioning-Skript für die App-Registrierung**: [`docs/App-Registration.md`](docs/App-Registration.md) listet alle benötigten delegierten Graph-Berechtigungen (Kern, Geräte-Tab, Read-Only) samt Auth-Konfiguration; [`docs/Setup-AppRegistration.ps1`](docs/Setup-AppRegistration.ps1) legt die Registrierung automatisch an bzw. aktualisiert sie (Rechte, Public-Client-Flow, Redirect-URIs, optional Admin-Consent) — Berechtigungs-IDs werden live aufgelöst, keine fest verdrahteten GUIDs.
### Behoben
- **Settings-Catalog-Import** war gegen Graph-Schema-Fehler anfällig: verschachtelte Collection-Properties (`children`, `*SettingCollectionValue`) werden jetzt konsequent als Arrays serialisiert (repariert PowerShell-5.1-JSON-Roundtrip-Schäden), `null`-Collections werden zu `[]` (Graph verlangt `Nullable=False`), der Wrapper-`@odata.type` wird je Setting gesetzt und das read-only `id`-Feld entfernt.
- **Phantom-Fehler beim Import**: ein fehlendes `fileNames`-Feld erzeugte über `@($null)` einen Geisterdurchlauf im Archiv-Pfad und meldete fälschlich „1 fehlgeschlagen".
- **Tenant-Wechsel**: das Frontend zeigte weiter die Apps/Gruppen des vorherigen Tenants, weil die Lade-Guards nicht zurückgesetzt wurden. Alle datentragenden Caches werden jetzt beim Wechsel verworfen (`resetClientState`).
- **WAM-Anmeldefenster** kommt beim Login/Tenant-Wechsel zuverlässig in den Vordergrund (AttachThreadInput + kurzer ALT-Tap zum Lösen des Windows-Foreground-Locks).
---
## [0.1.26] - 2026-08-21
Multi-Tenant, Pro-Tenant-Vorgaben, RPA entfernt.
### Neu
- **Multi-Tenant-Modus** (umschaltbar in den Einstellungen, Single/Multi): mehrere Mandanten mit **je eigener App-Registrierung**; Umschalter in der Topbar mit **Sofort-Reconnect**. Bestehende Single-Tenant-Konfiguration wird verlustfrei übernommen.
- **Pro-Tenant-Vorgaben** mit globalem Fallback: **Abteilungs-Präfixe** sowie **Required-/Available-Gruppen-Naming** je Profil überschreibbar (leer = globale Vorgabe).
- **Policy-Export als Einzeldateien** bei Mehrfachauswahl (statt Bundle).
- **CI**: gebaute MSI wird zusätzlich als **Gitea-Release-Asset** gespiegelt (Secret `GITEA_TOKEN`).
- Hilfe-Fenster: Hinweis „Entwickelt von WendeIT – Marco Wende".
### Geändert / Entfernt
- **RPA-Funktion entfernt**: RPA-Tab, RPA-Einstellungen und RPA-Test-Anzeige sind nicht mehr vorhanden.
- Setup-Zwang gelockert: nur **Tenant ID + Client ID** sind Pflicht; Abteilungs-Präfixe sind optional.
- Klarere Fehlermeldung bei nicht erreichbarem lokalen Server (statt „Failed to fetch").
---
## [0.1.25] - 2026-08-19
Policy Export/Import und Geräte-Tab.
### Neu
- **Policies-Tab**: Export und Import von Intune-Policies — **Settings Catalog** (`configurationPolicies`), **Compliance Policies** (`deviceCompliancePolicies`) und **Konfigurationsprofile** (`deviceConfigurations`)
- Tabelle über alle drei Typen mit Suche, Typ-Filter und Sortierung; Auswahl per Checkbox
- **Export** als JSON-Download (einzeln oder als gebündelte Datei bei mehreren) — zusätzlich server-seitig unter `%APPDATA%\IntuneAppManager-Web\policy-exports` archiviert
- **Import** per Datei-Upload (einzelne Envelopes oder Bundle) — legt Policies **immer als Neuanlage** an, überschreibt nie bestehende; im Read-Only-Modus ausgeblendet
- Neuer Scope `DeviceManagementConfiguration.ReadWrite.All` (bzw. `.Read.All`) wird automatisch zur Verbindung ergänzt
- Neue Endpoints: `GET /api/policies/{settingscatalog|compliance|configuration}`, `POST /api/policies/export`, `GET /api/policies/exports`, `POST /api/policies/import`
---
## [0.1.24] - 2026-07-03
Navigation-Tabs, Group Management, Read-Only-Modus, App Report, CSV-Import.
### Neu
- **Navigation-Tabs** im Topbar: *App Management* | *Group Management* | *App Report* — Topbar-Grid auf 3 Spalten (Brand | Nav | Actions) erweitert
- **Group Management** als eigene View (statt Modal): Mitglieder & Export, Benutzer hinzufügen, CSV-Import — drei Tabs, linke Gruppen-Suche + rechte Aktionspane
- **Read-Only-Modus**: `clientIdRo` + `scopesRo` in Settings; Verbindung versucht RW, fällt bei Fehler auf RO zurück; `body.read-only`-CSS-Klasse blendet alle Schreib-Elemente aus (Buttons, Tabs, Formular-Bereiche)
- **−R / −A Buttons** pro App-Zeile: Gruppe direkt aus Required- oder Available-Zuweisung entfernen (mit Gruppen-Picker bei mehreren)
- **App Report** (neuer Tab): Installationszähler für alle Apps via `deviceStatuses` aggregiert; Tabelle sortierbar, Suchfilter; CSV-Export der gefilterten Ansicht
- **Geräte-Export pro App**: Button in jeder Zeile des App Reports → `GET /api/apps/devicestatus?appId=` → CSV mit Gerätename, Benutzer, Status, Fehlercode, OS-Version, Sync-Datum
- **CSV-Import** im Group Management: UPNs/E-Mails einfügen oder CSV hochladen; automatische Spalten-Erkennung (Header `UserPrincipalName`/`Mail`/`Email`/`UPN`; Quoted-Fields; `,`/`;`/Tab); Graph-Batch-Lookup; Vorschau-Tabelle mit ✓/✗; Ergebnis-Banner mit farbigen Chips (hinzugefügt / bereits Mitglied / Fehler / nicht gefunden)
- **Toast-Z-Index** auf 3000 angehoben (war 1000 → lag hinter Modals mit z-index 1500)
- **Neuer Endpoint** `POST /api/groups/resolve-upns` — UPN-Liste → UserId + DisplayName via $batch
- **Neuer Endpoint** `GET /api/apps/devicestatus?appId=` — Geräte-Installationsstatus einer App
### Geändert
- **Group Management Modal** zur eigenständigen View umgebaut — keine doppelten IDs mehr
- **`openGroupExportModal()`** leitet jetzt auf `switchMainView('groups')` um
- **`switchMainView(view)`** verwaltet alle drei Views (apps / groups / report)
- **`applyReadOnlyMode()`** schaltet aktiven Schreib-Tab automatisch auf Export zurück wenn Read-Only einsetzt
- **Settings-Modal**: Felder `setClientIdRo` und `setScopesRo` hinzugefügt
- **`GET /api/status`**: liefert jetzt `readOnly: bool`
- **`POST /api/connect`**: setzt `$script:State.ReadOnly` nach RO-Fallback
- **`POST /api/disconnect`**: setzt `ReadOnly = $false` zurück
- **App Report Backend**: mehrfach überarbeitet — `installSummary` (400 für alle App-Typen ohne `DeviceManagementManagedDevices.Read.All`), `getAppInstallSummaryReport` (404 in beta und v1.0 ohne MDM-Berechtigung) → finaler Ansatz: `deviceStatuses` via `$batch` aggregiert
### Behoben
- **`$script:State.ReadOnly` Property-Fehler**: `[pscustomobject]` erlaubt keine dynamischen Properties — `ReadOnly = $false` musste in der Definition in `Start.ps1` stehen
- **Duplicate-ID-Bug**: `gexSearch`, `gexMembersArea` etc. existierten doppelt (alt: im Modal-Body, neu: in `#groupMgmtView`) — Modal-Body geleert
### Technisch
- `src/Models.ps1`: `clientIdRo`, `scopesRo` als optionale Settings-Felder
- `src/Api.ps1`: `Sync-ConfigFromSettings` + `Get-StatusEndpoint` + `Invoke-ConnectEndpoint` + `Invoke-DisconnectEndpoint` für RO-Logik erweitert; `Get-AppInstallReportEndpoint` (deviceStatuses-Aggregation); `Get-AppDeviceStatusEndpoint`; `Resolve-UpnsEndpoint`
- `www/styles.css`: `.topbar-nav`, `.nav-tab`, `.group-mgmt-view`, `.app-report-view`, `.app-report-table`, `.sortable`, `.btn-report-device-export`, `.csv-import-*`, `.csv-result-*`; `body.read-only`-Regeln erweitert um `#gexPaneImport` und `[data-tab="import"]`
---
## [0.1.23] - 2026-05-21
Setup-Datei nativer Apps aktualisierbar + Microsoft-Graph-Audit-Fixes.
### Neu
- **Setup-Datei aktualisieren** (Phase 1: `.intunewin` / win32LobApp): im App-Detail neuer Abschnitt *Setup-Datei* mit Button, der eine neue Setup-Datei von einem lokalen Server-Pfad hochlaedt und als neue contentVersion aktiviert — inkl. optionaler neuer Versionsnummer (`displayVersion`). Voller Graph-Upload-Flow: contentVersion → file → Azure-Blob-Chunk-Upload → commit → committedContentVersion. Vendor-verwaltete Apps (PMPC/Robopack) sind ausgeschlossen. MSI/MSIX folgen in spaeteren Phasen
- **Kategorie-Filter** in der App-Liste: neuer Dropdown, der sich dynamisch aus den vorkommenden App-Kategorien fuellt (inkl. *Ohne Kategorie*)
- **Kategorien-Anzeige** im App-Detail (immer sichtbar; "Default" wenn keine zugewiesen)
- **Mehrere Abteilungs-Praefixe** konfigurierbar (z.B. `abt-hm` *und* `abt-extern` parallel): neues Schema `departments.prefixes[]`, Settings-UI mit Textarea (eine pro Zeile). Der Graph-Filter wird OR-verkettet, ein einziger Listen-Request. Alter Single-String `prefix` wird weiter gelesen (Backward-Compat); Test-Endpoint zeigt Trefferzahl pro Praefix
### Geändert
- **App-Liste laedt `$expand=categories`** mit — `categories` ist eine Graph-Navigation-Property und kommt sonst leer (`null`) zurueck
- **Default-Scope** `DeviceManagementApps.Read.All` → `DeviceManagementApps.ReadWrite.All`: assign/rename/delete/content-update auf mobileApps brauchen ReadWrite (verifiziert via msgraph-Skill gegen den offiziellen Permission-Index)
### Behoben
- **429/503-Throttling**: neuer Retry-Wrapper `Invoke-MgGraphRequestRetry` mit `Retry-After`-Honorierung + Backoff (2/5/10s) in `Get-GraphPaged` (alle Lese-Pfade) + `Add-GraphMember` (Bulk-Member-Add). 403/404 werden unveraendert durchgereicht
- **Kategorien** wurden nie angezeigt — Ursache war die fehlende `$expand`-Klausel (s.o.), nicht das Frontend
### Technisch
- Neue Graph-Funktionen: `Read-IntuneWinPackage`, `New-GraphAppContentVersion`, `New-GraphAppContentFile`, `Wait-GraphContentFileState`, `Send-GraphContentToAzureBlob`, `Invoke-GraphContentRenewUpload`, `Invoke-GraphContentCommit`, `Update-GraphAppContent`, `Invoke-MgGraphRequestRetry`
- Neuer Endpoint: `POST /api/apps/{id}/content` (`Update-AppContentEndpoint`), Body `{ filePath, displayVersion? }`
- Intune-Content-Verschluesselung dokumentiert (AES-256-CBC + HMAC-SHA256, Layout `[HMAC|IV|Ciphertext]`, ProfileVersion1) — fuer `.intunewin` aus Detection.xml uebernommen
- `api()`-Helper unterstuetzt jetzt `timeoutMs` (AbortController) fuer lange Upload-Requests
---
## [0.1.22] - 2026-05-19
Robopack als zweiter Vendor analog zu PatchMyPC. Detection-Regeln wurden vom Hardcode in eine konfigurierbare Vendor-Registry verlagert.
### Neu
- **Robopack-Integration**: eigenes Source-Logo (`robopack.png`), Portal-Link auf `https://app.robopack.com/`, Lock-Icons fuer Delete/Rename, Filter-Eintrag "Nur Robopack-Apps". Default-Detection: `developer equals "Robopack"`
- **Vendor-Registry in `settings.json`**: neue Sektion `vendors[]` mit `id`, `displayName`, `portalUrl`, `logoFile`, `detection.field` (commandLine | developer | publisher | displayName | notes | owner), `detection.match` (contains | equals | regex | startsWith), `detection.pattern`, `block.delete`, `block.rename`. Mehrere Vendoren moeglich, erster Match gewinnt
- **Dynamisches Filter-Dropdown**: pro konfiguriertem Vendor wird eine Option `Nur <Name>-Apps` zur Laufzeit erzeugt
- **Vendor-Counts im Konfig-Test**: `Verbindung + Lookups testen` zeigt jetzt pro Vendor, wie viele Apps in der aktuellen Liste matchen — 0-Treffer warnen mit Hinweis auf die Detection-Regel
- **Letter-Fallback fuers Vendor-Logo**: wenn die Logo-Datei fehlt, zeigt der Badge den ersten Buchstaben des Vendor-Namens als Pille
### Geändert
- **Detection-Logik in `src/Graph.ps1`**: `Format-AppForFrontend` ruft `Resolve-AppVendorSource` mit `Test-AppVendorRule` auf, statt hardcoded `match "PatchMyPC"`. `Source`-String entspricht `vendor.displayName` ("PatchMyPC", "Robopack", ...) — bestehende PMPC-Datensaetze unveraendert
- **Backend-Blocking generisch** (`Remove-AppEndpoint`, `Update-AppEndpoint`): pro Vendor pruefen ob `block.delete`/`block.rename` gesetzt ist, HTTP 409 mit `code = "<vendorId>Managed"` (z.B. `patchmypcManaged`, `robopackManaged`)
- **Frontend-Render generisch**: Source-Badge, Delete-Lock und Rename-Lock werden aus dem Vendor-Eintrag (`SettingsState.vendorsByDisplayName`) abgeleitet — keine PMPC-Hardcodes mehr im UI
- **`code`-Format geaendert** von `PatchMyPCManaged` zu `patchmypcManaged` (kleines `id` + `Managed`-Suffix) — Frontend-Stellen, die den exakten String pruefen, sind keine vorhanden
### Behoben
- (keine; reine Feature-Erweiterung)
### Technisch
- Neue PowerShell-Funktionen: `Test-AppVendorRule`, `Resolve-AppVendorSource` (in `src/Graph.ps1`), `Find-VendorBySource` (in `src/Api.ps1`)
- Neue JS-Funktionen: `rebuildVendorIndexes(settings)`, `rebuildVendorFilterOptions()` (in `www/app.js`)
- Neue CSS-Klassen: `.app-source.app-source-letter` (Letter-Fallback), `.set-test-icon.warn` (gelbe Warn-Pille im Konfig-Test)
- Asset hinzu: `robopack.png` (Projekt-Root, ca. 53 KB)
- Migration: `Merge-Settings` ergaenzt fehlende `vendors`-Sektion aus den Defaults — bestehende `settings.json` bekommt PMPC + Robopack automatisch dazu
---
## [0.1.21] - 2026-05-19
Multi-Tenant-Readiness: das Tool ist jetzt fuer fremde Tenants ausrollbar, ohne dass HanseMerkur-spezifische Werte im Code als Defaults erscheinen.
### Neu
- **First-Run-Onboarding**: Bei leerem Tenant/Client/Praefix oeffnet sich das Settings-Modal automatisch beim Start. Setup-Banner im Modal und im Connect-Panel; Connect-Button bleibt disabled bis die kritischen Felder gefuellt sind
- **Konfiguration testen**: Neuer Button im Settings-Modal sowie neuer Endpoint `POST /api/settings/test` — prueft die aktuell eingetragenen Werte (auch vor dem Speichern) gegen Microsoft Graph: Verbindung, Abteilungs-Gruppen-Lookup mit Trefferzahl + Sample, RPA-Gruppen mit Found/Missing-Liste, User-Such-Probe. Inline-Ergebnis mit OK/FAIL-Pillen
- **Setup-Hilfetexte** unter den Connection-Feldern: Wo finde ich Tenant ID, Client ID, welche Redirect-URI ist noetig
### Geändert
- **Defaults neutralisiert** (`Get-DefaultSettings` in `src/Models.ps1`): `tenantId`, `clientId`, `departments.prefix` sind leer, `rpa.groupNames = @()`. Scopes/Naming/Theme bleiben generisch. Bestehende `settings.json` werden ueber Merge-Settings unveraendert geladen
- **Hilfedatei generisch**: `abt-hm-bd24-controlling` und `intune-win-app-adobe-reader-required` durch Platzhalter (`<dept-prefix>-team-controlling`, `intune-win-app-<app-slug>-required`) ersetzt; "Default: abt-hm"-Hinweis entfernt
### Behoben
- **Backend-Fallbacks entfernt**: `Get-GroupsEndpoint` liefert HTTP 412 + `code = "SettingsRequired"` wenn Praefix leer (vorher stiller `abt-hm`-Fallback). `Get-RpaGroupsEndpoint` liefert `notConfigured = $true` statt HM-RPA-Namen einzusetzen — Konfig-Probleme werden sichtbar statt kaschiert
- **PowerShell 5.1-Kompatibilitaet** (`src/Server.ps1`): `Read-RequestBody` nutzt `-AsHashtable` nur ab PS 6, in 5.1 wird ohne den Switch geparst. Endpoints handhaben sowohl Hashtable als auch PSCustomObject. Vorher: POST/PUT mit Body brach in Windows PowerShell 5.1 mit "Parameter 'AsHashtable' nicht gefunden"
- **Router-Logger-Bug** (`src/Router.ps1:33`): fehlende Parens um den `-f`-Format-Operator → PowerShell band `-f` als Prefix von `-ForegroundColor` und versuchte den Zeitstempel in eine ConsoleColor-Enum zu konvertieren. Folge: Unknown-Endpoint-Responses warfen 500er statt 404. Fix wie in Line 13/42 mit Klammern
### Technisch
- Neuer Endpoint: `POST /api/settings/test` (Body optional — testet uebergebene Werte gegen Graph, ohne sie zu speichern)
- Neue CSS-Klassen: `.banner-warning`, `.settings-test-result`, `.set-test-line`, `.set-test-icon.ok|fail`
---
## [0.1.20] - 2026-05-19
Konsolidierter Stand aller bisherigen Iterationen. Erster offiziell versionierter Release.
### Neu — App-Verwaltung
- **App-Zuweisungs-Workflow** mit Session-Konzept: mehrere Apps nacheinander Pillen klicken → alle Vorgänge in einem Rutsch ausführen → HTML-Report
- **App umbenennen** via Stift-Icon (Modal mit alter/neuer Name)
- **App löschen** via Trash-Icon (mit Bestätigung; bei Graph-Fehler wird Original-Message + Relationship-Hinweis ausgegeben)
- **PatchMyPC-Apps**: Rename + Delete blockiert (Lock-Icon + HTTP 409 mit `code: PatchMyPCManaged`)
### Neu — Zuweisungen
- **Zuweisung-Erstellen-Dialog** mit 6 Optionen in zwei Spalten:
- Required: Neue Gruppe / All Users / All Devices
- Available: Neue Gruppe / All Users / All Devices
- **Aktive Native-Zuweisungen werden ausgegraut** — keine Duplikate möglich
- **Available-/Required-Gruppen-Naming** unabhängig konfigurierbar (Präfix + Suffix)
- **Zuweisung entfernen** direkt im App-Detail oder im Picker-Popover (Trash-Icon pro Gruppe)
- **Native Zuweisungen** (All Users / All Devices) per `POST /api/apps/{id}/assignments`
### Neu — App-Detail-Panel
- **2-Spalten-Layout** statt 3 (Auto-Fit), Wide-Sektionen für lange Inhalte
- **Markdown-Rendering** der App-Beschreibung (Tabellen, Listen, Code-Blöcke) via gebundeltes [marked v15](https://github.com/markedjs/marked)
- **Installations-Statistik** je App (Geräte + Benutzer × Installiert / Fehler / Pending / N/A) mit Erfolgsquote-Pille
- **Abhängigkeiten** mit SVG-Flow-Diagramm (orthogonale Linien, klickbare Knoten) + Klartext-Erklärung pro Relation
- **Supersedence** analog mit Klartext-Erklärung (update / replace)
- **Klick auf Flow-Knoten** springt zur Ziel-App und expandiert sie (mit Highlight-Flash)
### Neu — Filter & Suche
- **Datums-Range-Filter** für "Zuletzt geändert" (via gebundeltes [flatpickr v4](https://flatpickr.js.org/), deutsche Lokalisierung)
- **Preset-Dropdown** (Alle / Ohne Zuweisungen / Nur Available / Nur Required / Mehrere / All Users / All Devices / Intune / PatchMyPC)
- **Checkbox-Chips** "Bereits Gruppenmitglied" und "All Users/Devices ausblenden"
### Neu — Einstellungen
- **Settings-Cog** im Header öffnet Modal mit:
- Connection: Tenant-ID, Client-ID, Scopes
- Abteilungs-Gruppen: konfigurierbarer Präfix (Default `abt-hm`)
- RPA-Gruppen: explizite Liste
- Benutzer-Suche: konfigurierbare Felder (DisplayName / UPN / Mail / Department)
- Required + Available Naming-Schema (Präfix + Suffix)
- Branding: Logo-Upload (PNG/JPG/SVG/WEBP/GIF, max 2 MB)
- Farben: 8 Akzentfarben + "Standardfarben wiederherstellen"
- Persistenz in `%APPDATA%\IntuneAppManager-Web\settings.json`
- **WCAG-Kontrast-Algorithmus** wählt automatisch Text-/Icon-Farbe (Schwarz/Weiß) je nach gewähltem Tint
- **Surface-Shade-Algorithmus** leitet harmonische innere Surfaces aus der gewählten Detail-Panel-Farbe ab
### Neu — Branding
- **Default-Logo** `application.png` im Projekt-Root wird angezeigt, sofern kein eigenes hochgeladen wurde
- **Brand-Farbe** ist eigene Konzeptfarbe (separat von Available) — Logo-Hintergrund und Stepper-Indikator
- **Avatar** im Header: Bootstrap `person-circle`-Icon, eingefärbt in Brand-Primary, mit pulsierendem grünem Online-Dot
- **Logout** als Türsymbol mit Pfeil
### Neu — Header
- **Cog-Icon** für Einstellungen
- **Fragezeichen-Icon** für Hilfe
- **Theme-Toggle** als Sun/Mond-Slider
- **Avatar** mit Tooltip (vollständiger UPN)
- **Logout-Icon** (statt Text-Button)
### Neu — Hilfe-System
- **Hilfe-Modal** (1320 px breit) mit:
- TOC-Sidebar (auto-generiert aus H2-Headings)
- Aktiver Eintrag wird via Scroll-Position highlighted
- Inhalt aus `www/help.md` (Markdown, jederzeit ohne Code-Änderung anpassbar)
- Inhalt: Schnellstart, Hauptworkflow, Header, Spalten, App-Detail, Einstellungen, Einschränkungen, Tastatur, Fehlerbehebung
### Neu — Empfänger-Liste
- **Drei Modi**: Abteilungen, RPA-Gruppen, Einzel-Benutzer — frei mischbar
- **Gruppen aufklappen** (Pfeil rechts) → Mitglieder inline mit Suchfilter
- **Teams-Icon** bei jedem User → Direkt-Chat in Teams-Desktop-App
- **Externer-Link- und Members-Tab-Icons** öffnen direkt im Intune-Portal
- **Icons immer sichtbar** (vorher hover-only)
### Neu — Backend
- **Graph `$batch`-Optimierung** für App-Details: 3 Sub-Calls in 1 HTTP-Roundtrip, server-seitig parallelisiert
- **PowerShell-Module-Pre-Flight** in `Start.ps1`: prüft, prompted, installiert fehlende Module im User-Scope
- **WAM-Window-Focus-Helper**: Auth-Popup wird automatisch nach vorne geholt (Background-Runspace)
- **HTML-Apply-Report** in `%TEMP%\IntuneAppManager-Reports\` mit Erfolg/Fehler-Tabelle nach App gruppiert
- **Caches**: Apps + Groups + Membership im Server-Process. Selektive Invalidierung bei Settings-Änderungen
- **Run.cmd** als plattform-unabhängiger Launcher; PowerShell-Fenster startet minimiert
### Geändert
- **App-Row-Layout**: schmalere Type-/Version-Spalten, breitere Name-Spalte; Icons rechtsbündig vertikal mittig
- **Filter-Chips**: keine Pillen-Rahmen mehr, mehr Gap zwischen Chips (20 px)
- **App-Namen**: brechen jetzt um statt zu truncieren (kein `…` mehr)
- **Detail-Panel**: max 2 Spalten statt Auto-Fit, lange Inhalte als Wide-Sektion
- **Modal-Höhe**: max 85 vh statt 60 vh, kein Scrollen für übliche Dialog-Inhalte
- **Stepper** im Header entfernt (war redundant)
- **Default-Farben**: Brand `#27a078`, Required `#cb2a7a`, RowSelected `#71e5c4`, DetailPanel `#f7f7f7`
### Behoben
- **PowerShell Single-Element-Array-JSON-Bug**: `@()` am Call-Site erzwingt Array-Serialisierung (sonst wurde Single-Dep als Objekt statt Array im JSON gerendert → Frontend ignorierte sie)
- **Date-Picker Blink-Effekt** beim Klick: nativer Browser-Picker ersetzt durch flatpickr (kein Chromium-Initial-Render-Quirk mehr)
- **Date-Picker Dark-Mode**: Calendar-Icon war nicht sichtbar — durch `filter: invert(1) brightness(1.4)` korrigiert
- **WAM-Auth-Fenster** versteckt hinter anderen Fenstern → Parallel-Runspace holt es nach vorne
- **Browser-Cache**: aggressive `no-store`-Header für HTML/JS/CSS sorgen für sofortige Updates
- **Transparenz-Slider** komplett entfernt — picked color = solid background (war zuvor verwirrend)
- **Logo-Cache** zweiter Upload greift sofort (mtime als Cache-Bust-Tag)
- **Settings-Save**: Selektive Cache-Invalidierung statt aller Caches (Logo-Update reloaded nicht mehr die Apps)
- **`jumpToAppById`**: triggert jetzt den Details-Fetch (vorher: ewiger Spinner + toggleAppExpand-Konflikt → "App geht nicht auf")
- **Portal-URLs**: Group-Links auf `intune.microsoft.com/.../GroupDetailsMenuBlade/.../menuId/` korrigiert (vorher `entra.microsoft.com` ohne `/menuId/`-Suffix)
- **App-Name-Icons** vertikal mittig zur ganzen Row (nicht nur zur Name-Line)
- **Type/Version-Chips in markierter Row**: Kontrast korrekt (vorher unleserlich)
- **Stepper-Reste**: Position der Header-Actions wieder rechts
- **Connect-Endpoint**: bessere Fehlermeldung mit echter Graph-Antwort statt nur "Ungültige Anfrage"
### Entfernt
- **Workflow-Stepper** im Header (Verbinden → App-Zuweisungen → Apps zuweisen → Ausführen)
- **Transparenz-Slider** in den Theme-Color-Settings
- **`members.html`-Standalone-Seite**: ersetzt durch direkten Intune-Portal-Link
- **Native Date-Inputs** (`type="date"`): ersetzt durch flatpickr
- **`color-scheme: light`**-Workaround für Date-Picker (nicht mehr nötig nach flatpickr-Integration)
### Bundled Libraries
- `marked v15.0.12` (MIT) — Markdown-Renderer für App-Beschreibung + Help-Page
- `flatpickr v4.6.13` (MIT) — Date-Range-Filter
### Technisch
- **PowerShell-Server**: HttpListener, Single-Thread Request-Loop, ausreichend für Single-Admin-Tool
- **Frontend**: Vanilla JS + CSS, keine Frameworks
- **Persistenz**: JSON-Datei in `%APPDATA%\IntuneAppManager-Web\settings.json`
- **Cache-Strategy**: Apps + Gruppen + GroupMembers im PS-Prozess; Theme + Logo per CSS-Variable zur Laufzeit überschrieben