Cross-Platform: Spike für Betrieb unter PowerShell 7 auf macOS/Linux
Windows-Verhalten bleibt identisch (Pfade/Temp verifiziert). Portable Anpassungen: - Get-AppDataDir/Test-IsWindows (Models.ps1): App-Daten unter macOS in ~/Library/Application Support, Linux in $XDG_CONFIG_HOME/~/.config; auf Windows unveraendert %APPDATA%. Settings- und Policy-Export-Pfad nutzen ihn. - ReportDir ueber [IO.Path]::GetTempPath() statt $env:TEMP (auf macOS/Linux leer). - Start.ps1: Browser plattformneutral oeffnen (open/xdg-open/Start-Process); WMI-Stale-Instanz-Erkennung nur noch auf Windows. - Datei-/Ordner-Dialog: macOS-nativer osascript-Chooser statt System.Windows.Forms; auf nicht unterstuetzten Plattformen klare Fehlermeldung. Auth (Device-Code-Flow) und HttpListener sind bereits plattformneutral. Test auf echtem macOS steht aus; Packaging (.app/.dmg) folgt separat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -158,7 +158,8 @@ $script:Config = @{
|
|||||||
Scopes = @($script:Settings.connection.scopes)
|
Scopes = @($script:Settings.connection.scopes)
|
||||||
ScopesRo = @($script:Settings.connection.scopesRo)
|
ScopesRo = @($script:Settings.connection.scopesRo)
|
||||||
WebRoot = (Join-Path $root "www")
|
WebRoot = (Join-Path $root "www")
|
||||||
ReportDir = (Join-Path $env:TEMP "IntuneAppManager-Reports")
|
# Plattformneutrales Temp-Verzeichnis ($env:TEMP ist auf macOS/Linux leer).
|
||||||
|
ReportDir = (Join-Path ([System.IO.Path]::GetTempPath()) "IntuneAppManager-Reports")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $script:Config.ReportDir)) {
|
if (-not (Test-Path $script:Config.ReportDir)) {
|
||||||
@@ -206,6 +207,11 @@ Write-Host ""
|
|||||||
# das alte Fenster bedient weiter mit altem Code. Darum alle anderen Start.ps1-
|
# das alte Fenster bedient weiter mit altem Code. Darum alle anderen Start.ps1-
|
||||||
# Prozesse DIESES Pfads vorher beenden, damit ein Neustart wirklich neu laedt.
|
# Prozesse DIESES Pfads vorher beenden, damit ein Neustart wirklich neu laedt.
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
# Nur auf Windows: die WMI-basierte Instanz-Erkennung (Win32_Process) gibt es
|
||||||
|
# nur dort. Auf macOS/Linux uebernimmt das der Listener selbst (Port belegt ->
|
||||||
|
# Fehler beim Start), ein manueller Neustart genuegt.
|
||||||
|
$isWin = ($env:OS -eq 'Windows_NT') -or ($PSVersionTable.PSVersion.Major -lt 6) -or $IsWindows
|
||||||
|
if ($isWin) {
|
||||||
try {
|
try {
|
||||||
$thisScript = $PSCommandPath
|
$thisScript = $PSCommandPath
|
||||||
if ([string]::IsNullOrWhiteSpace($thisScript)) { $thisScript = Join-Path $PSScriptRoot 'Start.ps1' }
|
if ([string]::IsNullOrWhiteSpace($thisScript)) { $thisScript = Join-Path $PSScriptRoot 'Start.ps1' }
|
||||||
@@ -223,6 +229,7 @@ try {
|
|||||||
} catch {
|
} catch {
|
||||||
Write-Host " (Konnte alte Instanzen nicht pruefen: $($_.Exception.Message))" -ForegroundColor DarkGray
|
Write-Host " (Konnte alte Instanzen nicht pruefen: $($_.Exception.Message))" -ForegroundColor DarkGray
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$url = "http://localhost:$Port/"
|
$url = "http://localhost:$Port/"
|
||||||
Write-Host " URL: $url" -ForegroundColor Green
|
Write-Host " URL: $url" -ForegroundColor Green
|
||||||
@@ -232,7 +239,15 @@ Write-Host " Beenden: Ctrl+C" -ForegroundColor DarkGray
|
|||||||
Write-Host ""
|
Write-Host ""
|
||||||
|
|
||||||
if (-not $NoBrowser) {
|
if (-not $NoBrowser) {
|
||||||
Start-Process $url
|
# Browser plattformneutral oeffnen.
|
||||||
|
try {
|
||||||
|
if ($isWin) { Start-Process $url }
|
||||||
|
elseif ($IsMacOS) { & /usr/bin/open $url }
|
||||||
|
elseif ($IsLinux) { & xdg-open $url }
|
||||||
|
else { Start-Process $url }
|
||||||
|
} catch {
|
||||||
|
Write-Host " (Browser konnte nicht automatisch geoeffnet werden - bitte $url manuell aufrufen.)" -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Start-WebServer -Port $Port
|
Start-WebServer -Port $Port
|
||||||
|
|||||||
+21
@@ -2840,11 +2840,28 @@ function Update-AppEndpoint {
|
|||||||
# nie heraus — deshalb der Backend-Dialog. Laeuft in einem STA-Runspace, weil
|
# nie heraus — deshalb der Backend-Dialog. Laeuft in einem STA-Runspace, weil
|
||||||
# WinForms-Dialoge zwingend STA brauchen. Owner-Form mit TopMost holt den Dialog
|
# WinForms-Dialoge zwingend STA brauchen. Owner-Form mit TopMost holt den Dialog
|
||||||
# vor das Browser-Fenster.
|
# vor das Browser-Fenster.
|
||||||
|
# macOS-nativer Auswahldialog via osascript. Liefert den POSIX-Pfad oder ''
|
||||||
|
# (Abbruch). Der Windows-Filter-String wird ignoriert (AppleScript kennt ihn nicht).
|
||||||
|
function Show-MacChooser {
|
||||||
|
param([ValidateSet('file','folder')][string]$Kind, [string]$Title = '')
|
||||||
|
$prompt = ($Title -replace '"', '\"')
|
||||||
|
$verb = if ($Kind -eq 'folder') { 'choose folder' } else { 'choose file' }
|
||||||
|
$script = "POSIX path of ($verb with prompt `"$prompt`")"
|
||||||
|
try {
|
||||||
|
$out = & /usr/bin/osascript -e $script 2>$null
|
||||||
|
return ([string]$out).Trim()
|
||||||
|
} catch { return '' }
|
||||||
|
}
|
||||||
|
|
||||||
function Show-OpenFileDialog {
|
function Show-OpenFileDialog {
|
||||||
param(
|
param(
|
||||||
[string]$Filter = "Alle Dateien (*.*)|*.*",
|
[string]$Filter = "Alle Dateien (*.*)|*.*",
|
||||||
[string]$Title = "Datei auswaehlen"
|
[string]$Title = "Datei auswaehlen"
|
||||||
)
|
)
|
||||||
|
if (-not (Test-IsWindows)) {
|
||||||
|
if ($IsMacOS) { return (Show-MacChooser -Kind 'file' -Title $Title) }
|
||||||
|
throw 'Datei-Dialog wird auf dieser Plattform nicht unterstuetzt - Pfad bitte manuell eingeben.'
|
||||||
|
}
|
||||||
# Eigener powershell.exe -STA Prozess: in einem In-Process-Runspace blitzt
|
# Eigener powershell.exe -STA Prozess: in einem In-Process-Runspace blitzt
|
||||||
# der Dialog nur kurz auf (keine echte Windows-Message-Pump, er bleibt nicht
|
# der Dialog nur kurz auf (keine echte Windows-Message-Pump, er bleibt nicht
|
||||||
# modal). Ein separater STA-Konsolen-Prozess hat einen vollwertigen
|
# modal). Ein separater STA-Konsolen-Prozess hat einen vollwertigen
|
||||||
@@ -2906,6 +2923,10 @@ function Invoke-FilePickerEndpoint {
|
|||||||
function Show-OpenFolderDialog {
|
function Show-OpenFolderDialog {
|
||||||
# Wie Show-OpenFileDialog, aber FolderBrowserDialog in einem STA-Prozess.
|
# Wie Show-OpenFileDialog, aber FolderBrowserDialog in einem STA-Prozess.
|
||||||
param([string]$Title = "Ordner auswaehlen")
|
param([string]$Title = "Ordner auswaehlen")
|
||||||
|
if (-not (Test-IsWindows)) {
|
||||||
|
if ($IsMacOS) { return (Show-MacChooser -Kind 'folder' -Title $Title) }
|
||||||
|
throw 'Ordner-Dialog wird auf dieser Plattform nicht unterstuetzt - Pfad bitte manuell eingeben.'
|
||||||
|
}
|
||||||
$tEsc = $Title -replace "'", "''"
|
$tEsc = $Title -replace "'", "''"
|
||||||
$inner = @"
|
$inner = @"
|
||||||
`$ProgressPreference = 'SilentlyContinue'
|
`$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|||||||
+26
-2
@@ -26,13 +26,37 @@ function ConvertTo-IsoDate {
|
|||||||
return $s
|
return $s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Plattform-Helfer: App-Daten-Verzeichnis (Settings, Exporte).
|
||||||
|
# Windows: %APPDATA%\IntuneAppManager-Web (unveraendert).
|
||||||
|
# macOS: ~/Library/Application Support/IntuneAppManager-Web
|
||||||
|
# Linux: $XDG_CONFIG_HOME bzw. ~/.config/IntuneAppManager-Web
|
||||||
|
# ============================================================
|
||||||
|
function Test-IsWindows {
|
||||||
|
# PS5.1 kennt $IsWindows nicht -> $env:OS faengt das ab.
|
||||||
|
return (($env:OS -eq 'Windows_NT') -or ($PSVersionTable.PSVersion.Major -lt 6) -or $IsWindows)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AppDataDir {
|
||||||
|
$base = if ($env:APPDATA) {
|
||||||
|
$env:APPDATA
|
||||||
|
} elseif ($IsMacOS) {
|
||||||
|
Join-Path $HOME 'Library/Application Support'
|
||||||
|
} elseif ($IsLinux) {
|
||||||
|
if ($env:XDG_CONFIG_HOME) { $env:XDG_CONFIG_HOME } else { Join-Path $HOME '.config' }
|
||||||
|
} else {
|
||||||
|
[Environment]::GetFolderPath('ApplicationData')
|
||||||
|
}
|
||||||
|
return (Join-Path $base 'IntuneAppManager-Web')
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Settings: editierbare Konfiguration, persistiert als JSON
|
# Settings: editierbare Konfiguration, persistiert als JSON
|
||||||
# unter %APPDATA%\IntuneAppManager-Web\settings.json
|
# unter <AppData>\IntuneAppManager-Web\settings.json
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
function Get-SettingsPath {
|
function Get-SettingsPath {
|
||||||
$dir = Join-Path $env:APPDATA "IntuneAppManager-Web"
|
$dir = Get-AppDataDir
|
||||||
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
||||||
return Join-Path $dir "settings.json"
|
return Join-Path $dir "settings.json"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -14,8 +14,7 @@
|
|||||||
# JSON-Inhalt (Frontend-Upload) oder eine Datei aus dem Server-Archiv.
|
# JSON-Inhalt (Frontend-Upload) oder eine Datei aus dem Server-Archiv.
|
||||||
|
|
||||||
function Get-PolicyExportDir {
|
function Get-PolicyExportDir {
|
||||||
$dir = Join-Path $env:APPDATA 'IntuneAppManager-Web'
|
$dir = Join-Path (Get-AppDataDir) 'policy-exports'
|
||||||
$dir = Join-Path $dir 'policy-exports'
|
|
||||||
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
||||||
return $dir
|
return $dir
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user