1529 lines
70 KiB
PowerShell
1529 lines
70 KiB
PowerShell
#Requires -Version 5.1
|
|
# Firefox Add-on Manager - Maschinenbasierte Bereitstellung
|
|
# Fuer maschinenweite Deployment-Optionen als Administrator ausfuehren.
|
|
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
# ---- Hilfsfunktionen ----
|
|
|
|
function Find-FirefoxProfile {
|
|
$appData = [Environment]::GetFolderPath("ApplicationData")
|
|
$profilesPath = Join-Path $appData "Mozilla\Firefox\Profiles"
|
|
if (-not (Test-Path $profilesPath)) { return $null }
|
|
$profiles = Get-ChildItem $profilesPath -Directory |
|
|
Where-Object { $_.Name -match '\.default' -or $_.Name -match 'default-release' }
|
|
if ($profiles) { return $profiles[0].FullName }
|
|
$all = Get-ChildItem $profilesPath -Directory
|
|
if ($all) { return $all[0].FullName }
|
|
return $null
|
|
}
|
|
|
|
function Find-FirefoxInstallDir {
|
|
$candidates = @(
|
|
"C:\Program Files\Mozilla Firefox",
|
|
"C:\Program Files (x86)\Mozilla Firefox"
|
|
)
|
|
foreach ($c in $candidates) {
|
|
if (Test-Path (Join-Path $c "firefox.exe")) { return $c }
|
|
}
|
|
# Suche in Registry
|
|
try {
|
|
$reg = Get-ItemProperty "HKLM:\SOFTWARE\Mozilla\Mozilla Firefox" -ErrorAction Stop
|
|
$installDir = $reg."Install Directory"
|
|
if ($installDir -and (Test-Path $installDir)) { return $installDir }
|
|
} catch {}
|
|
return $null
|
|
}
|
|
|
|
function Get-InstalledAddons {
|
|
param([string]$ProfilePath)
|
|
$extensionsJson = Join-Path $ProfilePath "extensions.json"
|
|
if (-not (Test-Path $extensionsJson)) { return @() }
|
|
$json = Get-Content $extensionsJson -Raw | ConvertFrom-Json
|
|
return $json.addons |
|
|
Where-Object { $_.type -eq "extension" } |
|
|
Select-Object id, defaultLocale, version, active
|
|
}
|
|
|
|
function Install-AddonFromFile {
|
|
param([string]$ProfilePath, [string]$XpiPath)
|
|
$extensionsDir = Join-Path $ProfilePath "extensions"
|
|
if (-not (Test-Path $extensionsDir)) {
|
|
New-Item -ItemType Directory -Path $extensionsDir | Out-Null
|
|
}
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$zip = [System.IO.Compression.ZipFile]::OpenRead($XpiPath)
|
|
try {
|
|
$manifestEntry = $zip.Entries | Where-Object { $_.Name -eq "manifest.json" }
|
|
if (-not $manifestEntry) { throw "Kein manifest.json in der XPI-Datei gefunden." }
|
|
$reader = New-Object System.IO.StreamReader($manifestEntry.Open())
|
|
$manifest = $reader.ReadToEnd() | ConvertFrom-Json
|
|
$reader.Close()
|
|
$addonId = $null
|
|
if ($manifest.browser_specific_settings.gecko.id) {
|
|
$addonId = $manifest.browser_specific_settings.gecko.id
|
|
} elseif ($manifest.applications.gecko.id) {
|
|
$addonId = $manifest.applications.gecko.id
|
|
} else {
|
|
$addonId = [System.IO.Path]::GetFileNameWithoutExtension($XpiPath) + "@local"
|
|
}
|
|
} finally {
|
|
$zip.Dispose()
|
|
}
|
|
$dest = Join-Path $extensionsDir "$addonId.xpi"
|
|
Copy-Item -Path $XpiPath -Destination $dest -Force
|
|
return $addonId
|
|
}
|
|
|
|
function Open-AddonPage {
|
|
param([string]$Url)
|
|
Start-Process "firefox" $Url -ErrorAction SilentlyContinue
|
|
if ($LASTEXITCODE -ne 0) { Start-Process $Url }
|
|
}
|
|
|
|
function Test-IsAdmin {
|
|
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object System.Security.Principal.WindowsPrincipal($id)
|
|
return $principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
function Test-IntuneManaged {
|
|
# Intune schreibt Firefox-Policies unter HKLM\SOFTWARE\Policies\Mozilla\Firefox
|
|
# Wenn dieser Key existiert und NICHT von uns stammt, verwaltet Intune Firefox
|
|
$key = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox"
|
|
if (Test-Path $key) {
|
|
$props = Get-ItemProperty $key -ErrorAction SilentlyContinue
|
|
# Intune setzt typischerweise DisableAppUpdate, DontCheckDefaultBrowser o.ae.
|
|
if ($props) { return $true }
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Get-ActiveFirefoxPolicies {
|
|
# Liest alle aktiven Registry-Policies aus
|
|
$base = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox"
|
|
$result = @()
|
|
if (-not (Test-Path $base)) { return $result }
|
|
function Read-RegTree {
|
|
param([string]$Path, [string]$Indent = "")
|
|
$props = Get-ItemProperty $Path -ErrorAction SilentlyContinue
|
|
if ($props) {
|
|
foreach ($p in $props.PSObject.Properties) {
|
|
if ($p.Name -notmatch '^PS') {
|
|
$result += $Indent + $p.Name + " = " + $p.Value
|
|
}
|
|
}
|
|
}
|
|
Get-ChildItem $Path -ErrorAction SilentlyContinue | ForEach-Object {
|
|
$result += $Indent + "[" + $_.PSChildName + "]"
|
|
Read-RegTree -Path $_.PSPath -Indent ($Indent + " ")
|
|
}
|
|
}
|
|
Read-RegTree -Path $base
|
|
return $result
|
|
}
|
|
|
|
function Export-RegFile {
|
|
param([string]$OutputPath, [array]$Addons)
|
|
$lines = @()
|
|
$lines += "Windows Registry Editor Version 5.00"
|
|
$lines += ""
|
|
$lines += "; Firefox Add-on Deployment via Intune Custom Policy"
|
|
$lines += "; Importieren: doppelklick auf .reg oder via Intune > Devices > Configuration > Custom (OMA-URI)"
|
|
$lines += ""
|
|
$lines += "[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings]"
|
|
$lines += ""
|
|
foreach ($a in $Addons) {
|
|
$url = if ($a.Url -and $a.Url.StartsWith("http")) { $a.Url } else {
|
|
"https://addons.mozilla.org/firefox/downloads/latest/latest.xpi"
|
|
}
|
|
# Registry-Schluessel-Namen muessen Backslashes escapen
|
|
$escapedId = $a.Id -replace '\\', '\\'
|
|
$lines += '[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings\' + $escapedId + ']'
|
|
$lines += '"installation_mode"="force_installed"'
|
|
$lines += '"install_url"="' + ($url -replace '\\', '\\') + '"'
|
|
$lines += ""
|
|
}
|
|
$lines | Out-File -FilePath $OutputPath -Encoding Unicode
|
|
}
|
|
|
|
# ---- Add-on Datenbank ----
|
|
$AllAddons = [System.Collections.Generic.List[PSCustomObject]]::new()
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="uBlock Origin"; Id="uBlock0@raymondhill.net"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/ublock-origin/"
|
|
Beschreibung="Effizienter Werbeblocker"
|
|
})
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="Privacy Badger"; Id="jid1-MnnxcxisBPnSXQ@jetpack"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/privacy-badger17/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/privacy-badger17/"
|
|
Beschreibung="Schutz vor Tracking"
|
|
})
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="Bitwarden"; Id="{446900e4-71c2-419f-a6a7-df9c091e268b}"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/"
|
|
Beschreibung="Passwort-Manager"
|
|
})
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="Dark Reader"; Id="addon@darkreader.org"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/darkreader/"
|
|
Beschreibung="Dunkles Design fuer alle Seiten"
|
|
})
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="Cookie AutoDelete"; Id="CookieAutoDelete@kennydo.com"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/cookie-autodelete/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/cookie-autodelete/"
|
|
Beschreibung="Cookies automatisch loeschen"
|
|
})
|
|
$AllAddons.Add([PSCustomObject]@{
|
|
Name="Ghostery"; Id="firefox@ghostery.com"
|
|
Url="https://addons.mozilla.org/firefox/downloads/latest/ghostery/latest.xpi"
|
|
StoreUrl="https://addons.mozilla.org/firefox/addon/ghostery/"
|
|
Beschreibung="Anti-Tracking und Werbeblocker"
|
|
})
|
|
|
|
# ---- GUI ----
|
|
|
|
$form = New-Object System.Windows.Forms.Form
|
|
$form.Text = "Firefox Add-on Manager - Maschinenbasierte Bereitstellung"
|
|
$form.Size = New-Object System.Drawing.Size(900, 680)
|
|
$form.StartPosition = "CenterScreen"
|
|
$form.FormBorderStyle = "FixedSingle"
|
|
$form.MaximizeBox = $false
|
|
$form.BackColor = [System.Drawing.Color]::FromArgb(245, 245, 250)
|
|
|
|
# Banner
|
|
$banner = New-Object System.Windows.Forms.Panel
|
|
$banner.Size = New-Object System.Drawing.Size(900, 60)
|
|
$banner.Location = New-Object System.Drawing.Point(0, 0)
|
|
$banner.BackColor = [System.Drawing.Color]::FromArgb(255, 100, 20)
|
|
$form.Controls.Add($banner)
|
|
|
|
$titleLabel = New-Object System.Windows.Forms.Label
|
|
$titleLabel.Text = "Firefox Add-on Manager"
|
|
$titleLabel.Font = New-Object System.Drawing.Font("Segoe UI", 16, [System.Drawing.FontStyle]::Bold)
|
|
$titleLabel.ForeColor = [System.Drawing.Color]::White
|
|
$titleLabel.AutoSize = $true
|
|
$titleLabel.Location = New-Object System.Drawing.Point(15, 10)
|
|
$banner.Controls.Add($titleLabel)
|
|
|
|
$adminLabel = New-Object System.Windows.Forms.Label
|
|
if (Test-IsAdmin) {
|
|
$adminLabel.Text = "Administrator-Modus aktiv"
|
|
$adminLabel.ForeColor = [System.Drawing.Color]::LightGreen
|
|
} else {
|
|
$adminLabel.Text = "KEIN Admin - maschinenweite Bereitstellung eingeschraenkt"
|
|
$adminLabel.ForeColor = [System.Drawing.Color]::Yellow
|
|
}
|
|
$adminLabel.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$adminLabel.AutoSize = $true
|
|
$adminLabel.Location = New-Object System.Drawing.Point(17, 40)
|
|
$banner.Controls.Add($adminLabel)
|
|
|
|
# TabControl
|
|
$tabs = New-Object System.Windows.Forms.TabControl
|
|
$tabs.Location = New-Object System.Drawing.Point(10, 70)
|
|
$tabs.Size = New-Object System.Drawing.Size(870, 535)
|
|
$tabs.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
|
$form.Controls.Add($tabs)
|
|
|
|
# ===========================================================
|
|
# TAB 1: Maschinenbasierte Bereitstellung (policies.json)
|
|
# ===========================================================
|
|
$tabDeploy = New-Object System.Windows.Forms.TabPage
|
|
$tabDeploy.Text = "Maschinenweite Bereitstellung"
|
|
$tabs.Controls.Add($tabDeploy)
|
|
|
|
# Info-Box
|
|
$pnlInfo = New-Object System.Windows.Forms.Panel
|
|
$pnlInfo.Location = New-Object System.Drawing.Point(10, 10)
|
|
$pnlInfo.Size = New-Object System.Drawing.Size(845, 55)
|
|
$pnlInfo.BackColor = [System.Drawing.Color]::FromArgb(220, 235, 255)
|
|
$pnlInfo.BorderStyle = "FixedSingle"
|
|
$tabDeploy.Controls.Add($pnlInfo)
|
|
|
|
$lblInfoText = New-Object System.Windows.Forms.Label
|
|
$lblInfoText.Text = "Add-ons werden per Firefox Enterprise Policy (policies.json) oder Windows Registry fuer ALLE Benutzer" +
|
|
" dieser Maschine zwingend installiert. Erfordert Administratorrechte und Firefox-Neustart."
|
|
$lblInfoText.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$lblInfoText.Location = New-Object System.Drawing.Point(5, 5)
|
|
$lblInfoText.Size = New-Object System.Drawing.Size(833, 44)
|
|
$pnlInfo.Controls.Add($lblInfoText)
|
|
|
|
# Interne URL Warnung
|
|
$pnlUrlWarn = New-Object System.Windows.Forms.Panel
|
|
$pnlUrlWarn.Location = New-Object System.Drawing.Point(10, 75)
|
|
$pnlUrlWarn.Size = New-Object System.Drawing.Size(845, 28)
|
|
$pnlUrlWarn.BackColor = [System.Drawing.Color]::FromArgb(255, 240, 200)
|
|
$pnlUrlWarn.BorderStyle = "FixedSingle"
|
|
$tabDeploy.Controls.Add($pnlUrlWarn)
|
|
|
|
$lblUrlWarn = New-Object System.Windows.Forms.Label
|
|
$lblUrlWarn.Text = "Intune/Firmen-Umgebung: addons.mozilla.org ist moeglicherweise blockiert. " +
|
|
"Bitte XPIs herunterladen, intern hosten und interne URL eintragen (Spalte 'Interne URL')."
|
|
$lblUrlWarn.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$lblUrlWarn.ForeColor = [System.Drawing.Color]::DarkOrange
|
|
$lblUrlWarn.Location = New-Object System.Drawing.Point(5, 6)
|
|
$lblUrlWarn.AutoSize = $true
|
|
$pnlUrlWarn.Controls.Add($lblUrlWarn)
|
|
|
|
# Add-on Auswahl
|
|
$grpSelect = New-Object System.Windows.Forms.GroupBox
|
|
$grpSelect.Text = "Add-ons auswaehlen (Doppelklick = interne URL bearbeiten)"
|
|
$grpSelect.Location = New-Object System.Drawing.Point(10, 110)
|
|
$grpSelect.Size = New-Object System.Drawing.Size(845, 175)
|
|
$grpSelect.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabDeploy.Controls.Add($grpSelect)
|
|
|
|
$lvDeploy = New-Object System.Windows.Forms.ListView
|
|
$lvDeploy.Location = New-Object System.Drawing.Point(10, 18)
|
|
$lvDeploy.Size = New-Object System.Drawing.Size(822, 148)
|
|
$lvDeploy.View = [System.Windows.Forms.View]::Details
|
|
$lvDeploy.CheckBoxes = $true
|
|
$lvDeploy.FullRowSelect = $true
|
|
$lvDeploy.GridLines = $true
|
|
$lvDeploy.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lvDeploy.Columns.Add("Add-on Name", 160) | Out-Null
|
|
$lvDeploy.Columns.Add("Add-on ID", 210) | Out-Null
|
|
$lvDeploy.Columns.Add("Interne URL (leer = AMO)", 420) | Out-Null
|
|
|
|
foreach ($addon in $AllAddons) {
|
|
$item = New-Object System.Windows.Forms.ListViewItem($addon.Name)
|
|
$item.SubItems.Add($addon.Id) | Out-Null
|
|
$item.SubItems.Add("") | Out-Null # Interne URL leer = AMO wird genutzt
|
|
$item.Tag = $addon
|
|
$lvDeploy.Items.Add($item) | Out-Null
|
|
}
|
|
|
|
# Doppelklick: interne URL bearbeiten
|
|
$lvDeploy.Add_DoubleClick({
|
|
if ($lvDeploy.SelectedItems.Count -eq 0) { return }
|
|
$sel = $lvDeploy.SelectedItems[0]
|
|
$currentUrl = $sel.SubItems[2].Text
|
|
$dlg = New-Object System.Windows.Forms.Form
|
|
$dlg.Text = "Interne URL fuer: " + $sel.Text
|
|
$dlg.Size = New-Object System.Drawing.Size(620, 130)
|
|
$dlg.StartPosition = "CenterParent"
|
|
$dlg.FormBorderStyle = "FixedDialog"
|
|
$dlg.MaximizeBox = $false; $dlg.MinimizeBox = $false
|
|
|
|
$lbl = New-Object System.Windows.Forms.Label
|
|
$lbl.Text = "Interne HTTPS-URL zur XPI-Datei (leer lassen = addons.mozilla.org wird verwendet):"
|
|
$lbl.Location = New-Object System.Drawing.Point(10, 10)
|
|
$lbl.Size = New-Object System.Drawing.Size(590, 18)
|
|
$lbl.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$dlg.Controls.Add($lbl)
|
|
|
|
$txt = New-Object System.Windows.Forms.TextBox
|
|
$txt.Location = New-Object System.Drawing.Point(10, 32)
|
|
$txt.Size = New-Object System.Drawing.Size(590, 23)
|
|
$txt.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$txt.Text = $currentUrl
|
|
$dlg.Controls.Add($txt)
|
|
|
|
$btnOk = New-Object System.Windows.Forms.Button
|
|
$btnOk.Text = "OK"; $btnOk.Location = New-Object System.Drawing.Point(440, 62)
|
|
$btnOk.Size = New-Object System.Drawing.Size(75, 26)
|
|
$btnOk.DialogResult = "OK"
|
|
$dlg.Controls.Add($btnOk); $dlg.AcceptButton = $btnOk
|
|
|
|
$btnClear = New-Object System.Windows.Forms.Button
|
|
$btnClear.Text = "Leeren"; $btnClear.Location = New-Object System.Drawing.Point(520, 62)
|
|
$btnClear.Size = New-Object System.Drawing.Size(75, 26)
|
|
$btnClear.Add_Click({ $txt.Text = ""; $dlg.DialogResult = "OK"; $dlg.Close() })
|
|
$dlg.Controls.Add($btnClear)
|
|
|
|
if ($dlg.ShowDialog() -eq "OK") {
|
|
$sel.SubItems[2].Text = $txt.Text.Trim()
|
|
if ($txt.Text.Trim() -ne "") {
|
|
$sel.ForeColor = [System.Drawing.Color]::DarkGreen
|
|
} else {
|
|
$sel.ForeColor = [System.Drawing.Color]::Black
|
|
}
|
|
}
|
|
})
|
|
$grpSelect.Controls.Add($lvDeploy)
|
|
|
|
# XPI herunterladen Button (nebeneinander mit Auswahl)
|
|
$btnDownloadXpis = New-Object System.Windows.Forms.Button
|
|
$btnDownloadXpis.Text = "XPIs herunterladen (fuer internes Hosting)"
|
|
$btnDownloadXpis.Size = New-Object System.Drawing.Size(280, 30)
|
|
$btnDownloadXpis.Location = New-Object System.Drawing.Point(10, 290)
|
|
$btnDownloadXpis.BackColor = [System.Drawing.Color]::FromArgb(0, 120, 80)
|
|
$btnDownloadXpis.ForeColor = [System.Drawing.Color]::White
|
|
$btnDownloadXpis.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnDownloadXpis.FlatStyle = "Flat"
|
|
$btnDownloadXpis.FlatAppearance.BorderSize = 0
|
|
$btnDownloadXpis.Add_Click({
|
|
$selected = $lvDeploy.Items | Where-Object { $_.Checked }
|
|
if ($selected.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show("Bitte mindestens ein Add-on auswaehlen.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$fbd = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
$fbd.Description = "Zielordner fuer XPI-Dateien auswaehlen"
|
|
if ($fbd.ShowDialog() -ne "OK") { return }
|
|
|
|
$errors = @()
|
|
foreach ($item in $selected) {
|
|
$addon = $item.Tag
|
|
$url = $addon.Url
|
|
$fileName = $addon.Name -replace '[^\w]', '_'
|
|
$dest = Join-Path $fbd.SelectedPath ($fileName + ".xpi")
|
|
try {
|
|
$wc = New-Object System.Net.WebClient
|
|
$wc.DownloadFile($url, $dest)
|
|
# Interne URL vorschlagen
|
|
$item.SubItems[2].Text = "(XPI gespeichert: $dest - bitte interne URL eintragen)"
|
|
$item.ForeColor = [System.Drawing.Color]::DarkBlue
|
|
} catch {
|
|
$errors += $addon.Name + ": " + $_
|
|
}
|
|
}
|
|
if ($errors.Count -gt 0) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Fehler beim Herunterladen:`n" + ($errors -join "`n"),
|
|
"Fehler", "OK", "Error")
|
|
} else {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"XPI-Dateien gespeichert in:`n" + $fbd.SelectedPath +
|
|
"`n`nNaechste Schritte:`n" +
|
|
"1. Dateien auf internen Webserver / SharePoint / Azure Blob hochladen`n" +
|
|
"2. HTTPS-URL per Doppelklick in der Liste eintragen`n" +
|
|
"3. Bereitstellung ausfuehren",
|
|
"Download abgeschlossen", "OK", "Information")
|
|
}
|
|
})
|
|
$tabDeploy.Controls.Add($btnDownloadXpis)
|
|
|
|
# Eigene Add-on ID hinzufuegen
|
|
$grpCustom = New-Object System.Windows.Forms.GroupBox
|
|
$grpCustom.Text = "Eigene Add-on ID hinzufuegen (z.B. aus eigenem Add-on)"
|
|
$grpCustom.Location = New-Object System.Drawing.Point(10, 283)
|
|
$grpCustom.Size = New-Object System.Drawing.Size(845, 72)
|
|
$grpCustom.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabDeploy.Controls.Add($grpCustom)
|
|
|
|
$lblCustomIdHint = New-Object System.Windows.Forms.Label
|
|
$lblCustomIdHint.Text = "Add-on ID (z.B. myaddon@firma.de):"
|
|
$lblCustomIdHint.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$lblCustomIdHint.ForeColor = [System.Drawing.Color]::Gray
|
|
$lblCustomIdHint.Location = New-Object System.Drawing.Point(10, 8)
|
|
$lblCustomIdHint.AutoSize = $true
|
|
$grpCustom.Controls.Add($lblCustomIdHint)
|
|
|
|
$txtCustomId = New-Object System.Windows.Forms.TextBox
|
|
$txtCustomId.Location = New-Object System.Drawing.Point(10, 25)
|
|
$txtCustomId.Size = New-Object System.Drawing.Size(380, 23)
|
|
$txtCustomId.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$grpCustom.Controls.Add($txtCustomId)
|
|
|
|
$lblCustomUrlHint = New-Object System.Windows.Forms.Label
|
|
$lblCustomUrlHint.Text = "Download-URL der XPI (optional):"
|
|
$lblCustomUrlHint.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
|
$lblCustomUrlHint.ForeColor = [System.Drawing.Color]::Gray
|
|
$lblCustomUrlHint.Location = New-Object System.Drawing.Point(400, 8)
|
|
$lblCustomUrlHint.AutoSize = $true
|
|
$grpCustom.Controls.Add($lblCustomUrlHint)
|
|
|
|
$txtCustomUrl = New-Object System.Windows.Forms.TextBox
|
|
$txtCustomUrl.Location = New-Object System.Drawing.Point(400, 25)
|
|
$txtCustomUrl.Size = New-Object System.Drawing.Size(318, 23)
|
|
$txtCustomUrl.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$grpCustom.Controls.Add($txtCustomUrl)
|
|
|
|
$btnAddCustom = New-Object System.Windows.Forms.Button
|
|
$btnAddCustom.Text = "+ Hinzufuegen"
|
|
$btnAddCustom.Location = New-Object System.Drawing.Point(728, 34)
|
|
$btnAddCustom.Size = New-Object System.Drawing.Size(108, 27)
|
|
$btnAddCustom.Add_Click({
|
|
if ($txtCustomId.Text.Trim() -eq "") {
|
|
[System.Windows.Forms.MessageBox]::Show("Bitte Add-on ID eingeben.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$newItem = New-Object System.Windows.Forms.ListViewItem("[Eigene] " + $txtCustomId.Text.Trim())
|
|
$newItem.SubItems.Add("Eigenes Add-on") | Out-Null
|
|
$newItem.SubItems.Add($txtCustomId.Text.Trim()) | Out-Null
|
|
$customAddon = [PSCustomObject]@{
|
|
Name="[Eigene] " + $txtCustomId.Text.Trim()
|
|
Id=$txtCustomId.Text.Trim()
|
|
Url=$txtCustomUrl.Text.Trim()
|
|
Beschreibung="Eigenes Add-on"
|
|
}
|
|
$newItem.Tag = $customAddon
|
|
$newItem.Checked = $true
|
|
$lvDeploy.Items.Add($newItem) | Out-Null
|
|
$txtCustomId.Text = ""
|
|
$txtCustomUrl.Text = ""
|
|
})
|
|
$grpCustom.Controls.Add($btnAddCustom)
|
|
|
|
# Bereitstellungs-Optionen
|
|
$grpMethod = New-Object System.Windows.Forms.GroupBox
|
|
$grpMethod.Text = "Bereitstellungs-Methode"
|
|
$grpMethod.Location = New-Object System.Drawing.Point(10, 352)
|
|
$grpMethod.Size = New-Object System.Drawing.Size(845, 70)
|
|
$grpMethod.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabDeploy.Controls.Add($grpMethod)
|
|
|
|
$rbPoliciesJson = New-Object System.Windows.Forms.RadioButton
|
|
$rbPoliciesJson.Text = "policies.json (direkt in Firefox-Installationsordner - empfohlen)"
|
|
$rbPoliciesJson.Location = New-Object System.Drawing.Point(10, 20)
|
|
$rbPoliciesJson.AutoSize = $true
|
|
$rbPoliciesJson.Checked = $true
|
|
$rbPoliciesJson.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$grpMethod.Controls.Add($rbPoliciesJson)
|
|
|
|
$rbRegistry = New-Object System.Windows.Forms.RadioButton
|
|
$rbRegistry.Text = "Windows Registry (HKLM - GPO-kompatibel, fuer Gruppenrichtlinien-Umgebungen)"
|
|
$rbRegistry.Location = New-Object System.Drawing.Point(10, 42)
|
|
$rbRegistry.AutoSize = $true
|
|
$rbRegistry.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$grpMethod.Controls.Add($rbRegistry)
|
|
|
|
# Aktions-Buttons
|
|
$btnDeploy = New-Object System.Windows.Forms.Button
|
|
$btnDeploy.Text = "Jetzt bereitstellen (diese Maschine)"
|
|
$btnDeploy.Size = New-Object System.Drawing.Size(260, 40)
|
|
$btnDeploy.Location = New-Object System.Drawing.Point(10, 435)
|
|
$btnDeploy.BackColor = [System.Drawing.Color]::FromArgb(255, 100, 20)
|
|
$btnDeploy.ForeColor = [System.Drawing.Color]::White
|
|
$btnDeploy.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
|
|
$btnDeploy.FlatStyle = "Flat"
|
|
$btnDeploy.FlatAppearance.BorderSize = 0
|
|
$btnDeploy.Add_Click({
|
|
$selected = $lvDeploy.Items | Where-Object { $_.Checked }
|
|
if ($selected.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Bitte mindestens ein Add-on auswaehlen.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
if (-not (Test-IsAdmin)) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Maschinenweite Bereitstellung erfordert Administratorrechte.`n" +
|
|
"Bitte das Skript als Administrator ausfuehren.",
|
|
"Kein Administrator", "OK", "Warning")
|
|
return
|
|
}
|
|
|
|
# Interne URL aus ListView-Spalte 2 uebernehmen (per Doppelklick eingetragen)
|
|
$addonsToInstall = $selected | ForEach-Object {
|
|
$clone = [PSCustomObject]@{
|
|
Name = $_.Tag.Name
|
|
Id = $_.Tag.Id
|
|
Url = $_.Tag.Url
|
|
Beschreibung= $_.Tag.Beschreibung
|
|
}
|
|
$internalUrl = $_.SubItems[2].Text.Trim()
|
|
if ($internalUrl -ne "" -and $internalUrl.StartsWith("http")) {
|
|
$clone.Url = $internalUrl
|
|
}
|
|
$clone
|
|
}
|
|
|
|
if ($rbPoliciesJson.Checked) {
|
|
# --- policies.json Methode ---
|
|
$ffDir = Find-FirefoxInstallDir
|
|
if (-not $ffDir) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Firefox-Installationsverzeichnis nicht gefunden.`n" +
|
|
"Bitte Firefox installieren oder den Pfad pruefen.",
|
|
"Fehler", "OK", "Error")
|
|
return
|
|
}
|
|
$distributionDir = Join-Path $ffDir "distribution"
|
|
if (-not (Test-Path $distributionDir)) {
|
|
New-Item -ItemType Directory -Path $distributionDir | Out-Null
|
|
}
|
|
$policiesFile = Join-Path $distributionDir "policies.json"
|
|
|
|
# Vorhandene policies.json einlesen oder neu erstellen
|
|
if (Test-Path $policiesFile) {
|
|
$existingJson = Get-Content $policiesFile -Raw | ConvertFrom-Json
|
|
} else {
|
|
$existingJson = [PSCustomObject]@{ policies = [PSCustomObject]@{} }
|
|
}
|
|
if (-not $existingJson.policies.PSObject.Properties["ExtensionSettings"]) {
|
|
$existingJson.policies | Add-Member -NotePropertyName "ExtensionSettings" `
|
|
-NotePropertyValue ([PSCustomObject]@{}) -Force
|
|
}
|
|
|
|
foreach ($a in $addonsToInstall) {
|
|
$setting = [PSCustomObject]@{
|
|
installation_mode = "force_installed"
|
|
}
|
|
if ($a.Url -and $a.Url.StartsWith("http")) {
|
|
$setting | Add-Member -NotePropertyName "install_url" -NotePropertyValue $a.Url
|
|
}
|
|
$existingJson.policies.ExtensionSettings |
|
|
Add-Member -NotePropertyName $a.Id -NotePropertyValue $setting -Force
|
|
}
|
|
|
|
$existingJson | ConvertTo-Json -Depth 10 | Set-Content $policiesFile -Encoding UTF8
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"policies.json erfolgreich geschrieben:`n$policiesFile`n`n" +
|
|
"Die folgenden Add-ons werden beim naechsten Firefox-Start automatisch fuer alle Benutzer installiert:`n" +
|
|
($addonsToInstall | ForEach-Object { " - " + $_.Name } | Out-String),
|
|
"Bereitstellung erfolgreich", "OK", "Information")
|
|
|
|
} else {
|
|
# --- Registry Methode (korrekte ExtensionSettings-Struktur) ---
|
|
# Firefox liest: HKLM\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings\<addon-id>
|
|
# Werte: installation_mode (REG_SZ) und install_url (REG_SZ)
|
|
$regBase = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings"
|
|
try {
|
|
if (-not (Test-Path $regBase)) {
|
|
New-Item -Path $regBase -Force | Out-Null
|
|
}
|
|
$written = @()
|
|
foreach ($a in $addonsToInstall) {
|
|
$addonKey = Join-Path $regBase $a.Id
|
|
if (-not (Test-Path $addonKey)) {
|
|
New-Item -Path $addonKey -Force | Out-Null
|
|
}
|
|
Set-ItemProperty -Path $addonKey -Name "installation_mode" `
|
|
-Value "force_installed" -Type String
|
|
$url = if ($a.Url -and $a.Url.StartsWith("http")) { $a.Url } else {
|
|
"https://addons.mozilla.org/firefox/downloads/latest/latest.xpi"
|
|
}
|
|
Set-ItemProperty -Path $addonKey -Name "install_url" -Value $url -Type String
|
|
|
|
# Verifizieren
|
|
$verify = Get-ItemProperty -Path $addonKey -ErrorAction SilentlyContinue
|
|
if ($verify.installation_mode -eq "force_installed") {
|
|
$written += $a.Name + " [OK] -> " + $addonKey
|
|
} else {
|
|
$written += $a.Name + " [FEHLER - Eintrag nicht verifiziert]"
|
|
}
|
|
}
|
|
$summary = $written | Out-String
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Registry-Eintraege gesetzt unter:`n$regBase\<addon-id>`n`n" +
|
|
"Ergebnis:`n" + $summary +
|
|
"`nFirefox beim naechsten Start installiert die Add-ons automatisch fuer alle Benutzer.",
|
|
"Bereitstellung erfolgreich", "OK", "Information")
|
|
} catch {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Registry-Fehler: $_`n`nBitte als Administrator ausfuehren.",
|
|
"Fehler", "OK", "Error")
|
|
}
|
|
}
|
|
})
|
|
$tabDeploy.Controls.Add($btnDeploy)
|
|
|
|
$btnExportScript = New-Object System.Windows.Forms.Button
|
|
$btnExportScript.Text = "Deployment-Skript exportieren"
|
|
$btnExportScript.Size = New-Object System.Drawing.Size(240, 40)
|
|
$btnExportScript.Location = New-Object System.Drawing.Point(280, 435)
|
|
$btnExportScript.BackColor = [System.Drawing.Color]::FromArgb(70, 130, 180)
|
|
$btnExportScript.ForeColor = [System.Drawing.Color]::White
|
|
$btnExportScript.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
|
$btnExportScript.FlatStyle = "Flat"
|
|
$btnExportScript.FlatAppearance.BorderSize = 0
|
|
$btnExportScript.Add_Click({
|
|
$selected = $lvDeploy.Items | Where-Object { $_.Checked }
|
|
if ($selected.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Bitte mindestens ein Add-on auswaehlen.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$sfd = New-Object System.Windows.Forms.SaveFileDialog
|
|
$sfd.Filter = "PowerShell-Skript (*.ps1)|*.ps1"
|
|
$sfd.FileName = "Deploy-FirefoxAddons.ps1"
|
|
if ($sfd.ShowDialog() -ne "OK") { return }
|
|
|
|
$addonsToInstall = $selected | ForEach-Object {
|
|
$clone = [PSCustomObject]@{
|
|
Name = $_.Tag.Name
|
|
Id = $_.Tag.Id
|
|
Url = $_.Tag.Url
|
|
Beschreibung= $_.Tag.Beschreibung
|
|
}
|
|
$internalUrl = $_.SubItems[2].Text.Trim()
|
|
if ($internalUrl -ne "" -and $internalUrl.StartsWith("http")) {
|
|
$clone.Url = $internalUrl
|
|
}
|
|
$clone
|
|
}
|
|
|
|
$lines = @()
|
|
$lines += "#Requires -RunAsAdministrator"
|
|
$lines += "# Automatisch generiertes Firefox Add-on Deployment-Skript"
|
|
$lines += "# Erstellt mit Firefox Add-on Manager"
|
|
$lines += ""
|
|
$lines += '$ffDir = "C:\Program Files\Mozilla Firefox"'
|
|
$lines += '$distributionDir = Join-Path $ffDir "distribution"'
|
|
$lines += 'if (-not (Test-Path $distributionDir)) { New-Item -ItemType Directory -Path $distributionDir | Out-Null }'
|
|
$lines += '$policiesFile = Join-Path $distributionDir "policies.json"'
|
|
$lines += ""
|
|
|
|
if ($rbPoliciesJson.Checked) {
|
|
$lines += "# policies.json erstellen"
|
|
$lines += '$policies = @{'
|
|
$lines += ' policies = @{'
|
|
$lines += ' ExtensionSettings = @{'
|
|
foreach ($a in $addonsToInstall) {
|
|
$lines += ' "' + $a.Id + '" = @{'
|
|
$lines += ' installation_mode = "force_installed"'
|
|
if ($a.Url -and $a.Url.StartsWith("http")) {
|
|
$lines += ' install_url = "' + $a.Url + '"'
|
|
}
|
|
$lines += ' }'
|
|
}
|
|
$lines += ' }'
|
|
$lines += ' }'
|
|
$lines += '}'
|
|
$lines += '$policies | ConvertTo-Json -Depth 10 | Set-Content $policiesFile -Encoding UTF8'
|
|
$lines += 'Write-Host "Deployment abgeschlossen. Firefox neu starten." -ForegroundColor Green'
|
|
} else {
|
|
$lines += "# Registry ExtensionSettings setzen"
|
|
$lines += '# Firefox liest: HKLM\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings\<addon-id>'
|
|
$lines += '$regBase = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings"'
|
|
$lines += 'if (-not (Test-Path $regBase)) { New-Item -Path $regBase -Force | Out-Null }'
|
|
foreach ($a in $addonsToInstall) {
|
|
$url = if ($a.Url -and $a.Url.StartsWith("http")) { $a.Url } else {
|
|
"https://addons.mozilla.org/firefox/downloads/latest/latest.xpi"
|
|
}
|
|
$lines += ""
|
|
$lines += "# " + $a.Name
|
|
$lines += '$addonKey = "' + ('HKLM:\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings\' + $a.Id) + '"'
|
|
$lines += 'New-Item -Path $addonKey -Force | Out-Null'
|
|
$lines += 'Set-ItemProperty -Path $addonKey -Name "installation_mode" -Value "force_installed" -Type String'
|
|
$lines += 'Set-ItemProperty -Path $addonKey -Name "install_url" -Value "' + $url + '" -Type String'
|
|
}
|
|
$lines += ""
|
|
$lines += 'Write-Host "Registry-Eintraege gesetzt. Firefox neu starten." -ForegroundColor Green'
|
|
}
|
|
|
|
$lines | Out-File -FilePath $sfd.FileName -Encoding UTF8
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Skript exportiert:`n" + $sfd.FileName,
|
|
"Export erfolgreich", "OK", "Information")
|
|
})
|
|
$tabDeploy.Controls.Add($btnExportScript)
|
|
|
|
$btnShowCurrent = New-Object System.Windows.Forms.Button
|
|
$btnShowCurrent.Text = "Aktuelle policies.json anzeigen"
|
|
$btnShowCurrent.Size = New-Object System.Drawing.Size(240, 40)
|
|
$btnShowCurrent.Location = New-Object System.Drawing.Point(530, 435)
|
|
$btnShowCurrent.BackColor = [System.Drawing.Color]::FromArgb(100, 100, 100)
|
|
$btnShowCurrent.ForeColor = [System.Drawing.Color]::White
|
|
$btnShowCurrent.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
|
$btnShowCurrent.FlatStyle = "Flat"
|
|
$btnShowCurrent.FlatAppearance.BorderSize = 0
|
|
$btnShowCurrent.Add_Click({
|
|
$ffDir = Find-FirefoxInstallDir
|
|
if (-not $ffDir) {
|
|
[System.Windows.Forms.MessageBox]::Show("Firefox-Installationsverzeichnis nicht gefunden.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$pf = Join-Path $ffDir "distribution\policies.json"
|
|
if (Test-Path $pf) {
|
|
$content = Get-Content $pf -Raw
|
|
$dlg = New-Object System.Windows.Forms.Form
|
|
$dlg.Text = "policies.json - " + $pf
|
|
$dlg.Size = New-Object System.Drawing.Size(700, 500)
|
|
$dlg.StartPosition = "CenterParent"
|
|
$tb = New-Object System.Windows.Forms.TextBox
|
|
$tb.Multiline = $true; $tb.ScrollBars = "Both"; $tb.ReadOnly = $true
|
|
$tb.Dock = "Fill"; $tb.Font = New-Object System.Drawing.Font("Consolas", 9)
|
|
$tb.Text = $content
|
|
$dlg.Controls.Add($tb)
|
|
$dlg.ShowDialog() | Out-Null
|
|
} else {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Keine policies.json gefunden unter:`n" + (Join-Path $ffDir "distribution"),
|
|
"Nicht gefunden", "OK", "Information")
|
|
}
|
|
})
|
|
$tabDeploy.Controls.Add($btnShowCurrent)
|
|
|
|
# ===========================================================
|
|
# TAB 2: Beliebte Add-ons (Benutzer-Store)
|
|
# ===========================================================
|
|
$tabPopular = New-Object System.Windows.Forms.TabPage
|
|
$tabPopular.Text = "Store - Einzelinstallation"
|
|
$tabs.Controls.Add($tabPopular)
|
|
|
|
$lblPopInfo = New-Object System.Windows.Forms.Label
|
|
$lblPopInfo.Text = "Add-on auswaehlen und per Firefox Store installieren (nur fuer aktuellen Benutzer)."
|
|
$lblPopInfo.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lblPopInfo.ForeColor = [System.Drawing.Color]::Gray
|
|
$lblPopInfo.Location = New-Object System.Drawing.Point(10, 10)
|
|
$lblPopInfo.AutoSize = $true
|
|
$tabPopular.Controls.Add($lblPopInfo)
|
|
|
|
$lvPopular = New-Object System.Windows.Forms.ListView
|
|
$lvPopular.Location = New-Object System.Drawing.Point(10, 35)
|
|
$lvPopular.Size = New-Object System.Drawing.Size(845, 390)
|
|
$lvPopular.View = [System.Windows.Forms.View]::Details
|
|
$lvPopular.FullRowSelect = $true
|
|
$lvPopular.GridLines = $true
|
|
$lvPopular.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lvPopular.Columns.Add("Add-on Name", 200) | Out-Null
|
|
$lvPopular.Columns.Add("Beschreibung", 450) | Out-Null
|
|
$lvPopular.Columns.Add("Quelle", 160) | Out-Null
|
|
foreach ($addon in $AllAddons) {
|
|
$item = New-Object System.Windows.Forms.ListViewItem($addon.Name)
|
|
$item.SubItems.Add($addon.Beschreibung) | Out-Null
|
|
$item.SubItems.Add("Mozilla Store") | Out-Null
|
|
$item.Tag = $addon
|
|
$lvPopular.Items.Add($item) | Out-Null
|
|
}
|
|
$tabPopular.Controls.Add($lvPopular)
|
|
|
|
$btnInstallPopular = New-Object System.Windows.Forms.Button
|
|
$btnInstallPopular.Text = "Im Firefox Store oeffnen"
|
|
$btnInstallPopular.Size = New-Object System.Drawing.Size(220, 35)
|
|
$btnInstallPopular.Location = New-Object System.Drawing.Point(10, 440)
|
|
$btnInstallPopular.BackColor = [System.Drawing.Color]::FromArgb(255, 100, 20)
|
|
$btnInstallPopular.ForeColor = [System.Drawing.Color]::White
|
|
$btnInstallPopular.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
|
|
$btnInstallPopular.FlatStyle = "Flat"
|
|
$btnInstallPopular.FlatAppearance.BorderSize = 0
|
|
$btnInstallPopular.Add_Click({
|
|
if ($lvPopular.SelectedItems.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show("Bitte zuerst ein Add-on auswaehlen.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$addon = $lvPopular.SelectedItems[0].Tag
|
|
$url = if ($addon.StoreUrl) { $addon.StoreUrl } else { $addon.Url }
|
|
Open-AddonPage -Url $url
|
|
})
|
|
$tabPopular.Controls.Add($btnInstallPopular)
|
|
|
|
$btnOpenAMO = New-Object System.Windows.Forms.Button
|
|
$btnOpenAMO.Text = "Alle Add-ons durchsuchen"
|
|
$btnOpenAMO.Size = New-Object System.Drawing.Size(220, 35)
|
|
$btnOpenAMO.Location = New-Object System.Drawing.Point(240, 440)
|
|
$btnOpenAMO.BackColor = [System.Drawing.Color]::FromArgb(70, 130, 180)
|
|
$btnOpenAMO.ForeColor = [System.Drawing.Color]::White
|
|
$btnOpenAMO.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
|
$btnOpenAMO.FlatStyle = "Flat"
|
|
$btnOpenAMO.FlatAppearance.BorderSize = 0
|
|
$btnOpenAMO.Add_Click({ Open-AddonPage -Url "https://addons.mozilla.org/de/firefox/" })
|
|
$tabPopular.Controls.Add($btnOpenAMO)
|
|
|
|
# ===========================================================
|
|
# TAB 3: XPI direkt installieren
|
|
# ===========================================================
|
|
$tabXpi = New-Object System.Windows.Forms.TabPage
|
|
$tabXpi.Text = "XPI-Datei installieren"
|
|
$tabs.Controls.Add($tabXpi)
|
|
|
|
$lblXpiInfo = New-Object System.Windows.Forms.Label
|
|
$lblXpiInfo.Text = "Installiere ein Add-on direkt aus einer lokalen .xpi-Datei in ein Firefox-Profil."
|
|
$lblXpiInfo.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lblXpiInfo.ForeColor = [System.Drawing.Color]::Gray
|
|
$lblXpiInfo.Location = New-Object System.Drawing.Point(10, 10)
|
|
$lblXpiInfo.AutoSize = $true
|
|
$tabXpi.Controls.Add($lblXpiInfo)
|
|
|
|
$lblXpiPath = New-Object System.Windows.Forms.Label
|
|
$lblXpiPath.Text = "XPI-Datei:"; $lblXpiPath.Location = New-Object System.Drawing.Point(10, 50)
|
|
$lblXpiPath.AutoSize = $true; $tabXpi.Controls.Add($lblXpiPath)
|
|
|
|
$txtXpiPath = New-Object System.Windows.Forms.TextBox
|
|
$txtXpiPath.Location = New-Object System.Drawing.Point(10, 70)
|
|
$txtXpiPath.Size = New-Object System.Drawing.Size(650, 25)
|
|
$txtXpiPath.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabXpi.Controls.Add($txtXpiPath)
|
|
|
|
$btnBrowseXpi = New-Object System.Windows.Forms.Button
|
|
$btnBrowseXpi.Text = "Durchsuchen..."; $btnBrowseXpi.Location = New-Object System.Drawing.Point(670, 68)
|
|
$btnBrowseXpi.Size = New-Object System.Drawing.Size(160, 28)
|
|
$btnBrowseXpi.Add_Click({
|
|
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
|
$ofd.Filter = "Firefox Add-on (*.xpi)|*.xpi"
|
|
if ($ofd.ShowDialog() -eq "OK") { $txtXpiPath.Text = $ofd.FileName }
|
|
})
|
|
$tabXpi.Controls.Add($btnBrowseXpi)
|
|
|
|
$lblProfile = New-Object System.Windows.Forms.Label
|
|
$lblProfile.Text = "Firefox-Profil:"; $lblProfile.Location = New-Object System.Drawing.Point(10, 110)
|
|
$lblProfile.AutoSize = $true; $tabXpi.Controls.Add($lblProfile)
|
|
|
|
$txtProfile = New-Object System.Windows.Forms.TextBox
|
|
$txtProfile.Location = New-Object System.Drawing.Point(10, 130)
|
|
$txtProfile.Size = New-Object System.Drawing.Size(650, 25)
|
|
$txtProfile.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$dp = Find-FirefoxProfile
|
|
if ($dp) { $txtProfile.Text = $dp }
|
|
$tabXpi.Controls.Add($txtProfile)
|
|
|
|
$btnBrowseProfile = New-Object System.Windows.Forms.Button
|
|
$btnBrowseProfile.Text = "Profil waehlen..."; $btnBrowseProfile.Location = New-Object System.Drawing.Point(670, 128)
|
|
$btnBrowseProfile.Size = New-Object System.Drawing.Size(160, 28)
|
|
$btnBrowseProfile.Add_Click({
|
|
$fbd = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
if ($fbd.ShowDialog() -eq "OK") { $txtProfile.Text = $fbd.SelectedPath }
|
|
})
|
|
$tabXpi.Controls.Add($btnBrowseProfile)
|
|
|
|
$btnInstallXpi = New-Object System.Windows.Forms.Button
|
|
$btnInstallXpi.Text = "Add-on installieren"
|
|
$btnInstallXpi.Size = New-Object System.Drawing.Size(200, 40)
|
|
$btnInstallXpi.Location = New-Object System.Drawing.Point(10, 180)
|
|
$btnInstallXpi.BackColor = [System.Drawing.Color]::FromArgb(255, 100, 20)
|
|
$btnInstallXpi.ForeColor = [System.Drawing.Color]::White
|
|
$btnInstallXpi.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
|
|
$btnInstallXpi.FlatStyle = "Flat"; $btnInstallXpi.FlatAppearance.BorderSize = 0
|
|
$btnInstallXpi.Add_Click({
|
|
if (-not (Test-Path $txtXpiPath.Text)) {
|
|
[System.Windows.Forms.MessageBox]::Show("XPI-Datei nicht gefunden.", "Fehler", "OK", "Error"); return
|
|
}
|
|
if (-not (Test-Path $txtProfile.Text)) {
|
|
[System.Windows.Forms.MessageBox]::Show("Profilordner nicht gefunden.", "Fehler", "OK", "Error"); return
|
|
}
|
|
$ff = Get-Process -Name "firefox" -ErrorAction SilentlyContinue
|
|
if ($ff) {
|
|
$ans = [System.Windows.Forms.MessageBox]::Show(
|
|
"Firefox ist geoeffnet. Jetzt beenden?", "Firefox beenden", "YesNo", "Warning")
|
|
if ($ans -eq "Yes") { $ff | Stop-Process -Force; Start-Sleep 2 } else { return }
|
|
}
|
|
try {
|
|
$id = Install-AddonFromFile -ProfilePath $txtProfile.Text -XpiPath $txtXpiPath.Text
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Installiert! ID: $id`nFirefox neu starten.", "Erfolg", "OK", "Information")
|
|
$txtXpiPath.Text = ""
|
|
} catch {
|
|
[System.Windows.Forms.MessageBox]::Show("Fehler: $_", "Fehler", "OK", "Error")
|
|
}
|
|
})
|
|
$tabXpi.Controls.Add($btnInstallXpi)
|
|
|
|
# ===========================================================
|
|
# TAB 4: Installierte Add-ons
|
|
# ===========================================================
|
|
$tabInstalled = New-Object System.Windows.Forms.TabPage
|
|
$tabInstalled.Text = "Installierte Add-ons"
|
|
$tabs.Controls.Add($tabInstalled)
|
|
|
|
$lvInstalled = New-Object System.Windows.Forms.ListView
|
|
$lvInstalled.Location = New-Object System.Drawing.Point(10, 10)
|
|
$lvInstalled.Size = New-Object System.Drawing.Size(845, 420)
|
|
$lvInstalled.View = [System.Windows.Forms.View]::Details
|
|
$lvInstalled.FullRowSelect = $true; $lvInstalled.GridLines = $true
|
|
$lvInstalled.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lvInstalled.Columns.Add("Name", 220) | Out-Null
|
|
$lvInstalled.Columns.Add("Version", 80) | Out-Null
|
|
$lvInstalled.Columns.Add("Aktiv", 60) | Out-Null
|
|
$lvInstalled.Columns.Add("ID", 460) | Out-Null
|
|
$tabInstalled.Controls.Add($lvInstalled)
|
|
|
|
$btnRefresh = New-Object System.Windows.Forms.Button
|
|
$btnRefresh.Text = "Aktualisieren"; $btnRefresh.Size = New-Object System.Drawing.Size(160, 35)
|
|
$btnRefresh.Location = New-Object System.Drawing.Point(10, 445)
|
|
$btnRefresh.BackColor = [System.Drawing.Color]::FromArgb(70, 130, 180)
|
|
$btnRefresh.ForeColor = [System.Drawing.Color]::White
|
|
$btnRefresh.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
|
$btnRefresh.FlatStyle = "Flat"; $btnRefresh.FlatAppearance.BorderSize = 0
|
|
$btnRefresh.Add_Click({
|
|
$lvInstalled.Items.Clear()
|
|
$profilePath = Find-FirefoxProfile
|
|
if (-not $profilePath) {
|
|
[System.Windows.Forms.MessageBox]::Show("Kein Firefox-Profil gefunden.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$addons = Get-InstalledAddons -ProfilePath $profilePath
|
|
foreach ($a in $addons) {
|
|
$name = if ($a.defaultLocale.name) { $a.defaultLocale.name } else { $a.id }
|
|
$item = New-Object System.Windows.Forms.ListViewItem($name)
|
|
$item.SubItems.Add($a.version) | Out-Null
|
|
$item.SubItems.Add($(if ($a.active) { "Ja" } else { "Nein" })) | Out-Null
|
|
$item.SubItems.Add($a.id) | Out-Null
|
|
if (-not $a.active) { $item.ForeColor = [System.Drawing.Color]::Gray }
|
|
$lvInstalled.Items.Add($item) | Out-Null
|
|
}
|
|
if ($lvInstalled.Items.Count -eq 0) {
|
|
$lvInstalled.Items.Add(
|
|
(New-Object System.Windows.Forms.ListViewItem("Keine Add-ons gefunden."))) | Out-Null
|
|
}
|
|
})
|
|
$tabInstalled.Controls.Add($btnRefresh)
|
|
|
|
# ===========================================================
|
|
# TAB 5: Diagnose & Intune
|
|
# ===========================================================
|
|
$tabDiag = New-Object System.Windows.Forms.TabPage
|
|
$tabDiag.Text = "Diagnose / Intune"
|
|
$tabs.Controls.Add($tabDiag)
|
|
|
|
# Intune-Warnung
|
|
$pnlIntune = New-Object System.Windows.Forms.Panel
|
|
$pnlIntune.Location = New-Object System.Drawing.Point(10, 8)
|
|
$pnlIntune.Size = New-Object System.Drawing.Size(845, 28)
|
|
$pnlIntune.BorderStyle = "FixedSingle"
|
|
$tabDiag.Controls.Add($pnlIntune)
|
|
$lblIntuneStatus = New-Object System.Windows.Forms.Label
|
|
$lblIntuneStatus.Font = New-Object System.Drawing.Font("Segoe UI", 8, [System.Drawing.FontStyle]::Bold)
|
|
$lblIntuneStatus.Location = New-Object System.Drawing.Point(6, 6)
|
|
$lblIntuneStatus.Size = New-Object System.Drawing.Size(830, 18)
|
|
if (Test-IntuneManaged) {
|
|
$pnlIntune.BackColor = [System.Drawing.Color]::FromArgb(255, 240, 200)
|
|
$lblIntuneStatus.Text = "INTUNE erkannt - Firefox wird via Intune verwaltet. policies.json wird ignoriert. Registry-Methode oder .reg-Export verwenden."
|
|
$lblIntuneStatus.ForeColor = [System.Drawing.Color]::DarkOrange
|
|
} else {
|
|
$pnlIntune.BackColor = [System.Drawing.Color]::FromArgb(220, 255, 220)
|
|
$lblIntuneStatus.Text = "Kein Intune-Management erkannt. policies.json und Registry-Methode sollten funktionieren."
|
|
$lblIntuneStatus.ForeColor = [System.Drawing.Color]::DarkGreen
|
|
}
|
|
$pnlIntune.Controls.Add($lblIntuneStatus)
|
|
|
|
# Policy-Konflikt-Checker
|
|
$grpCheck = New-Object System.Windows.Forms.GroupBox
|
|
$grpCheck.Text = "Policy-Konflikt-Pruefung - moegliche Gruende warum Add-ons nicht installiert werden"
|
|
$grpCheck.Location = New-Object System.Drawing.Point(10, 44)
|
|
$grpCheck.Size = New-Object System.Drawing.Size(845, 220)
|
|
$grpCheck.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabDiag.Controls.Add($grpCheck)
|
|
|
|
$lvChecks = New-Object System.Windows.Forms.ListView
|
|
$lvChecks.Location = New-Object System.Drawing.Point(10, 18)
|
|
$lvChecks.Size = New-Object System.Drawing.Size(822, 192)
|
|
$lvChecks.View = [System.Windows.Forms.View]::Details
|
|
$lvChecks.FullRowSelect = $true
|
|
$lvChecks.GridLines = $true
|
|
$lvChecks.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$lvChecks.Columns.Add("Status", 55) | Out-Null
|
|
$lvChecks.Columns.Add("Policy / Einstellung", 240) | Out-Null
|
|
$lvChecks.Columns.Add("Aktueller Wert", 200) | Out-Null
|
|
$lvChecks.Columns.Add("Auswirkung / Loesung", 300) | Out-Null
|
|
$grpCheck.Controls.Add($lvChecks)
|
|
|
|
function Invoke-PolicyCheck {
|
|
$lvChecks.Items.Clear()
|
|
$base = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox"
|
|
|
|
# Hilfsfunktion: Eintrag hinzufuegen
|
|
function Add-CheckItem {
|
|
param([string]$Status, [string]$Policy, [string]$Value, [string]$Info, [string]$Color)
|
|
$item = New-Object System.Windows.Forms.ListViewItem($Status)
|
|
$item.SubItems.Add($Policy) | Out-Null
|
|
$item.SubItems.Add($Value) | Out-Null
|
|
$item.SubItems.Add($Info) | Out-Null
|
|
switch ($Color) {
|
|
"red" { $item.BackColor = [System.Drawing.Color]::FromArgb(255, 210, 210) }
|
|
"yellow" { $item.BackColor = [System.Drawing.Color]::FromArgb(255, 245, 200) }
|
|
"green" { $item.BackColor = [System.Drawing.Color]::FromArgb(210, 255, 210) }
|
|
}
|
|
$lvChecks.Items.Add($item) | Out-Null
|
|
}
|
|
|
|
# 1. BlockAboutAddons - sperrt about:addons komplett
|
|
$val = (Get-ItemProperty "$base" -Name "BlockAboutAddons" -ErrorAction SilentlyContinue).BlockAboutAddons
|
|
if ($val -eq 1) {
|
|
Add-CheckItem "FEHLER" "BlockAboutAddons" "1 (aktiv)" "Sperrt Add-on-Manager komplett. Auf 0 setzen oder entfernen." "red"
|
|
} else {
|
|
Add-CheckItem "OK" "BlockAboutAddons" "(nicht gesetzt)" "Kein Problem." "green"
|
|
}
|
|
|
|
# 2. InstallAddonsPermission - steuert wer Add-ons installieren darf
|
|
$allowKey = "$base\InstallAddonsPermission\Allow"
|
|
$blockKey = "$base\InstallAddonsPermission\Block"
|
|
$hasAllow = Test-Path $allowKey
|
|
$hasBlock = Test-Path $blockKey
|
|
if ($hasBlock) {
|
|
$blockVals = (Get-ItemProperty $blockKey -ErrorAction SilentlyContinue).PSObject.Properties |
|
|
Where-Object { $_.Name -notmatch '^PS' } | ForEach-Object { $_.Value }
|
|
if ($blockVals -contains "<all_urls>" -or $blockVals -contains "*") {
|
|
Add-CheckItem "FEHLER" "InstallAddonsPermission\Block" "<all_urls>" "Alle Installationen geblockt! Eintrag entfernen." "red"
|
|
} else {
|
|
Add-CheckItem "WARN" "InstallAddonsPermission\Block" ($blockVals -join ", ") "Bestimmte Quellen geblockt. Pruefen ob AMO/interne URL betroffen." "yellow"
|
|
}
|
|
} else {
|
|
Add-CheckItem "OK" "InstallAddonsPermission" "(keine Block-Regel)" "Kein Problem." "green"
|
|
}
|
|
|
|
# 3. ExtensionSettings - ist force_installed korrekt gesetzt?
|
|
$extKey = "$base\ExtensionSettings"
|
|
if (Test-Path $extKey) {
|
|
$subkeys = Get-ChildItem $extKey -ErrorAction SilentlyContinue
|
|
if ($subkeys) {
|
|
foreach ($sk in $subkeys) {
|
|
$mode = (Get-ItemProperty $sk.PSPath -Name "installation_mode" -ErrorAction SilentlyContinue).installation_mode
|
|
$url = (Get-ItemProperty $sk.PSPath -Name "install_url" -ErrorAction SilentlyContinue).install_url
|
|
if ($mode -eq "force_installed") {
|
|
if ($url) {
|
|
Add-CheckItem "OK" ("ExtensionSettings\" + $sk.PSChildName) "force_installed" "install_url: $url" "green"
|
|
} else {
|
|
Add-CheckItem "WARN" ("ExtensionSettings\" + $sk.PSChildName) "force_installed" "Keine install_url - Firefox muss AMO erreichen koennen." "yellow"
|
|
}
|
|
} elseif ($mode -eq "blocked") {
|
|
Add-CheckItem "FEHLER" ("ExtensionSettings\" + $sk.PSChildName) "blocked" "Dieses Add-on ist explizit geblockt!" "red"
|
|
} elseif ($mode) {
|
|
Add-CheckItem "WARN" ("ExtensionSettings\" + $sk.PSChildName) $mode "Modus ist nicht force_installed." "yellow"
|
|
}
|
|
}
|
|
# Wildcard-Eintrag pruefen (blockiert alle nicht explizit erlaubten)
|
|
$wildcard = Get-ItemProperty (Join-Path $extKey "*") -ErrorAction SilentlyContinue
|
|
if ($wildcard) {
|
|
$wMode = $wildcard.installation_mode
|
|
if ($wMode -eq "blocked") {
|
|
Add-CheckItem "FEHLER" 'ExtensionSettings\* (Wildcard)' "blocked" "Alle Add-ons ausser explizit force_installed sind geblockt. Kann force_installed verhindern wenn Reihenfolge falsch." "red"
|
|
} elseif ($wMode) {
|
|
Add-CheckItem "WARN" 'ExtensionSettings\* (Wildcard)' $wMode "Wildcard-Regel aktiv - pruefen ob sie force_installed ueberschreibt." "yellow"
|
|
}
|
|
}
|
|
} else {
|
|
Add-CheckItem "WARN" "ExtensionSettings" "(leer)" "Kein Add-on als force_installed eingetragen." "yellow"
|
|
}
|
|
} else {
|
|
Add-CheckItem "WARN" "ExtensionSettings" "(nicht vorhanden)" "Noch keine Extension-Policy gesetzt." "yellow"
|
|
}
|
|
|
|
# 4. DisabledCiphers / WebsiteFilter die AMO blockieren koennten
|
|
$proxyKey = Get-ItemProperty "$base\Proxy" -ErrorAction SilentlyContinue
|
|
if ($proxyKey) {
|
|
Add-CheckItem "INFO" "Proxy-Policy aktiv" ($proxyKey | Out-String).Trim().Split("`n")[0] "Proxy kann AMO-Download blockieren - interne URL empfohlen." "yellow"
|
|
}
|
|
|
|
# 5. AppAutoUpdate - verhindert nicht Installation, aber Info
|
|
$upd = (Get-ItemProperty "$base" -Name "DisableAppUpdate" -ErrorAction SilentlyContinue).DisableAppUpdate
|
|
if ($upd -eq 1) {
|
|
Add-CheckItem "INFO" "DisableAppUpdate" "1 (aktiv)" "Kein Problem fuer Add-ons, aber Firefox-Updates deaktiviert." "yellow"
|
|
}
|
|
|
|
# 6. ExtensionUpdate deaktiviert?
|
|
$extUpd = (Get-ItemProperty "$base" -Name "ExtensionUpdate" -ErrorAction SilentlyContinue).ExtensionUpdate
|
|
if ($extUpd -eq 0) {
|
|
Add-CheckItem "WARN" "ExtensionUpdate" "0 (deaktiviert)" "Add-on-Updates deaktiviert. Erstinstallation via force_installed funktioniert trotzdem." "yellow"
|
|
}
|
|
|
|
if ($lvChecks.Items.Count -eq 0) {
|
|
Add-CheckItem "INFO" "(keine Policies gefunden)" "" "HKLM\SOFTWARE\Policies\Mozilla\Firefox existiert nicht." "yellow"
|
|
}
|
|
}
|
|
|
|
$btnRunCheck = New-Object System.Windows.Forms.Button
|
|
$btnRunCheck.Text = "Policy-Check ausfuehren"
|
|
$btnRunCheck.Size = New-Object System.Drawing.Size(200, 30)
|
|
$btnRunCheck.Location = New-Object System.Drawing.Point(10, 272)
|
|
$btnRunCheck.BackColor = [System.Drawing.Color]::FromArgb(180, 0, 0)
|
|
$btnRunCheck.ForeColor = [System.Drawing.Color]::White
|
|
$btnRunCheck.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnRunCheck.FlatStyle = "Flat"
|
|
$btnRunCheck.FlatAppearance.BorderSize = 0
|
|
$btnRunCheck.Add_Click({ Invoke-PolicyCheck })
|
|
$tabDiag.Controls.Add($btnRunCheck)
|
|
|
|
$btnFixSelected = New-Object System.Windows.Forms.Button
|
|
$btnFixSelected.Text = "Markierten FEHLER beheben"
|
|
$btnFixSelected.Size = New-Object System.Drawing.Size(210, 30)
|
|
$btnFixSelected.Location = New-Object System.Drawing.Point(220, 272)
|
|
$btnFixSelected.BackColor = [System.Drawing.Color]::FromArgb(140, 0, 0)
|
|
$btnFixSelected.ForeColor = [System.Drawing.Color]::White
|
|
$btnFixSelected.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnFixSelected.FlatStyle = "Flat"
|
|
$btnFixSelected.FlatAppearance.BorderSize = 0
|
|
$btnFixSelected.Add_Click({
|
|
if ($lvChecks.SelectedItems.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Bitte zuerst einen FEHLER-Eintrag in der Liste auswaehlen.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
if (-not (Test-IsAdmin)) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Administratorrechte erforderlich.", "Kein Admin", "OK", "Warning"); return
|
|
}
|
|
$sel = $lvChecks.SelectedItems[0]
|
|
$status = $sel.SubItems[0].Text
|
|
$policy = $sel.SubItems[1].Text
|
|
$curVal = $sel.SubItems[2].Text
|
|
|
|
$extBase = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings"
|
|
|
|
# Fall 1: Explizit geblocktes Add-on (z.B. uBlock0@raymondhill.net -> blocked)
|
|
if ($status -eq "FEHLER" -and $policy -match "^ExtensionSettings\\(.+)$" -and
|
|
$Matches[1] -ne "*" -and $curVal -eq "blocked") {
|
|
$addonId = $Matches[1]
|
|
$addonKey = Join-Path $extBase $addonId
|
|
$ans = [System.Windows.Forms.MessageBox]::Show(
|
|
"Add-on '$addonId' ist explizit geblockt.`n`n" +
|
|
"Was soll gemacht werden?`n" +
|
|
"[Ja] Auf 'force_installed' aendern (Add-on wird zwingend installiert)`n" +
|
|
"[Nein] Block-Eintrag komplett loeschen (Add-on wird nicht mehr explizit geblockt)",
|
|
"Blocked-Eintrag beheben", "YesNo", "Question")
|
|
if ($ans -eq "Yes") {
|
|
if (-not (Test-Path $addonKey)) { New-Item -Path $addonKey -Force | Out-Null }
|
|
Set-ItemProperty -Path $addonKey -Name "installation_mode" -Value "force_installed" -Type String
|
|
# install_url setzen falls bekannt
|
|
$known = $AllAddons | Where-Object { $_.Id -eq $addonId }
|
|
if ($known -and $known.Url) {
|
|
Set-ItemProperty -Path $addonKey -Name "install_url" -Value $known.Url -Type String
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Geaendert: '$addonId'`nModus: force_installed`nURL: $($known.Url)`n`nFirefox neu starten.",
|
|
"Behoben", "OK", "Information")
|
|
} else {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Geaendert: '$addonId' -> force_installed`nHinweis: install_url nicht bekannt - bitte manuell eintragen oder AMO muss erreichbar sein.`n`nFirefox neu starten.",
|
|
"Behoben", "OK", "Information")
|
|
}
|
|
} else {
|
|
if (Test-Path $addonKey) {
|
|
Remove-Item -Path $addonKey -Recurse -Force
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Block-Eintrag fuer '$addonId' geloescht.`n`nFirefox neu starten.",
|
|
"Geloescht", "OK", "Information")
|
|
}
|
|
}
|
|
}
|
|
# Fall 2: Wildcard geblockt
|
|
elseif ($status -eq "FEHLER" -and $policy -match "\*") {
|
|
$wildcardKey = Join-Path $extBase "*"
|
|
$ans = [System.Windows.Forms.MessageBox]::Show(
|
|
"Wildcard (*) ist auf 'blocked' gesetzt.`n`n" +
|
|
"[Ja] Wildcard-Eintrag loeschen (empfohlen wenn Intune force_installed nicht respektiert)`n" +
|
|
"[Nein] Wildcard auf 'allowed' aendern (alle Add-ons erlaubt, weniger sicher)",
|
|
"Wildcard beheben", "YesNo", "Question")
|
|
if ($ans -eq "Yes") {
|
|
if (Test-Path $wildcardKey) { Remove-Item -Path $wildcardKey -Recurse -Force }
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Wildcard-Eintrag geloescht.`nFirefox neu starten.",
|
|
"Geloescht", "OK", "Information")
|
|
} else {
|
|
if (-not (Test-Path $wildcardKey)) { New-Item -Path $wildcardKey -Force | Out-Null }
|
|
Set-ItemProperty -Path $wildcardKey -Name "installation_mode" -Value "allowed" -Type String
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Wildcard auf 'allowed' gesetzt.`nFirefox neu starten.",
|
|
"Geaendert", "OK", "Information")
|
|
}
|
|
}
|
|
else {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Fuer diesen Eintrag ist keine automatische Korrektur verfuegbar.`nBitte manuell pruefen.",
|
|
"Hinweis", "OK", "Information")
|
|
}
|
|
Invoke-PolicyCheck
|
|
})
|
|
$tabDiag.Controls.Add($btnFixSelected)
|
|
|
|
$btnFixWildcard = New-Object System.Windows.Forms.Button
|
|
$btnFixWildcard.Text = "Alle FEHLERs beheben"
|
|
$btnFixWildcard.Size = New-Object System.Drawing.Size(185, 30)
|
|
$btnFixWildcard.Location = New-Object System.Drawing.Point(440, 272)
|
|
$btnFixWildcard.BackColor = [System.Drawing.Color]::FromArgb(180, 80, 0)
|
|
$btnFixWildcard.ForeColor = [System.Drawing.Color]::White
|
|
$btnFixWildcard.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnFixWildcard.FlatStyle = "Flat"
|
|
$btnFixWildcard.FlatAppearance.BorderSize = 0
|
|
$btnFixWildcard.Add_Click({
|
|
if (-not (Test-IsAdmin)) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Administratorrechte erforderlich.", "Kein Admin", "OK", "Warning"); return
|
|
}
|
|
$errors = $lvChecks.Items | Where-Object { $_.SubItems[0].Text -eq "FEHLER" }
|
|
if ($errors.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show("Keine FEHLER-Eintraege gefunden.", "Hinweis", "OK", "Information")
|
|
return
|
|
}
|
|
$report = @()
|
|
$extBase = "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\ExtensionSettings"
|
|
foreach ($err in $errors) {
|
|
$policy = $err.SubItems[1].Text
|
|
# Explizit geblocktes Add-on -> auf force_installed setzen
|
|
if ($policy -match "^ExtensionSettings\\(.+)$" -and $Matches[1] -ne "*" -and
|
|
$err.SubItems[2].Text -eq "blocked") {
|
|
$addonId = $Matches[1]
|
|
$addonKey = Join-Path $extBase $addonId
|
|
if (-not (Test-Path $addonKey)) { New-Item -Path $addonKey -Force | Out-Null }
|
|
Set-ItemProperty -Path $addonKey -Name "installation_mode" -Value "force_installed" -Type String
|
|
$known = $AllAddons | Where-Object { $_.Id -eq $addonId }
|
|
if ($known -and $known.Url) {
|
|
Set-ItemProperty -Path $addonKey -Name "install_url" -Value $known.Url -Type String
|
|
}
|
|
$report += "force_installed gesetzt: $addonId"
|
|
}
|
|
# Wildcard -> loeschen
|
|
elseif ($policy -match "\*") {
|
|
$wildcardKey = Join-Path $extBase "*"
|
|
if (Test-Path $wildcardKey) { Remove-Item -Path $wildcardKey -Recurse -Force }
|
|
$report += "Wildcard (*) entfernt"
|
|
}
|
|
}
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Automatische Korrektur abgeschlossen:`n`n" + ($report -join "`n") +
|
|
"`n`nFirefox neu starten.",
|
|
"Alle Fehler behoben", "OK", "Information")
|
|
Invoke-PolicyCheck
|
|
})
|
|
$tabDiag.Controls.Add($btnFixWildcard)
|
|
|
|
# Aktive Policies (Rohansicht)
|
|
$grpPolicies = New-Object System.Windows.Forms.GroupBox
|
|
$grpPolicies.Text = "Registry-Rohansicht (HKLM\SOFTWARE\Policies\Mozilla\Firefox)"
|
|
$grpPolicies.Location = New-Object System.Drawing.Point(10, 310)
|
|
$grpPolicies.Size = New-Object System.Drawing.Size(845, 120)
|
|
$grpPolicies.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$tabDiag.Controls.Add($grpPolicies)
|
|
|
|
$txtPolicies = New-Object System.Windows.Forms.TextBox
|
|
$txtPolicies.Multiline = $true
|
|
$txtPolicies.ScrollBars = "Both"
|
|
$txtPolicies.ReadOnly = $true
|
|
$txtPolicies.Location = New-Object System.Drawing.Point(10, 18)
|
|
$txtPolicies.Size = New-Object System.Drawing.Size(822, 92)
|
|
$txtPolicies.Font = New-Object System.Drawing.Font("Consolas", 8)
|
|
$txtPolicies.WordWrap = $false
|
|
$grpPolicies.Controls.Add($txtPolicies)
|
|
|
|
# Buttons
|
|
$btnOpenAboutPolicies = New-Object System.Windows.Forms.Button
|
|
$btnOpenAboutPolicies.Text = "about:policies oeffnen"
|
|
$btnOpenAboutPolicies.Size = New-Object System.Drawing.Size(190, 32)
|
|
$btnOpenAboutPolicies.Location = New-Object System.Drawing.Point(10, 438)
|
|
$btnOpenAboutPolicies.BackColor = [System.Drawing.Color]::FromArgb(255, 100, 20)
|
|
$btnOpenAboutPolicies.ForeColor = [System.Drawing.Color]::White
|
|
$btnOpenAboutPolicies.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnOpenAboutPolicies.FlatStyle = "Flat"; $btnOpenAboutPolicies.FlatAppearance.BorderSize = 0
|
|
$btnOpenAboutPolicies.Add_Click({
|
|
try { Start-Process "firefox" "about:policies" }
|
|
catch { [System.Windows.Forms.MessageBox]::Show("Fehler: $_", "Fehler", "OK", "Error") }
|
|
})
|
|
$tabDiag.Controls.Add($btnOpenAboutPolicies)
|
|
|
|
$btnRefreshPolicies = New-Object System.Windows.Forms.Button
|
|
$btnRefreshPolicies.Text = "Rohansicht laden"
|
|
$btnRefreshPolicies.Size = New-Object System.Drawing.Size(160, 32)
|
|
$btnRefreshPolicies.Location = New-Object System.Drawing.Point(210, 438)
|
|
$btnRefreshPolicies.BackColor = [System.Drawing.Color]::FromArgb(70, 130, 180)
|
|
$btnRefreshPolicies.ForeColor = [System.Drawing.Color]::White
|
|
$btnRefreshPolicies.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
$btnRefreshPolicies.FlatStyle = "Flat"; $btnRefreshPolicies.FlatAppearance.BorderSize = 0
|
|
$btnRefreshPolicies.Add_Click({
|
|
$lines = Get-ActiveFirefoxPolicies
|
|
$txtPolicies.Text = if ($lines.Count -eq 0) {
|
|
"(Keine Registry-Policies gefunden)"
|
|
} else { $lines -join "`r`n" }
|
|
})
|
|
$tabDiag.Controls.Add($btnRefreshPolicies)
|
|
|
|
$btnExportReg = New-Object System.Windows.Forms.Button
|
|
$btnExportReg.Text = ".reg fuer Intune exportieren"
|
|
$btnExportReg.Size = New-Object System.Drawing.Size(210, 32)
|
|
$btnExportReg.Location = New-Object System.Drawing.Point(380, 438)
|
|
$btnExportReg.BackColor = [System.Drawing.Color]::FromArgb(0, 120, 80)
|
|
$btnExportReg.ForeColor = [System.Drawing.Color]::White
|
|
$btnExportReg.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnExportReg.FlatStyle = "Flat"; $btnExportReg.FlatAppearance.BorderSize = 0
|
|
$btnExportReg.Add_Click({
|
|
$selected = $lvDeploy.Items | Where-Object { $_.Checked }
|
|
if ($selected.Count -eq 0) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Bitte zuerst im Tab 'Maschinenweite Bereitstellung' Add-ons auswaehlen.",
|
|
"Hinweis", "OK", "Information"); return
|
|
}
|
|
$sfd = New-Object System.Windows.Forms.SaveFileDialog
|
|
$sfd.Filter = "Registry-Datei (*.reg)|*.reg"
|
|
$sfd.FileName = "Firefox-Addons-Intune.reg"
|
|
if ($sfd.ShowDialog() -ne "OK") { return }
|
|
$addonsToExport = $selected | ForEach-Object {
|
|
$clone = [PSCustomObject]@{ Name=$_.Tag.Name; Id=$_.Tag.Id; Url=$_.Tag.Url; Beschreibung=$_.Tag.Beschreibung }
|
|
$internalUrl = $_.SubItems[2].Text.Trim()
|
|
if ($internalUrl -ne "" -and $internalUrl.StartsWith("http")) { $clone.Url = $internalUrl }
|
|
$clone
|
|
}
|
|
Export-RegFile -OutputPath $sfd.FileName -Addons $addonsToExport
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Exportiert: $($sfd.FileName)`n`nIntune OMA-URI:`n./Device/Vendor/MSFT/Policy/Config/Firefox~Policy~mozilla_firefox~Extensions/ExtensionSettings`n`nAlternativ: .reg via Intune PowerShell-Skript importieren:`n reg import `"Firefox-Addons-Intune.reg`"",
|
|
"Export erfolgreich", "OK", "Information")
|
|
})
|
|
$tabDiag.Controls.Add($btnExportReg)
|
|
|
|
$btnImportReg = New-Object System.Windows.Forms.Button
|
|
$btnImportReg.Text = "REG-Datei einlesen & anwenden"
|
|
$btnImportReg.Size = New-Object System.Drawing.Size(240, 32)
|
|
$btnImportReg.Location = New-Object System.Drawing.Point(600, 438)
|
|
$btnImportReg.BackColor = [System.Drawing.Color]::FromArgb(60, 90, 160)
|
|
$btnImportReg.ForeColor = [System.Drawing.Color]::White
|
|
$btnImportReg.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
|
|
$btnImportReg.FlatStyle = "Flat"
|
|
$btnImportReg.FlatAppearance.BorderSize = 0
|
|
$btnImportReg.Add_Click({
|
|
if (-not (Test-IsAdmin)) {
|
|
[System.Windows.Forms.MessageBox]::Show(
|
|
"Administratorrechte erforderlich.", "Kein Admin", "OK", "Warning"); return
|
|
}
|
|
|
|
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
|
$ofd.Filter = "Registry-Datei (*.reg)|*.reg"
|
|
$ofd.Title = "REG-Datei fuer Intune-Policy auswaehlen"
|
|
if ($ofd.ShowDialog() -ne "OK") { return }
|
|
|
|
# REG-Datei parsen
|
|
$lines = Get-Content $ofd.FileName -Encoding Unicode -ErrorAction SilentlyContinue
|
|
if (-not $lines) {
|
|
$lines = Get-Content $ofd.FileName -Encoding UTF8 -ErrorAction SilentlyContinue
|
|
}
|
|
if (-not $lines) {
|
|
[System.Windows.Forms.MessageBox]::Show("Datei konnte nicht gelesen werden.", "Fehler", "OK", "Error")
|
|
return
|
|
}
|
|
|
|
$currentKey = $null
|
|
$applied = @()
|
|
$skipped = @()
|
|
$errors = @()
|
|
|
|
foreach ($line in $lines) {
|
|
$line = $line.Trim()
|
|
if ($line -eq "" -or $line.StartsWith(";")) { continue }
|
|
if ($line.StartsWith("Windows Registry Editor")) { continue }
|
|
|
|
# Schluessel-Zeile: [HKEY_LOCAL_MACHINE\...]
|
|
if ($line -match '^\[(.+)\]$') {
|
|
$rawKey = $Matches[1]
|
|
# Nur Firefox-Policy-Keys erlauben
|
|
if ($rawKey -match 'SOFTWARE\\Policies\\Mozilla\\Firefox') {
|
|
# HKEY_LOCAL_MACHINE -> HKLM:
|
|
$psKey = $rawKey `
|
|
-replace '^HKEY_LOCAL_MACHINE', 'HKLM:' `
|
|
-replace '^HKEY_CURRENT_USER', 'HKCU:'
|
|
$currentKey = $psKey
|
|
} else {
|
|
$currentKey = $null
|
|
$skipped += "Uebersprungen (nicht Firefox-Policy): $rawKey"
|
|
}
|
|
continue
|
|
}
|
|
|
|
# Wert-Zeile nur verarbeiten wenn Key erlaubt
|
|
if (-not $currentKey) { continue }
|
|
|
|
# Wert parsen: "Name"="Wert" oder "Name"=dword:00000001
|
|
if ($line -match '^"(.+)"=(dword|hex|qword):(.+)$') {
|
|
$name = $Matches[1]
|
|
$type = $Matches[2]
|
|
$value = $Matches[3]
|
|
try {
|
|
if (-not (Test-Path $currentKey)) { New-Item -Path $currentKey -Force | Out-Null }
|
|
switch ($type) {
|
|
"dword" {
|
|
$int = [Convert]::ToInt32($value, 16)
|
|
Set-ItemProperty -Path $currentKey -Name $name -Value $int -Type DWord
|
|
}
|
|
default {
|
|
Set-ItemProperty -Path $currentKey -Name $name -Value $value -Type String
|
|
}
|
|
}
|
|
$applied += "$currentKey -> $name = [$type] $value"
|
|
} catch {
|
|
$errors += "Fehler bei $currentKey -> $name : $_"
|
|
}
|
|
} elseif ($line -match '^"(.+)"="(.*)"$') {
|
|
$name = $Matches[1]
|
|
$value = $Matches[2] -replace '\\"', '"'
|
|
try {
|
|
if (-not (Test-Path $currentKey)) { New-Item -Path $currentKey -Force | Out-Null }
|
|
Set-ItemProperty -Path $currentKey -Name $name -Value $value -Type String
|
|
$applied += "$currentKey -> $name = $value"
|
|
} catch {
|
|
$errors += "Fehler bei $currentKey -> $name : $_"
|
|
}
|
|
} elseif ($line -match '^@="(.*)"$') {
|
|
# Standard-Wert
|
|
$value = $Matches[1]
|
|
try {
|
|
if (-not (Test-Path $currentKey)) { New-Item -Path $currentKey -Force | Out-Null }
|
|
Set-ItemProperty -Path $currentKey -Name "(Default)" -Value $value -Type String
|
|
$applied += "$currentKey -> (Default) = $value"
|
|
} catch {
|
|
$errors += "Fehler bei $currentKey -> Default : $_"
|
|
}
|
|
} elseif ($line -match '^"-(.+)"$') {
|
|
# Wert loeschen
|
|
$name = $Matches[1]
|
|
try {
|
|
Remove-ItemProperty -Path $currentKey -Name $name -ErrorAction SilentlyContinue
|
|
$applied += "Geloescht: $currentKey -> $name"
|
|
} catch {
|
|
$errors += "Loeschen fehlgeschlagen: $currentKey -> $name"
|
|
}
|
|
} elseif ($line -match '^\[-(.+)\]$') {
|
|
# Schluessel loeschen
|
|
$delKey = $Matches[1] -replace '^HKEY_LOCAL_MACHINE', 'HKLM:'
|
|
if (Test-Path $delKey) {
|
|
Remove-Item -Path $delKey -Recurse -Force -ErrorAction SilentlyContinue
|
|
$applied += "Schluessel geloescht: $delKey"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Ergebnisbericht
|
|
$dlg = New-Object System.Windows.Forms.Form
|
|
$dlg.Text = "Import-Ergebnis: " + [System.IO.Path]::GetFileName($ofd.FileName)
|
|
$dlg.Size = New-Object System.Drawing.Size(750, 500)
|
|
$dlg.StartPosition = "CenterParent"
|
|
|
|
$tbResult = New-Object System.Windows.Forms.TextBox
|
|
$tbResult.Multiline = $true; $tbResult.ScrollBars = "Both"
|
|
$tbResult.ReadOnly = $true; $tbResult.Dock = "Fill"
|
|
$tbResult.Font = New-Object System.Drawing.Font("Consolas", 8)
|
|
$tbResult.WordWrap = $false
|
|
|
|
$summary = ""
|
|
if ($applied.Count -gt 0) {
|
|
$summary += "=== ANGEWENDET ($($applied.Count)) ===`r`n"
|
|
$summary += ($applied -join "`r`n") + "`r`n`r`n"
|
|
}
|
|
if ($skipped.Count -gt 0) {
|
|
$summary += "=== UEBERSPRUNGEN ($($skipped.Count)) ===`r`n"
|
|
$summary += ($skipped -join "`r`n") + "`r`n`r`n"
|
|
}
|
|
if ($errors.Count -gt 0) {
|
|
$summary += "=== FEHLER ($($errors.Count)) ===`r`n"
|
|
$summary += ($errors -join "`r`n") + "`r`n`r`n"
|
|
}
|
|
$summary += "`r`nFirefox neu starten damit die Aenderungen wirksam werden."
|
|
$tbResult.Text = $summary
|
|
|
|
$dlg.Controls.Add($tbResult)
|
|
$dlg.ShowDialog() | Out-Null
|
|
|
|
Invoke-PolicyCheck
|
|
$btnRefreshPolicies.PerformClick()
|
|
})
|
|
$tabDiag.Controls.Add($btnImportReg)
|
|
|
|
$lblOmaUri = New-Object System.Windows.Forms.Label
|
|
$lblOmaUri.Text = "OMA-URI: ./Device/Vendor/MSFT/Policy/Config/Firefox~Policy~mozilla_firefox~Extensions/ExtensionSettings"
|
|
$lblOmaUri.Font = New-Object System.Drawing.Font("Consolas", 7)
|
|
$lblOmaUri.ForeColor = [System.Drawing.Color]::DarkBlue
|
|
$lblOmaUri.Location = New-Object System.Drawing.Point(10, 478)
|
|
$lblOmaUri.Size = New-Object System.Drawing.Size(845, 14)
|
|
$tabDiag.Controls.Add($lblOmaUri)
|
|
|
|
# Statusleiste
|
|
$statusBar = New-Object System.Windows.Forms.StatusStrip
|
|
$statusLabel = New-Object System.Windows.Forms.ToolStripStatusLabel
|
|
$statusLabel2 = New-Object System.Windows.Forms.ToolStripStatusLabel
|
|
$statusLabel3 = New-Object System.Windows.Forms.ToolStripStatusLabel
|
|
$ffInstallDir = Find-FirefoxInstallDir
|
|
if ($ffInstallDir) {
|
|
$statusLabel.Text = "Firefox: $ffInstallDir"
|
|
} else {
|
|
$statusLabel.Text = "Firefox-Installation nicht gefunden"
|
|
$statusLabel.ForeColor = [System.Drawing.Color]::Red
|
|
}
|
|
$statusLabel2.Text = " | " + $(if (Test-IsAdmin) { "Admin: Ja" } else { "Admin: Nein" })
|
|
$statusLabel3.Text = " | " + $(if (Test-IntuneManaged) { "Intune: erkannt" } else { "Intune: nicht erkannt" })
|
|
$statusBar.Items.Add($statusLabel) | Out-Null
|
|
$statusBar.Items.Add($statusLabel2) | Out-Null
|
|
$statusBar.Items.Add($statusLabel3) | Out-Null
|
|
$form.Controls.Add($statusBar)
|
|
|
|
$tabs.add_SelectedIndexChanged({
|
|
if ($tabs.SelectedIndex -eq 3) { $btnRefresh.PerformClick() }
|
|
if ($tabs.SelectedIndex -eq 4) {
|
|
Invoke-PolicyCheck
|
|
$btnRefreshPolicies.PerformClick()
|
|
}
|
|
})
|
|
|
|
[void]$form.ShowDialog()
|