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]>
This commit is contained in:
@@ -157,13 +157,32 @@ function Invoke-Api {
|
||||
'^GET /api/status$' { return Send-Json $Ctx (Get-SystemInfo) }
|
||||
'^GET /api/catalog$' { return Send-Json $Ctx (Get-JsonFile 'config\apps.json') }
|
||||
'^GET /api/presets$' {
|
||||
return Send-Json $Ctx ([pscustomobject]@{ shortcuts = (Get-JsonFile 'config\shortcuts.json'); timezones = @(Get-TimeZone -ListAvailable | ForEach-Object { @{ id = $_.Id; name = $_.DisplayName } }) })
|
||||
return Send-Json $Ctx ([pscustomobject]@{ shortcuts = @((Get-JsonFile 'config\shortcuts.json') | ForEach-Object { $_ }); timezones = @(Get-TimeZone -ListAvailable | ForEach-Object { @{ id = $_.Id; name = $_.DisplayName } }) })
|
||||
}
|
||||
'^GET /api/winget/search$' { return Send-Json $Ctx @(Search-Winget -Query $q['q'] -Source $(if ($q['source']) { $q['source'] } else { 'winget' })) }
|
||||
'^GET /api/local-installers$' {
|
||||
$dir = Join-Path $global:KdsRoot 'installers'
|
||||
$files = @(Get-ChildItem $dir -Recurse -Include *.exe, *.msi -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName.Substring($global:KdsRoot.Length + 1) })
|
||||
return Send-Json $Ctx $files
|
||||
'^GET /api/local-installers$' { return Send-Json $Ctx @(Get-LocalInstallers) }
|
||||
'^POST /api/local-installers$' { $b = Read-Body $Ctx; Set-InstallerMeta $b; return Send-Json $Ctx @{ ok = $true } }
|
||||
|
||||
# Datei-Upload: Body = Rohdaten, ?kind=installers|icons|rdp&name=Datei.ext
|
||||
'^POST /api/upload$' {
|
||||
$dir, $name = Resolve-UploadTarget $q['kind'] $q['name']
|
||||
New-Item $dir -ItemType Directory -Force | Out-Null
|
||||
$target = Join-Path $dir $name
|
||||
$fs = [IO.File]::Create($target)
|
||||
try { $Ctx.Request.InputStream.CopyTo($fs, 1MB) } finally { $fs.Close() }
|
||||
Write-Log "Upload: $($q['kind'])\$name ($([math]::Round((Get-Item $target).Length / 1MB, 1)) MB)"
|
||||
return Send-Json $Ctx @{ path = $target.Substring($global:KdsRoot.Length + 1); name = $name }
|
||||
}
|
||||
'^GET /api/files$' {
|
||||
$dir = (Resolve-UploadTarget $q['kind'] 'x.ico')[0]
|
||||
return Send-Json $Ctx @(Get-ChildItem $dir -File -ErrorAction SilentlyContinue | Where-Object Name -notlike '.*' | Where-Object Name -ne 'installers.json' |
|
||||
ForEach-Object { [pscustomobject]@{ name = $_.Name; sizeMB = [math]::Round($_.Length / 1MB, 2) } })
|
||||
}
|
||||
'^DELETE /api/files$' {
|
||||
$dir, $name = Resolve-UploadTarget $q['kind'] $q['name']
|
||||
Remove-Item (Join-Path $dir $name) -Force -ErrorAction SilentlyContinue
|
||||
if ($q['kind'] -eq 'installers') { Set-InstallerMeta ([pscustomobject]@{ file = "installers\$name"; remove = $true }) }
|
||||
return Send-Json $Ctx @{ ok = $true }
|
||||
}
|
||||
'^POST /api/apps/install$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob "Programme installieren ($(@($b.apps).Count))" 'Install-Apps' $b) } }
|
||||
'^POST /api/apps/upgrade-all$' { return Send-Json $Ctx @{ job = (Add-KdsJob 'Alle Programme aktualisieren (winget)' 'Update-AllApps' @{}) } }
|
||||
@@ -185,6 +204,10 @@ function Invoke-Api {
|
||||
'^GET /api/icons$' {
|
||||
return Send-Json $Ctx @(Get-ChildItem (Join-Path $global:KdsRoot 'icons') -Include *.ico, *.exe, *.dll -Recurse -ErrorAction SilentlyContinue | ForEach-Object Name)
|
||||
}
|
||||
'^GET /api/rdpfiles$' {
|
||||
return Send-Json $Ctx @(Get-ChildItem (Join-Path $global:KdsRoot 'rdp') -Filter *.rdp -ErrorAction SilentlyContinue | ForEach-Object Name)
|
||||
}
|
||||
'^POST /api/rdp/preview$' { $b = Read-Body $Ctx; return Send-Response $Ctx ([Text.Encoding]::UTF8.GetBytes((New-RdpContent $b))) 'text/plain; charset=utf-8' }
|
||||
|
||||
'^POST /api/system$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob 'Systemeinstellungen' 'Set-SystemConfig' $b) } }
|
||||
'^POST /api/security$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob 'Sicherheitseinstellungen' 'Set-SecurityConfig' $b) } }
|
||||
@@ -193,6 +216,8 @@ function Invoke-Api {
|
||||
$active = (powercfg /getactivescheme) -join ''
|
||||
return Send-Json $Ctx @{ active = $active; hibernate = [bool](Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Power' -Name HibernateEnabled -ErrorAction SilentlyContinue).HibernateEnabled }
|
||||
}
|
||||
'^GET /api/bloatware$' { return Send-Json $Ctx @(Get-BloatwareInventory) }
|
||||
'^POST /api/bloatware$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob 'Bloatware entfernen' 'Remove-Bloatware' $b) } }
|
||||
'^GET /api/bitlocker$' { return Send-Json $Ctx (Get-BitLockerInfo) }
|
||||
'^POST /api/bitlocker$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob "BitLocker: $($b.bitlocker.action)" 'Set-BitLockerConfig' $b) } }
|
||||
|
||||
@@ -201,22 +226,23 @@ function Invoke-Api {
|
||||
'^POST /api/updates/vendor$' { return Send-Json $Ctx @{ job = (Add-KdsJob 'Hersteller-Treiber-Update' 'Invoke-VendorDriverUpdate' @{}) } }
|
||||
'^POST /api/reboot$' { Restart-Computer -Force; return Send-Json $Ctx @{ ok = $true } }
|
||||
|
||||
'^GET /api/profiles$' {
|
||||
return Send-Json $Ctx @(Get-ChildItem (Join-Path $global:KdsRoot 'profiles') -Filter *.json -ErrorAction SilentlyContinue | ForEach-Object BaseName)
|
||||
}
|
||||
'^GET /api/profiles/(?<n>[\w\-\. ]+)$' {
|
||||
$p = Join-Path $global:KdsRoot "profiles\$($Matches.n).json"
|
||||
if (-not (Test-Path $p)) { return Send-Json $Ctx @{ error = 'nicht gefunden' } 404 }
|
||||
# Blaupausen (Standard-Einrichtungen je Kunde) unter blueprints\<id>.json
|
||||
'^GET /api/blueprints$' { return Send-Json $Ctx @(Get-Blueprints) }
|
||||
'^GET /api/blueprints/(?<n>[^/\\]+)$' {
|
||||
$p = Get-BlueprintPath $Matches.n
|
||||
if (-not (Test-Path $p)) { return Send-Json $Ctx @{ error = 'Blaupause nicht gefunden' } 404 }
|
||||
return Send-Response $Ctx ([IO.File]::ReadAllBytes($p))
|
||||
}
|
||||
'^POST /api/profiles/(?<n>[\w\-\. ]+)$' {
|
||||
'^POST /api/blueprints/(?<n>[^/\\]+)$' {
|
||||
$sr = New-Object IO.StreamReader($Ctx.Request.InputStream, [Text.Encoding]::UTF8); $txt = $sr.ReadToEnd(); $sr.Close()
|
||||
$dir = Join-Path $global:KdsRoot 'profiles'; New-Item $dir -ItemType Directory -Force | Out-Null
|
||||
[IO.File]::WriteAllText((Join-Path $dir "$($Matches.n).json"), $txt, (New-Object Text.UTF8Encoding($false)))
|
||||
$null = $txt | ConvertFrom-Json # nur gueltiges JSON speichern
|
||||
$p = Get-BlueprintPath $Matches.n
|
||||
New-Item (Split-Path $p) -ItemType Directory -Force | Out-Null
|
||||
[IO.File]::WriteAllText($p, $txt, (New-Object Text.UTF8Encoding($false)))
|
||||
return Send-Json $Ctx @{ ok = $true }
|
||||
}
|
||||
'^DELETE /api/profiles/(?<n>[\w\-\. ]+)$' { Remove-Item (Join-Path $global:KdsRoot "profiles\$($Matches.n).json") -ErrorAction SilentlyContinue; return Send-Json $Ctx @{ ok = $true } }
|
||||
'^POST /api/run-profile$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob "Profil ausfuehren: $($b.name)" 'Invoke-FullProfile' $b) } }
|
||||
'^DELETE /api/blueprints/(?<n>[^/\\]+)$' { Remove-Item (Get-BlueprintPath $Matches.n) -ErrorAction SilentlyContinue; return Send-Json $Ctx @{ ok = $true } }
|
||||
'^POST /api/run-profile$' { $b = Read-Body $Ctx; return Send-Json $Ctx @{ job = (Add-KdsJob "Einrichtung: $(@($b.customer, $b.name) -ne '' -join ' / ')" 'Invoke-FullProfile' $b) } }
|
||||
|
||||
'^GET /api/jobs$' { Update-KdsJobs; return Send-Json $Ctx @($script:Jobs.Values | ForEach-Object { Get-KdsJobView $_ }) }
|
||||
'^GET /api/jobs/(?<id>\d+)$' {
|
||||
@@ -276,7 +302,7 @@ while ($script:Running -and $listener.IsListening) {
|
||||
$async = $listener.BeginGetContext($null, $null)
|
||||
while (-not $async.AsyncWaitHandle.WaitOne(1000)) { Update-KdsJobs }
|
||||
$ctx = $listener.EndGetContext($async)
|
||||
$path = $ctx.Request.Url.AbsolutePath
|
||||
$path = [Uri]::UnescapeDataString($ctx.Request.Url.AbsolutePath)
|
||||
try {
|
||||
if ($path.StartsWith('/api/')) {
|
||||
$t = $ctx.Request.Headers['X-Token']
|
||||
|
||||
Reference in New Issue
Block a user