Files
KDS-Install-Agent/web/index.html
T
MrBlakeandClaude Opus 5.5 ebfec7000e Blaupausen je Kunde, Datei-Uploads, RDP-Verknuepfungen, Bloatware-Entfernung
- Blaupausen (blueprints\) mit Kunde/Beschreibung, gruppierte Ansicht,
  Duplizieren/Export, Schnellauswahl auf der Uebersicht, 2 Beispiele
- Upload von Setups (EXE/MSI/MSIX/PS1/CMD) per Drag & Drop inkl.
  gespeicherter Silent-Parameter; Upload von Icons und .rdp-Dateien
- RDP-Verknuepfungen fuer alle Benutzer: Generator (Gateway, RemoteApp,
  Umleitungen) oder hochgeladene .rdp-Dateien
- Bloatware-Tab: Store-Apps, Hersteller-Tools, Testversionen,
  vorinstalliertes Office/OneNote (C2R) und OneDrive entfernen;
  Katalog in config/bloatware.json, auch als Schritt in Blaupausen
- Fix: Top-Level-JSON-Arrays (Vorlagen) wurden falsch serialisiert

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:00:25 +02:00

424 lines
23 KiB
HTML
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.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>KDS Install Agent</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect width='16' height='16' rx='3' fill='%230a64d6'/><path d='M4 8l3 3 5-6' stroke='white' stroke-width='2' fill='none'/></svg>">
</head>
<body>
<aside class="side">
<div class="brand">KDS <span>Install Agent</span></div>
<nav id="nav">
<a data-tab="overview" class="active">Übersicht</a>
<a data-tab="apps">Programme</a>
<a data-tab="office">Office</a>
<a data-tab="shortcuts">Desktop-Icons</a>
<a data-tab="bloatware">Bloatware</a>
<a data-tab="system">System &amp; Sicherheit</a>
<a data-tab="power">Energie</a>
<a data-tab="bitlocker">BitLocker</a>
<a data-tab="updates">Updates &amp; Treiber</a>
<a data-tab="profiles">Blaupausen</a>
<a data-tab="jobs">Aufgaben <b id="jobBadge" class="badge hidden">0</b></a>
</nav>
<div class="side-foot">
<div id="profileName" class="muted">Blaupause: (ungespeichert)</div>
<button class="ghost" id="btnShutdown">Agent beenden</button>
</div>
</aside>
<main>
<!-- Übersicht -->
<section id="tab-overview" class="tab active">
<h1>Übersicht</h1>
<div id="sysinfo" class="grid4"></div>
<div class="card">
<h2>Komplette Einrichtung mit einem Klick</h2>
<p class="muted">Blaupause wählen (oder in den Tabs selbst konfigurieren) und starten. Alle Einstellungen werden in sinnvoller Reihenfolge ausgeführt.</p>
<div class="row">
<label class="f">Blaupause / Kunde<select id="bpQuick"><option value="">– aktuelle Konfiguration –</option></select></label>
</div>
<p id="bpQuickDesc" class="muted small"></p>
<div class="checks" id="steps">
<label><input type="checkbox" value="system" checked> System</label>
<label><input type="checkbox" value="bloatware"> Bloatware</label>
<label><input type="checkbox" value="security" checked> Sicherheit</label>
<label><input type="checkbox" value="power" checked> Energie</label>
<label><input type="checkbox" value="apps" checked> Programme</label>
<label><input type="checkbox" value="office" checked> Office</label>
<label><input type="checkbox" value="shortcuts" checked> Desktop-Icons</label>
<label><input type="checkbox" value="drivers"> Hersteller-Treiber</label>
<label><input type="checkbox" value="updates" checked> Windows Update</label>
<label><input type="checkbox" value="bitlocker"> BitLocker</label>
</div>
<div id="summary" class="summary"></div>
<button class="primary big" id="btnRunAll">▶ Einrichtung starten</button>
</div>
</section>
<!-- Programme -->
<section id="tab-apps" class="tab">
<h1>Programme</h1>
<div class="cols">
<div>
<div class="card">
<h2>Suche in öffentlichen Bibliotheken</h2>
<div class="row">
<input id="appSearch" placeholder="z.B. firefox, acrobat, teamviewer …">
<select id="appSource"><option value="winget">winget (Community-Repo)</option><option value="msstore">Microsoft Store</option></select>
<button id="btnSearch">Suchen</button>
</div>
<div id="searchResults" class="list"></div>
</div>
<div class="card">
<h2>Schnellauswahl</h2>
<div id="catalog"></div>
</div>
<div class="card">
<h2>Eigene Installer <span class="muted small">(EXE, MSI, MSIX, PS1, CMD – Ordner <code>installers\</code>)</span></h2>
<label class="drop" id="instDrop">
<input type="file" id="instFile" multiple accept=".exe,.msi,.msix,.msixbundle,.appx,.appxbundle,.ps1,.cmd,.bat" hidden>
<b>Setup-Dateien hierher ziehen</b> oder klicken zum Auswählen
<span class="muted small">Die Dateien werden auf den Stick hochgeladen und stehen in allen Blaupausen zur Verfügung.</span>
</label>
<div id="uploadProgress" class="muted small"></div>
<div id="localList" class="list"></div>
<p class="muted small">Silent-Parameter (Vorschläge):
<code class="hint" data-hint="/S">/S</code> NSIS ·
<code class="hint" data-hint="/VERYSILENT /SUPPRESSMSGBOXES /NORESTART">/VERYSILENT …</code> Inno Setup ·
<code class="hint" data-hint="/quiet /norestart">/quiet /norestart</code> WiX/Burn ·
<code class="hint" data-hint="/s /v&quot;/qn&quot;">/s /v"/qn"</code> InstallShield ·
MSI: <code>/qn</code> wird automatisch gesetzt</p>
</div>
</div>
<div>
<div class="card sticky">
<h2>Ausgewählt <span id="appCount" class="badge">0</span></h2>
<div id="selectedApps" class="list"></div>
<button class="primary" id="btnInstallApps">Jetzt installieren</button>
<button id="btnUpgradeAll">Alle installierten Programme aktualisieren</button>
</div>
</div>
</div>
</section>
<!-- Office -->
<section id="tab-office" class="tab">
<h1>Microsoft Office</h1>
<div class="cols">
<div class="card">
<h2>Konfiguration</h2>
<label class="f">Produkt<select id="officeProduct" data-bind="office.product"></select></label>
<label class="f">Update-Kanal<select id="officeChannel" data-bind="office.channel"></select></label>
<label class="f">Architektur
<select data-bind="office.arch"><option value="64">64-Bit (empfohlen)</option><option value="32">32-Bit</option></select></label>
<label class="f">Lizenzschlüssel (nur Volumenlizenz/MAK)<input data-bind="office.pidKey" placeholder="XXXXX-XXXXX-XXXXX-XXXXX-XXXXX"></label>
<label class="f">Firmenname<input data-bind="office.company" placeholder="optional"></label>
<h3>Sprachen</h3>
<div class="checks" data-bind-list="office.languages">
<label><input type="checkbox" value="de-de"> Deutsch</label>
<label><input type="checkbox" value="en-us"> Englisch</label>
<label><input type="checkbox" value="fr-fr"> Französisch</label>
<label><input type="checkbox" value="it-it"> Italienisch</label>
<label><input type="checkbox" value="es-es"> Spanisch</label>
<label><input type="checkbox" value="nl-nl"> Niederländisch</label>
<label><input type="checkbox" value="pl-pl"> Polnisch</label>
<label><input type="checkbox" value="tr-tr"> Türkisch</label>
<label><input type="checkbox" value="MatchOS"> Wie Windows</label>
</div>
<h3>Apps <span class="muted small">(abgewählte werden nicht installiert)</span></h3>
<div class="checks" id="officeApps"></div>
<h3>Zusatzprodukte</h3>
<div class="checks" id="officeExtras"></div>
<h3>Optionen</h3>
<div class="checks col">
<label><input type="checkbox" data-bind="office.updates"> Automatische Updates</label>
<label><input type="checkbox" data-bind="office.removeMsi"> Alte MSI-Office-Versionen entfernen</label>
<label><input type="checkbox" data-bind="office.migrateArch"> Architektur einer vorhandenen Installation migrieren</label>
<label><input type="checkbox" data-bind="office.sharedComputer"> Aktivierung für gemeinsam genutzte Computer (RDS)</label>
<label><input type="checkbox" data-bind="office.disableVba"> Makros aus dem Internet blockieren</label>
<label><input type="checkbox" data-bind="office.ooxmlDefault"> Erststart-Dialog unterdrücken</label>
<label><input type="checkbox" data-bind="office.showUi"> Installationsfortschritt anzeigen</label>
</div>
</div>
<div>
<div class="card">
<h2>Generierte configuration.xml</h2>
<pre id="officeXml" class="code"></pre>
<div class="row">
<button id="btnXmlDownload">XML herunterladen</button>
<button id="btnXmlCopy">Kopieren</button>
</div>
</div>
<div class="card">
<h2>Ausführen</h2>
<label class="f">Modus
<select data-bind="officeMode">
<option value="online">Online installieren (direkt von Microsoft)</option>
<option value="download">Nur Build erstellen (Dateien auf den Stick laden)</option>
<option value="offline">Vom Stick installieren (Build wird bei Bedarf erstellt)</option>
</select></label>
<p class="muted small">setup.exe des Office Deployment Tools wird bei Bedarf automatisch von Microsoft geladen und unter <code>office\</code> abgelegt. Builds liegen in <code>office\source\</code>.</p>
<div id="officeBuilds" class="muted small"></div>
<button class="primary" id="btnOffice">Ausführen</button>
</div>
</div>
</div>
</section>
<!-- Desktop-Icons -->
<section id="tab-shortcuts" class="tab">
<h1>Desktop-Icons für alle Benutzer</h1>
<div class="cols">
<div>
<div class="card">
<h2>Neue Verknüpfung</h2>
<label class="f">Typ<select id="scType">
<option value="url">Webseite (URL)</option>
<option value="lnk">Programm / Datei / Ordner</option>
<option value="rdp">Remotedesktop (RDP)</option></select></label>
<label class="f">Name<input id="scName" placeholder="z.B. Intranet, Terminalserver"></label>
<label class="f t-url t-lnk">Ziel<input id="scTarget" placeholder="https://… oder %ProgramFiles%\…\app.exe"></label>
<label class="f t-lnk">Argumente<input id="scArgs"></label>
<div class="t-rdp">
<label class="f">Quelle<select id="rdpSource"><option value="">Neu konfigurieren</option></select></label>
<div id="rdpForm">
<div class="row">
<label class="f" style="flex:3">Server / Host<input id="rdpHost" placeholder="ts01.firma.local"></label>
<label class="f" style="flex:1">Port<input id="rdpPort" type="number" placeholder="3389"></label>
</div>
<div class="row">
<label class="f">Benutzer (optional)<input id="rdpUser" placeholder="FIRMA\benutzer"></label>
<label class="f">RD-Gateway (optional)<input id="rdpGateway" placeholder="gw.firma.de"></label>
</div>
<div class="row">
<label class="f">RemoteApp-Alias (optional)<input id="rdpRemoteApp" placeholder="z.B. DATEV"></label>
<label class="f">Audio<select id="rdpAudio"><option value="local">auf diesem PC</option><option value="remote">auf dem Server</option><option value="none">aus</option></select></label>
</div>
<div class="checks">
<label><input type="checkbox" id="rdpFullscreen" checked> Vollbild</label>
<label><input type="checkbox" id="rdpMultimon"> Alle Monitore</label>
<label><input type="checkbox" id="rdpClipboard" checked> Zwischenablage</label>
<label><input type="checkbox" id="rdpPrinters" checked> Drucker</label>
<label><input type="checkbox" id="rdpDrives"> Laufwerke</label>
<label><input type="checkbox" id="rdpSmartcards"> Smartcards</label>
<label><input type="checkbox" id="rdpMicrophone"> Mikrofon</label>
<label><input type="checkbox" id="rdpCamera"> Kamera</label>
<label><input type="checkbox" id="rdpAdmin"> Admin-Sitzung</label>
</div>
<label class="f" style="margin-top:10px">Weitere RDP-Zeilen (optional)<textarea id="rdpExtra" rows="2" placeholder="z.B. session bpp:i:32"></textarea></label>
<details><summary class="muted small">Vorschau der .rdp-Datei</summary><pre id="rdpPreview" class="code"></pre></details>
</div>
<p class="muted small">Vorhandene .rdp-Dateien hochladen:
<label class="button small">.rdp hochladen<input type="file" id="rdpUpload" accept=".rdp" multiple hidden></label></p>
</div>
<div class="f t-url t-lnk"><label class="f" for="scIcon" style="margin:0">Icon <span class="muted small">(aus <code>icons\</code> oder Pfad)</span></label>
<div class="row" style="margin-top:3px"><input id="scIcon" list="iconList" placeholder="optional">
<label class="button">.ico hochladen<input type="file" id="iconUpload" accept=".ico,.exe,.dll" hidden></label></div></div>
<datalist id="iconList"></datalist>
<div class="row">
<button class="primary" id="btnScCreate">Sofort anlegen</button>
<button id="btnScPlan">Zum Profil hinzufügen</button>
</div>
</div>
<div class="card">
<h2>Vorlagen</h2>
<div id="scPresets" class="chips"></div>
</div>
</div>
<div>
<div class="card">
<h2>Im Profil geplant</h2>
<div id="scPlanned" class="list"></div>
<button class="primary" id="btnScApplyAll">Alle geplanten jetzt anlegen</button>
</div>
<div class="card">
<h2>Aktuell auf dem öffentlichen Desktop <button class="small ghost" id="btnScRefresh">↻</button></h2>
<div id="scCurrent" class="list"></div>
</div>
</div>
</div>
</section>
<!-- Bloatware -->
<section id="tab-bloatware" class="tab">
<h1>Bloatware entfernen</h1>
<div class="card">
<div class="row wrap" style="margin-top:0">
<button id="btnBloatScan">↻ Gerät scannen</button>
<button id="btnBloatRec">Empfohlene auswählen</button>
<button id="btnBloatNone" class="ghost">Keine</button>
<span class="sep"></span>
<button class="primary" id="btnBloatRemove">Ausgewählte entfernen</button>
</div>
<label class="checks" style="margin-top:12px"><input type="checkbox" data-bind="bloatware.recommended">
<span>In der Blaupause: <b>alle empfohlenen</b> Einträge entfernen (plus die manuell angehakten, minus die abgewählten). So funktioniert die Blaupause auch auf anderen Geräten und bei anderen Herstellern.</span></label>
<p class="muted small">Gefunden werden Store-Apps (für alle Benutzer + Vorlage für neue Benutzer), Hersteller-Tools, Testversionen, vorinstallierte Office/OneNote-Versionen (Click-to-Run, z. B. „Microsoft 365 – fr-fr“) und OneDrive. Katalog erweiterbar in <code>config\bloatware.json</code>.</p>
</div>
<div id="bloatList"><div class="card muted">Noch nicht gescannt.</div></div>
</section>
<!-- System & Sicherheit -->
<section id="tab-system" class="tab">
<h1>System &amp; Sicherheit</h1>
<div class="cols">
<div class="card">
<h2>System</h2>
<label class="f">Computername <span class="muted small">(leer = unverändert, max. 15 Zeichen)</span><input data-bind="system.computerName" maxlength="15"></label>
<label class="f">Zeitzone<select id="tzSelect" data-bind="system.timeZone"><option value="">unverändert</option></select></label>
<div class="checks col">
<label><input type="checkbox" data-bind="system.showExtensions"> Dateiendungen anzeigen (auch für neue Benutzer)</label>
<label><input type="checkbox" data-bind="system.disableConsumer"> Werbe-Apps / Consumer-Features deaktivieren</label>
</div>
<button class="primary" data-run="system">Systemeinstellungen anwenden</button>
</div>
<div class="card">
<h2>Sicherheit</h2>
<div class="checks col">
<label><input type="checkbox" data-bind="security.defender"> Defender: Echtzeit-, Cloud- &amp; PUA-Schutz</label>
<label><input type="checkbox" data-bind="security.firewall"> Firewall für alle Profile aktivieren</label>
<label><input type="checkbox" data-bind="security.smartScreen"> SmartScreen aktivieren</label>
<label><input type="checkbox" data-bind="security.uac"> UAC auf höchste Stufe</label>
<label><input type="checkbox" data-bind="security.disableSmb1"> SMBv1 deaktivieren</label>
<label><input type="checkbox" data-bind="security.disableAutorun"> Autorun / Autoplay deaktivieren</label>
<label><input type="checkbox" data-bind="security.lsaProtection"> LSA-Schutz (Credential-Diebstahl erschweren)</label>
<label><input type="checkbox" data-bind="security.telemetryMin"> Telemetrie minimieren</label>
</div>
<label class="f">Remotedesktop
<select data-bind="security.rdp"><option value="keep">unverändert</option><option value="enable">aktivieren (mit NLA)</option><option value="disable">deaktivieren</option></select></label>
<h3>Lokales Admin-Konto <span class="muted small">(optional)</span></h3>
<div class="row">
<input data-bind="security.localAdminName" placeholder="Benutzername">
<input data-bind="security.localAdminPassword" type="password" placeholder="Kennwort" autocomplete="new-password">
</div>
<p class="muted small">Hinweis: Das Kennwort wird beim Speichern im Profil im Klartext abgelegt.</p>
<button class="primary" data-run="security">Sicherheitseinstellungen anwenden</button>
</div>
</div>
</section>
<!-- Energie -->
<section id="tab-power" class="tab">
<h1>Energie</h1>
<div class="card">
<div id="powerState" class="muted small"></div>
<label class="f">Energieplan
<select data-bind="power.plan"><option value="">unverändert</option><option value="balanced">Ausbalanciert</option><option value="high">Höchstleistung</option><option value="ultimate">Ultimative Leistung</option></select></label>
<table class="ptable">
<tr><th></th><th>Netzbetrieb 🔌</th><th>Akku 🔋</th></tr>
<tr><td>Bildschirm aus nach (Min., 0 = nie)</td><td><input type="number" min="0" data-bind="power.monitorAc"></td><td><input type="number" min="0" data-bind="power.monitorDc"></td></tr>
<tr><td>Energiesparmodus nach</td><td><input type="number" min="0" data-bind="power.sleepAc"></td><td><input type="number" min="0" data-bind="power.sleepDc"></td></tr>
<tr><td>Ruhezustand nach</td><td><input type="number" min="0" data-bind="power.hibernateAc"></td><td><input type="number" min="0" data-bind="power.hibernateDc"></td></tr>
<tr><td>Deckel schließen</td><td><select data-bind="power.lidAc" class="act"></select></td><td><select data-bind="power.lidDc" class="act"></select></td></tr>
<tr><td>Netzschalter</td><td><select data-bind="power.buttonAc" class="act"></select></td><td><select data-bind="power.buttonDc" class="act"></select></td></tr>
</table>
<div class="row">
<label class="f">Ruhezustand<select data-bind="power.hibernate"><option value="">unverändert</option><option value="on">ein</option><option value="off">aus</option></select></label>
<label class="f">Schnellstart<select data-bind="power.fastStartup"><option value="">unverändert</option><option value="on">ein</option><option value="off">aus (empfohlen für Updates)</option></select></label>
</div>
<button class="primary" data-run="power">Energieeinstellungen anwenden</button>
</div>
</section>
<!-- BitLocker -->
<section id="tab-bitlocker" class="tab">
<h1>BitLocker</h1>
<div class="cols">
<div class="card">
<h2>Status <button class="small ghost" id="btnBlRefresh">↻</button></h2>
<div id="blStatus">Lade …</div>
</div>
<div class="card">
<h2>Aktivieren</h2>
<label class="f">Verschlüsselung<select data-bind="bitlocker.method"><option value="XtsAes256">XTS-AES 256 (empfohlen)</option><option value="XtsAes128">XTS-AES 128</option></select></label>
<div class="checks col">
<label><input type="checkbox" data-bind="bitlocker.usedSpaceOnly"> Nur belegten Speicher verschlüsseln (schnell, für neue Geräte)</label>
<label><input type="checkbox" data-bind="bitlocker.skipHardwareTest"> Hardwaretest überspringen (sofort starten)</label>
<label><input type="checkbox" data-bind="bitlocker.usePin"> Start-PIN zusätzlich zum TPM</label>
<label><input type="checkbox" data-bind="bitlocker.backupAad"> Schlüssel in Entra ID (Azure AD) sichern</label>
<label><input type="checkbox" data-bind="bitlocker.backupAd"> Schlüssel im Active Directory sichern</label>
</div>
<label class="f pinonly">PIN (6–20 Ziffern)<input data-bind="bitlocker.pin" type="password" inputmode="numeric"></label>
<p class="muted small">Der Wiederherstellungsschlüssel wird immer auf dem Stick unter <code>bitlocker-keys\</code> abgelegt (Computername + Seriennummer).</p>
<div class="row">
<button class="primary" data-bl="enable">BitLocker aktivieren</button>
<button data-bl="savekey">Schlüssel erneut sichern</button>
<button class="danger" data-bl="disable">Deaktivieren</button>
</div>
</div>
</div>
</section>
<!-- Updates -->
<section id="tab-updates" class="tab">
<h1>Updates &amp; Treiber</h1>
<div class="card">
<div class="row wrap">
<button class="primary" data-scan="Software">Windows-Updates suchen</button>
<button class="primary" data-scan="Driver">Treiber-Updates suchen</button>
<button data-scan="all">Alles suchen</button>
<span class="sep"></span>
<button id="btnVendor">Hersteller-Tool (Dell/Lenovo/HP)</button>
<button id="btnWingetUpg">Programme aktualisieren (winget)</button>
<button id="btnWinget">winget reparieren</button>
<span class="sep"></span>
<button class="danger" id="btnReboot">Neustart</button>
</div>
</div>
<div class="card">
<h2>Gefundene Updates <span id="updCount" class="badge">0</span></h2>
<div id="updList" class="list"><p class="muted">Noch keine Suche durchgeführt.</p></div>
<div class="row">
<button class="primary" id="btnUpdSel">Ausgewählte installieren</button>
<button id="btnUpdAll">Alle installieren</button>
</div>
</div>
</section>
<!-- Profile -->
<section id="tab-profiles" class="tab">
<h1>Blaupausen</h1>
<p class="muted">Eine Blaupause speichert die komplette Einrichtung (Programme, Office, Icons, RDP, Sicherheit, Energie, BitLocker, Schritte), zum Beispiel als Standard für einen Kunden. Ablage: <code>blueprints\</code> auf dem Stick.</p>
<div class="cols">
<div>
<div class="row" style="margin:0 0 12px"><input id="bpFilter" placeholder="Kunde oder Blaupause suchen …"></div>
<div id="profileList"></div>
</div>
<div class="card sticky">
<h2>Aktuelle Konfiguration speichern</h2>
<label class="f">Kunde<input id="bpCustomer" list="bpCustomers" placeholder="z.B. Müller GmbH"></label>
<datalist id="bpCustomers"></datalist>
<label class="f">Name der Blaupause<input id="profileSaveName" placeholder="z.B. Büro-Notebook, Außendienst"></label>
<label class="f">Beschreibung<textarea id="bpDescription" rows="3" placeholder="optional – Hinweise für Techniker"></textarea></label>
<div class="row"><button class="primary" id="btnProfileSave">Speichern</button><button id="btnProfileSaveAs">Als neue Blaupause</button></div>
<h3>Import / Export</h3>
<div class="row">
<button id="btnExport">Als JSON exportieren</button>
<label class="button">Importieren<input type="file" id="importFile" accept=".json" hidden></label>
<button class="ghost" id="btnReset">Zurücksetzen</button>
</div>
</div>
</div>
</section>
<!-- Jobs -->
<section id="tab-jobs" class="tab">
<h1>Aufgaben</h1>
<div class="cols jobs">
<div class="card"><div id="jobList" class="list"></div></div>
<div class="card">
<h2 id="jobTitle">Protokoll</h2>
<pre id="jobLog" class="code log"></pre>
<div class="row"><button class="danger hidden" id="btnJobStop">Abbrechen</button></div>
</div>
</div>
</section>
</main>
<div id="toast"></div>
<script src="app.js"></script>
</body>
</html>