Files
firefox-addin-manager/FirefoxAddinManager.ps1
T
2026-06-10 21:57:50 +02:00

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()