Files
Intune-Manager/CHANGELOG.md
T
marcoandClaude Opus 4.8 5c60eacc12
Build & Release MSI / build-msi (push) Canceled after 0s
v0.1.29 — Geraete-Offboarding (v1)
Neu:
- Geraete-Offboarding: Geraete ueber Intune, Autopilot und Entra ID
  entfernen. Suche + ID-Aufloesung (via $batch), Recovery-Keys
  (BitLocker/FileVault/LAPS) vor dem Loeschen, Bestaetigungs-Dialog mit
  Dienst-Auswahl + 403/Multi-Admin-Approval-Handling, im Read-Only gesperrt.
  Neues Modul src/Offboard.ps1, Endpoints /api/offboard/{search,keys,execute}.
  Portiert aus Device Offboarding Manager (Ugur Koc, MIT).
- Offboarding-Berechtigungen dokumentiert; Setup-Skript -IncludeOffboarding.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-24 12:37:41 +02:00

365 lines
26 KiB
Markdown
Raw Permalink 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.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