Rewrite as standalone C# WinForms app
Replace the Office Web Add-in with a native Windows application. The web add-in required Exchange/M365 for registration which is not available in all customer environments (standalone Office, POP/IMAP only). The new app: - Uses COM Interop to access Outlook contacts directly - Communicates with Starface REST API (accepts self-signed certs) - Runs as System Tray app with optional auto-sync - Profile-based config stored in %AppData% - No webserver, no certificates, no Exchange, no M365 needed - Inno Setup installer for clean MSI-style deployment - Works with any Outlook version (Classic and New) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Importiert das SSL-Zertifikat einer Starface-Anlage in den Windows-Zertifikatspeicher.
|
||||
.DESCRIPTION
|
||||
Verbindet sich per SSL/TLS zur angegebenen Starface-Anlage, extrahiert das
|
||||
Zertifikat und importiert es als vertrauenswuerdig. Danach kann das Outlook
|
||||
Add-in die Starface REST-API ueber HTTPS erreichen.
|
||||
.EXAMPLE
|
||||
.\import-cert.ps1 -StarfaceHost 192.168.1.100
|
||||
.EXAMPLE
|
||||
.\import-cert.ps1 -StarfaceHost pbx.firma.local -Port 8443
|
||||
#>
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$StarfaceHost,
|
||||
|
||||
[int]$Port = 443
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " Starface-Zertifikat importieren" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Write-Host " [OK] Verbinde mit ${StarfaceHost}:${Port} ..." -ForegroundColor Green
|
||||
|
||||
try {
|
||||
$tcpClient = New-Object System.Net.Sockets.TcpClient
|
||||
$tcpClient.Connect($StarfaceHost, $Port)
|
||||
$sslStream = New-Object System.Net.Security.SslStream(
|
||||
$tcpClient.GetStream(),
|
||||
$false,
|
||||
{ $true } # Alle Zertifikate akzeptieren fuer den Abruf
|
||||
)
|
||||
$sslStream.AuthenticateAsClient($StarfaceHost)
|
||||
|
||||
$remoteCert = $sslStream.RemoteCertificate
|
||||
$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($remoteCert)
|
||||
|
||||
$sslStream.Close()
|
||||
$tcpClient.Close()
|
||||
|
||||
Write-Host " Zertifikat erhalten:" -ForegroundColor Green
|
||||
Write-Host " Subject: $($x509Cert.Subject)" -ForegroundColor White
|
||||
Write-Host " Aussteller: $($x509Cert.Issuer)" -ForegroundColor White
|
||||
Write-Host " Gueltig bis: $($x509Cert.NotAfter)" -ForegroundColor White
|
||||
Write-Host " Thumbprint: $($x509Cert.Thumbprint)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
# Pruefen ob bereits vorhanden
|
||||
$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store(
|
||||
[System.Security.Cryptography.X509Certificates.StoreName]::Root,
|
||||
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
|
||||
)
|
||||
$rootStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
|
||||
$existing = $rootStore.Certificates | Where-Object { $_.Thumbprint -eq $x509Cert.Thumbprint }
|
||||
$rootStore.Close()
|
||||
|
||||
if ($existing) {
|
||||
Write-Host " Zertifikat ist bereits als vertrauenswuerdig gespeichert." -ForegroundColor Yellow
|
||||
} else {
|
||||
$rootStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||
$rootStore.Add($x509Cert)
|
||||
$rootStore.Close()
|
||||
Write-Host " [OK] Zertifikat erfolgreich als vertrauenswuerdig importiert!" -ForegroundColor Green
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host " [X] Fehler: $_" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host " Moegliche Ursachen:" -ForegroundColor Yellow
|
||||
Write-Host " - Starface nicht erreichbar (IP/Hostname pruefen)" -ForegroundColor Yellow
|
||||
Write-Host " - Falscher Port (Standard: 443)" -ForegroundColor Yellow
|
||||
Write-Host " - Firewall blockiert die Verbindung" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Read-Host "Eingabetaste zum Beenden"
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Minimaler lokaler HTTPS-Server für das Starface Outlook Sync Add-in.
|
||||
* Liefert nur statische Dateien aus dem webroot-Verzeichnis aus.
|
||||
* Wird als Windows-Dienst oder Scheduled Task ausgeführt.
|
||||
*/
|
||||
|
||||
const https = require("https");
|
||||
const http = require("http");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const url = require("url");
|
||||
|
||||
// Konfiguration aus config.json laden
|
||||
const configPath = path.join(__dirname, "config.json");
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.error("config.json nicht gefunden:", configPath);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
||||
const PORT = config.port || 444;
|
||||
const WEBROOT = path.join(__dirname, "webroot");
|
||||
const CERT_DIR = path.join(__dirname, "certs");
|
||||
|
||||
// MIME-Types
|
||||
const MIME_TYPES = {
|
||||
".html": "text/html; charset=utf-8",
|
||||
".js": "application/javascript; charset=utf-8",
|
||||
".css": "text/css; charset=utf-8",
|
||||
".json": "application/json; charset=utf-8",
|
||||
".png": "image/png",
|
||||
".jpg": "image/jpeg",
|
||||
".svg": "image/svg+xml",
|
||||
".ico": "image/x-icon",
|
||||
".xml": "application/xml; charset=utf-8",
|
||||
};
|
||||
|
||||
function getMimeType(filePath) {
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
return MIME_TYPES[ext] || "application/octet-stream";
|
||||
}
|
||||
|
||||
function handleRequest(req, res) {
|
||||
// CORS-Header für Office Add-in
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
||||
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
||||
|
||||
if (req.method === "OPTIONS") {
|
||||
res.writeHead(204);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
res.writeHead(405, { "Content-Type": "text/plain" });
|
||||
res.end("Method Not Allowed");
|
||||
return;
|
||||
}
|
||||
|
||||
// URL parsen und Pfad bereinigen
|
||||
const parsedUrl = url.parse(req.url);
|
||||
let filePath = decodeURIComponent(parsedUrl.pathname || "/");
|
||||
|
||||
// Directory index
|
||||
if (filePath === "/" || filePath === "") {
|
||||
filePath = "/taskpane.html";
|
||||
}
|
||||
|
||||
// Pfad-Traversal verhindern
|
||||
const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, "");
|
||||
const fullPath = path.join(WEBROOT, safePath);
|
||||
|
||||
// Sicherstellen, dass der Pfad innerhalb des webroot liegt
|
||||
if (!fullPath.startsWith(WEBROOT)) {
|
||||
res.writeHead(403, { "Content-Type": "text/plain" });
|
||||
res.end("Forbidden");
|
||||
return;
|
||||
}
|
||||
|
||||
// Datei ausliefern
|
||||
fs.stat(fullPath, (err, stats) => {
|
||||
if (err || !stats.isFile()) {
|
||||
res.writeHead(404, { "Content-Type": "text/plain" });
|
||||
res.end("Not Found: " + safePath);
|
||||
return;
|
||||
}
|
||||
|
||||
const mimeType = getMimeType(fullPath);
|
||||
res.writeHead(200, {
|
||||
"Content-Type": mimeType,
|
||||
"Cache-Control": "no-cache",
|
||||
});
|
||||
|
||||
const stream = fs.createReadStream(fullPath);
|
||||
stream.pipe(res);
|
||||
stream.on("error", () => {
|
||||
res.writeHead(500, { "Content-Type": "text/plain" });
|
||||
res.end("Internal Server Error");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Zertifikate laden und HTTPS-Server starten
|
||||
const pfxFile = path.join(CERT_DIR, "localhost.pfx");
|
||||
const pfxPasswordFile = path.join(CERT_DIR, "pfx-password.txt");
|
||||
|
||||
if (!fs.existsSync(pfxFile) || !fs.existsSync(pfxPasswordFile)) {
|
||||
console.error("Zertifikate nicht gefunden in:", CERT_DIR);
|
||||
console.error("Bitte zuerst setup.ps1 ausfuehren.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pfxPassword = fs.readFileSync(pfxPasswordFile, "utf-8").trim();
|
||||
|
||||
const serverOptions = {
|
||||
pfx: fs.readFileSync(pfxFile),
|
||||
passphrase: pfxPassword,
|
||||
};
|
||||
|
||||
const server = https.createServer(serverOptions, handleRequest);
|
||||
|
||||
server.listen(PORT, "127.0.0.1", () => {
|
||||
console.log(`Starface Outlook Sync - Lokaler Server`);
|
||||
console.log(`Läuft auf: https://localhost:${PORT}`);
|
||||
console.log(`Webroot: ${WEBROOT}`);
|
||||
console.log(`PID: ${process.pid}`);
|
||||
});
|
||||
|
||||
server.on("error", (err) => {
|
||||
if (err.code === "EADDRINUSE") {
|
||||
console.error(`Port ${PORT} ist bereits belegt.`);
|
||||
console.error("Bitte anderen Port in config.json wählen.");
|
||||
} else {
|
||||
console.error("Server-Fehler:", err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Graceful Shutdown
|
||||
process.on("SIGINT", () => {
|
||||
console.log("Server wird beendet...");
|
||||
server.close(() => process.exit(0));
|
||||
});
|
||||
process.on("SIGTERM", () => {
|
||||
console.log("Server wird beendet...");
|
||||
server.close(() => process.exit(0));
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
; Inno Setup Script fuer Starface Outlook Sync
|
||||
; Erfordert Inno Setup 6.x (https://jrsoftware.org/isinfo.php)
|
||||
|
||||
#define MyAppName "Starface Outlook Sync"
|
||||
#define MyAppVersion "0.0.0.1"
|
||||
#define MyAppPublisher "HackerSoft - Hacker-Net Telekommunikation"
|
||||
#define MyAppURL "https://www.hacker-net.de"
|
||||
#define MyAppExeName "StarfaceOutlookSync.exe"
|
||||
|
||||
[Setup]
|
||||
AppId={{B7E3F4A1-2C8D-4E5F-9A0B-1D2E3F4A5B6C}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppVerName={#MyAppName} {#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
DefaultDirName={autopf}\StarfaceOutlookSync
|
||||
DefaultGroupName={#MyAppName}
|
||||
DisableProgramGroupPage=yes
|
||||
OutputDir=..\dist
|
||||
OutputBaseFilename=StarfaceOutlookSync_Setup_{#MyAppVersion}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
PrivilegesRequired=admin
|
||||
ArchitecturesAllowed=x64compatible
|
||||
ArchitecturesInstallIn64BitMode=x64compatible
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
|
||||
[Languages]
|
||||
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "Desktop-Verknuepfung erstellen"; GroupDescription: "Zusaetzliche Optionen:"
|
||||
Name: "autostart"; Description: "Bei Windows-Anmeldung automatisch starten"; GroupDescription: "Zusaetzliche Optionen:"; Flags: checkedonce
|
||||
|
||||
[Files]
|
||||
; Hauptanwendung - Pfad anpassen nach Build
|
||||
Source: "..\src\StarfaceOutlookSync\bin\Release\net4.8\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
Name: "{group}\{#MyAppName} deinstallieren"; Filename: "{uninstallexe}"
|
||||
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||
|
||||
[Registry]
|
||||
; Autostart
|
||||
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "StarfaceOutlookSync"; ValueData: """{app}\{#MyAppExeName}"""; Flags: uninsdeletevalue; Tasks: autostart
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{#MyAppName} jetzt starten"; Flags: nowait postinstall skipifsilent
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "taskkill"; Parameters: "/F /IM {#MyAppExeName}"; Flags: runhidden; RunOnceId: "KillApp"
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{userappdata}\StarfaceOutlookSync"
|
||||
|
||||
[Code]
|
||||
// Pruefe ob .NET Framework 4.8 installiert ist
|
||||
function IsDotNetInstalled(): Boolean;
|
||||
var
|
||||
Version: Cardinal;
|
||||
begin
|
||||
Result := RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full', 'Release', Version);
|
||||
if Result then
|
||||
Result := Version >= 528040; // .NET 4.8
|
||||
end;
|
||||
|
||||
function InitializeSetup(): Boolean;
|
||||
begin
|
||||
Result := True;
|
||||
|
||||
if not IsDotNetInstalled() then
|
||||
begin
|
||||
MsgBox('.NET Framework 4.8 oder hoeher wird benoetigt.' + #13#10 +
|
||||
'Bitte installieren Sie es von:' + #13#10 +
|
||||
'https://dotnet.microsoft.com/download/dotnet-framework/net48',
|
||||
mbError, MB_OK);
|
||||
Result := False;
|
||||
end;
|
||||
end;
|
||||
@@ -1,499 +0,0 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Setup-Script fuer Starface Outlook Sync Add-in.
|
||||
.DESCRIPTION
|
||||
- Fragt Starface-Host ab (zum Import des SSL-Zertifikats)
|
||||
- Fragt lokalen Port ab fuer den Webserver
|
||||
- Extrahiert das SSL-Zertifikat der Starface und importiert es als vertrauenswuerdig
|
||||
- Erstellt eine lokale CA und ein localhost-Zertifikat
|
||||
- Installiert den lokalen HTTPS-Webserver als Windows Scheduled Task
|
||||
- Registriert das Outlook Add-in
|
||||
Login-Daten werden NICHT benoetigt - diese werden spaeter im Add-in selbst
|
||||
in den Sync-Profilen konfiguriert.
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$InstallDir = "$env:ProgramFiles\StarfaceOutlookSync"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# ============================================================
|
||||
# Hilfsfunktionen
|
||||
# ============================================================
|
||||
|
||||
function Write-Header($text) {
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " $text" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Write-Step($text) {
|
||||
Write-Host " [OK] $text" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Warn($text) {
|
||||
Write-Host " [!] $text" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
function Write-Err($text) {
|
||||
Write-Host " [X] $text" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Test-NodeJs {
|
||||
try {
|
||||
$version = & node --version 2>$null
|
||||
if ($version) {
|
||||
Write-Step "Node.js gefunden: $version"
|
||||
return $true
|
||||
}
|
||||
} catch {}
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-PortAvailable($port) {
|
||||
$listener = Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue
|
||||
return ($null -eq $listener)
|
||||
}
|
||||
|
||||
function Import-StarfaceCert($host_, $port_) {
|
||||
Write-Step "Verbinde mit ${host_}:${port_} ..."
|
||||
|
||||
$tcpClient = New-Object System.Net.Sockets.TcpClient
|
||||
$tcpClient.Connect($host_, $port_)
|
||||
$sslStream = New-Object System.Net.Security.SslStream(
|
||||
$tcpClient.GetStream(),
|
||||
$false,
|
||||
{ $true } # Alle Zertifikate akzeptieren fuer den Abruf
|
||||
)
|
||||
$sslStream.AuthenticateAsClient($host_)
|
||||
|
||||
$remoteCert = $sslStream.RemoteCertificate
|
||||
$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($remoteCert)
|
||||
|
||||
$sslStream.Close()
|
||||
$tcpClient.Close()
|
||||
|
||||
Write-Step "Zertifikat erhalten: $($x509Cert.Subject)"
|
||||
Write-Step "Aussteller: $($x509Cert.Issuer)"
|
||||
Write-Step "Gueltig bis: $($x509Cert.NotAfter)"
|
||||
|
||||
# In den Trusted Root Store importieren
|
||||
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
|
||||
[System.Security.Cryptography.X509Certificates.StoreName]::Root,
|
||||
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
|
||||
)
|
||||
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||
$store.Add($x509Cert)
|
||||
$store.Close()
|
||||
|
||||
Write-Step "Starface-Zertifikat als vertrauenswuerdig importiert."
|
||||
return $x509Cert
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Voraussetzungen pruefen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Starface Outlook Sync - Setup"
|
||||
|
||||
# Node.js pruefen und ggf. installieren
|
||||
if (-not (Test-NodeJs)) {
|
||||
Write-Warn "Node.js ist nicht installiert."
|
||||
Write-Host " Node.js wird fuer den lokalen Webserver benoetigt." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
$installNode = Read-Host "Node.js jetzt automatisch herunterladen und installieren? (j/n)"
|
||||
|
||||
if ($installNode -eq "j") {
|
||||
Write-Step "Ermittle System-Architektur ..."
|
||||
$arch = if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" }
|
||||
$nodeVersion = "v22.14.0" # LTS
|
||||
$msiUrl = "https://nodejs.org/dist/$nodeVersion/node-$nodeVersion-$arch.msi"
|
||||
$msiPath = Join-Path $env:TEMP "node-$nodeVersion-$arch.msi"
|
||||
|
||||
Write-Step "Lade Node.js $nodeVersion ($arch) herunter ..."
|
||||
Write-Host " $msiUrl" -ForegroundColor Gray
|
||||
|
||||
try {
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$ProgressPreference = 'SilentlyContinue' # Beschleunigt den Download
|
||||
Invoke-WebRequest -Uri $msiUrl -OutFile $msiPath -UseBasicParsing
|
||||
|
||||
if (-not (Test-Path $msiPath)) {
|
||||
Write-Err "Download fehlgeschlagen."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$fileSize = [math]::Round((Get-Item $msiPath).Length / 1MB, 1)
|
||||
Write-Step "Download abgeschlossen ($fileSize MB)"
|
||||
|
||||
Write-Step "Installiere Node.js (bitte warten) ..."
|
||||
$msiArgs = "/i `"$msiPath`" /qn /norestart"
|
||||
$process = Start-Process -FilePath "msiexec.exe" -ArgumentList $msiArgs -Wait -PassThru
|
||||
if ($process.ExitCode -ne 0) {
|
||||
Write-Err "Installation fehlgeschlagen (Exit-Code: $($process.ExitCode))"
|
||||
Write-Host " Bitte Node.js manuell installieren: https://nodejs.org/" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
# PATH aktualisieren (MSI fuegt Node.js zum System-PATH hinzu)
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||
|
||||
# Aufraeumen
|
||||
Remove-Item $msiPath -Force -ErrorAction SilentlyContinue
|
||||
|
||||
if (Test-NodeJs) {
|
||||
Write-Step "Node.js erfolgreich installiert!"
|
||||
} else {
|
||||
Write-Err "Node.js wurde installiert, ist aber nicht im PATH gefunden."
|
||||
Write-Host " Bitte das Setup nach einem Neustart erneut ausfuehren." -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Err "Fehler beim Download/Installation: $_"
|
||||
Write-Host " Bitte Node.js manuell installieren: https://nodejs.org/" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host " Bitte Node.js manuell installieren: https://nodejs.org/" -ForegroundColor Yellow
|
||||
Write-Host " (LTS-Version empfohlen)" -ForegroundColor Yellow
|
||||
Read-Host "Eingabetaste zum Beenden"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Benutzereingaben
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Starface-Verbindung"
|
||||
Write-Host " Das Add-in kommuniziert per HTTPS mit der Starface." -ForegroundColor Gray
|
||||
Write-Host " Da die Starface meist ein selbstsigniertes Zertifikat verwendet," -ForegroundColor Gray
|
||||
Write-Host " muss dieses Zertifikat (CA) einmalig als vertrauenswuerdig" -ForegroundColor Gray
|
||||
Write-Host " importiert werden. Dafuer wird hier nur die Adresse benoetigt." -ForegroundColor Gray
|
||||
Write-Host "" -ForegroundColor Gray
|
||||
Write-Host " Login-Daten werden hier NICHT benoetigt - diese konfigurieren" -ForegroundColor Gray
|
||||
Write-Host " Sie spaeter im Add-in in den Sync-Profilen." -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
$starfaceHost = Read-Host "Starface Host/IP-Adresse (z.B. 192.168.1.100 oder pbx.firma.local)"
|
||||
if ([string]::IsNullOrWhiteSpace($starfaceHost)) {
|
||||
Write-Err "Kein Host angegeben."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$starfacePortInput = Read-Host "Starface HTTPS-Port [443]"
|
||||
$starfacePort = if ([string]::IsNullOrWhiteSpace($starfacePortInput)) { 443 } else { [int]$starfacePortInput }
|
||||
|
||||
Write-Host ""
|
||||
Write-Header "Lokaler Webserver"
|
||||
|
||||
$localPortInput = Read-Host "Lokaler HTTPS-Port fuer das Add-in [444]"
|
||||
$localPort = if ([string]::IsNullOrWhiteSpace($localPortInput)) { 444 } else { [int]$localPortInput }
|
||||
|
||||
if (-not (Test-PortAvailable $localPort)) {
|
||||
Write-Warn "Port $localPort ist bereits belegt!"
|
||||
$localPortInput = Read-Host "Bitte einen anderen Port waehlen"
|
||||
$localPort = [int]$localPortInput
|
||||
if (-not (Test-PortAvailable $localPort)) {
|
||||
Write-Err "Port $localPort ist ebenfalls belegt. Abbruch."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
Write-Step "Verwende Port: $localPort"
|
||||
|
||||
# ============================================================
|
||||
# Schritt 1: Starface SSL-Zertifikat extrahieren und importieren
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 1: Starface-Zertifikat importieren"
|
||||
|
||||
try {
|
||||
Import-StarfaceCert $starfaceHost $starfacePort
|
||||
} catch {
|
||||
Write-Err "Fehler beim Abrufen des Starface-Zertifikats: $_"
|
||||
Write-Warn "Die Verbindung zur Starface API koennte fehlschlagen."
|
||||
Write-Warn "Sie koennen das Zertifikat spaeter nachholen mit:"
|
||||
Write-Host " .\import-cert.ps1 -StarfaceHost $starfaceHost -Port $starfacePort" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Moechten Sie trotzdem fortfahren? (j/n)" -ForegroundColor Yellow
|
||||
$continue = Read-Host
|
||||
if ($continue -ne "j") { exit 1 }
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 2: Lokale CA und localhost-Zertifikat erstellen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 2: Lokale Zertifikate erstellen"
|
||||
|
||||
$certDir = Join-Path $InstallDir "certs"
|
||||
New-Item -ItemType Directory -Path $certDir -Force | Out-Null
|
||||
|
||||
# Lokale CA erstellen
|
||||
Write-Step "Erstelle lokale CA ..."
|
||||
|
||||
$caParams = @{
|
||||
Subject = "CN=Starface Outlook Sync Local CA"
|
||||
KeyLength = 2048
|
||||
KeyAlgorithm = "RSA"
|
||||
HashAlgorithm = "SHA256"
|
||||
KeyExportPolicy = "Exportable"
|
||||
NotAfter = (Get-Date).AddYears(10)
|
||||
CertStoreLocation = "Cert:\LocalMachine\My"
|
||||
KeyUsage = "CertSign", "CRLSign"
|
||||
TextExtension = @("2.5.29.19={text}CA=true&pathlength=1")
|
||||
}
|
||||
|
||||
$caCert = New-SelfSignedCertificate @caParams
|
||||
Write-Step "Lokale CA erstellt: $($caCert.Thumbprint)"
|
||||
|
||||
# CA in Trusted Root Store importieren
|
||||
$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store(
|
||||
[System.Security.Cryptography.X509Certificates.StoreName]::Root,
|
||||
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
|
||||
)
|
||||
$rootStore.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||
$rootStore.Add($caCert)
|
||||
$rootStore.Close()
|
||||
Write-Step "Lokale CA als vertrauenswuerdig importiert."
|
||||
|
||||
# Localhost-Zertifikat erstellen, signiert von der lokalen CA
|
||||
Write-Step "Erstelle localhost-Zertifikat ..."
|
||||
|
||||
$localhostParams = @{
|
||||
Subject = "CN=localhost"
|
||||
KeyLength = 2048
|
||||
KeyAlgorithm = "RSA"
|
||||
HashAlgorithm = "SHA256"
|
||||
KeyExportPolicy = "Exportable"
|
||||
NotAfter = (Get-Date).AddYears(5)
|
||||
CertStoreLocation = "Cert:\LocalMachine\My"
|
||||
Signer = $caCert
|
||||
DnsName = "localhost", "127.0.0.1"
|
||||
TextExtension = @("2.5.29.37={text}1.3.6.1.5.5.7.3.1") # Server Authentication
|
||||
}
|
||||
|
||||
$localhostCert = New-SelfSignedCertificate @localhostParams
|
||||
Write-Step "Localhost-Zertifikat erstellt: $($localhostCert.Thumbprint)"
|
||||
|
||||
# Zertifikat als PFX exportieren (fuer Node.js)
|
||||
# PFX funktioniert auf allen Windows-Versionen (.NET Framework + .NET Core)
|
||||
Write-Step "Exportiere Zertifikate fuer den Webserver ..."
|
||||
|
||||
$pfxPassword = [guid]::NewGuid().ToString()
|
||||
$pfxSecure = ConvertTo-SecureString -String $pfxPassword -Force -AsPlainText
|
||||
$pfxPath = Join-Path $certDir "localhost.pfx"
|
||||
|
||||
Export-PfxCertificate -Cert $localhostCert -FilePath $pfxPath -Password $pfxSecure | Out-Null
|
||||
|
||||
# Passwort in config speichern (wird vom Server gelesen)
|
||||
Set-Content -Path (Join-Path $certDir "pfx-password.txt") -Value $pfxPassword -Encoding ASCII
|
||||
|
||||
Write-Step "PFX-Zertifikat exportiert."
|
||||
|
||||
# CA-Zertifikat exportieren (fuer Deinstallation)
|
||||
$caCertPem = "-----BEGIN CERTIFICATE-----`n"
|
||||
$caCertPem += [Convert]::ToBase64String($caCert.RawData, [Base64FormattingOptions]::InsertLineBreaks)
|
||||
$caCertPem += "`n-----END CERTIFICATE-----"
|
||||
Set-Content -Path (Join-Path $certDir "local-ca.crt") -Value $caCertPem -Encoding ASCII
|
||||
|
||||
# Thumbprints speichern (fuer Deinstallation)
|
||||
$certInfo = @{
|
||||
caThumbprint = $caCert.Thumbprint
|
||||
localhostThumbprint = $localhostCert.Thumbprint
|
||||
}
|
||||
$certInfo | ConvertTo-Json | Set-Content (Join-Path $InstallDir "cert-info.json") -Encoding UTF8
|
||||
|
||||
Write-Step "Zertifikate exportiert nach: $certDir"
|
||||
|
||||
# ============================================================
|
||||
# Schritt 3: Add-in Dateien installieren
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 3: Add-in Dateien installieren"
|
||||
|
||||
$webrootDir = Join-Path $InstallDir "webroot"
|
||||
New-Item -ItemType Directory -Path $webrootDir -Force | Out-Null
|
||||
|
||||
# Pruefen ob dist-Ordner existiert (bereits gebaut)
|
||||
$distDir = Join-Path $scriptDir "..\dist"
|
||||
if (-not (Test-Path $distDir)) {
|
||||
Write-Step "Baue Add-in (npm run build) ..."
|
||||
Push-Location (Join-Path $scriptDir "..")
|
||||
& npm run build 2>&1 | Out-Null
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if (-not (Test-Path $distDir)) {
|
||||
Write-Err "Build fehlgeschlagen. dist-Ordner nicht gefunden."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Dateien kopieren
|
||||
Copy-Item -Path "$distDir\*" -Destination $webrootDir -Recurse -Force
|
||||
Write-Step "Add-in Dateien kopiert nach: $webrootDir"
|
||||
|
||||
# manifest.xml mit korrektem Port anpassen
|
||||
$manifestPath = Join-Path $webrootDir "manifest.xml"
|
||||
if (Test-Path $manifestPath) {
|
||||
$manifestContent = Get-Content $manifestPath -Raw -Encoding UTF8
|
||||
$manifestContent = $manifestContent -replace "https://localhost:3000", "https://localhost:$localPort"
|
||||
Set-Content -Path $manifestPath -Value $manifestContent -Encoding UTF8
|
||||
Write-Step "manifest.xml angepasst (Port: $localPort)"
|
||||
}
|
||||
|
||||
# Auch eine Kopie der manifest.xml ins Installationsverzeichnis
|
||||
Copy-Item -Path $manifestPath -Destination (Join-Path $InstallDir "manifest.xml") -Force
|
||||
|
||||
# ============================================================
|
||||
# Schritt 4: Server-Konfiguration und Installation
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 4: Lokalen Webserver einrichten"
|
||||
|
||||
# Server-Dateien kopieren
|
||||
Copy-Item -Path (Join-Path $scriptDir "local-server.js") -Destination $InstallDir -Force
|
||||
|
||||
# import-cert.ps1 ins Installationsverzeichnis kopieren (fuer spaetere Nutzung)
|
||||
$importCertSrc = Join-Path $scriptDir "import-cert.ps1"
|
||||
if (Test-Path $importCertSrc) {
|
||||
Copy-Item -Path $importCertSrc -Destination $InstallDir -Force
|
||||
}
|
||||
|
||||
# uninstall.ps1 ins Installationsverzeichnis kopieren
|
||||
$uninstallSrc = Join-Path $scriptDir "uninstall.ps1"
|
||||
if (Test-Path $uninstallSrc) {
|
||||
Copy-Item -Path $uninstallSrc -Destination $InstallDir -Force
|
||||
}
|
||||
|
||||
# config.json erstellen
|
||||
$serverConfig = @{
|
||||
port = $localPort
|
||||
}
|
||||
$serverConfig | ConvertTo-Json | Set-Content (Join-Path $InstallDir "config.json") -Encoding UTF8
|
||||
Write-Step "Server-Konfiguration erstellt."
|
||||
|
||||
# Windows Scheduled Task erstellen (startet beim Systemstart)
|
||||
$taskName = "StarfaceOutlookSyncServer"
|
||||
|
||||
# Bestehenden Task entfernen falls vorhanden
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
|
||||
$nodeExe = (Get-Command node).Source
|
||||
$serverScript = Join-Path $InstallDir "local-server.js"
|
||||
|
||||
$action = New-ScheduledTaskAction -Execute $nodeExe -Argument "`"$serverScript`"" -WorkingDirectory $InstallDir
|
||||
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
||||
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit ([TimeSpan]::Zero)
|
||||
|
||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Lokaler HTTPS-Server fuer Starface Outlook Sync Add-in" | Out-Null
|
||||
|
||||
# Task sofort starten
|
||||
Start-ScheduledTask -TaskName $taskName
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
# Pruefen ob der Server laeuft
|
||||
try {
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||
$response = Invoke-WebRequest -Uri "https://localhost:$localPort/taskpane.html" -UseBasicParsing -TimeoutSec 5
|
||||
if ($response.StatusCode -eq 200) {
|
||||
Write-Step "Lokaler Webserver laeuft auf https://localhost:$localPort"
|
||||
}
|
||||
} catch {
|
||||
Write-Warn "Server-Test fehlgeschlagen. Server startet moeglicherweise verzoegert."
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 5: Outlook Add-in registrieren
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 5: Outlook Add-in registrieren"
|
||||
|
||||
# Manifest-Datei vorbereiten
|
||||
$manifestDir = Join-Path $InstallDir "manifest-catalog"
|
||||
New-Item -ItemType Directory -Path $manifestDir -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $InstallDir "manifest.xml") -Destination $manifestDir -Force
|
||||
$manifestFile = Join-Path $manifestDir "manifest.xml"
|
||||
|
||||
# Outlook Add-ins werden pro Benutzer ueber den Browser registriert.
|
||||
# Das Add-in wird am Microsoft 365 Konto des Benutzers gespeichert,
|
||||
# nicht am Computer. Auf einem Terminal Server muss jeder Benutzer
|
||||
# das Add-in einmalig selbst hinzufuegen.
|
||||
|
||||
Write-Host " Das Add-in muss pro Benutzer einmalig in Outlook" -ForegroundColor White
|
||||
Write-Host " hinzugefuegt werden. Es wird am Microsoft 365 Konto" -ForegroundColor White
|
||||
Write-Host " gespeichert und ist dann auf allen Geraeten verfuegbar." -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " So geht's:" -ForegroundColor Cyan
|
||||
Write-Host " 1. Im Browser oeffnen: https://aka.ms/olksideload" -ForegroundColor White
|
||||
Write-Host " 2. Mit dem eigenen Microsoft 365 Konto anmelden" -ForegroundColor White
|
||||
Write-Host " 3. 'Meine Add-Ins' -> 'Benutzerdefinierte Add-Ins'" -ForegroundColor White
|
||||
Write-Host " 4. 'Benutzerdefiniertes Add-In hinzufuegen' -> 'Aus Datei'" -ForegroundColor White
|
||||
Write-Host " 5. Diese Datei waehlen:" -ForegroundColor White
|
||||
Write-Host " $manifestFile" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host " Alternativ direkt in Outlook:" -ForegroundColor Cyan
|
||||
Write-Host " Classic: Datei -> Info -> 'Add-Ins verwalten'" -ForegroundColor White
|
||||
Write-Host " Neu: Einstellungen -> Add-Ins verwalten" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
$openBrowser = Read-Host "Sideload-Seite jetzt im Browser oeffnen? (j/n)"
|
||||
if ($openBrowser -eq "j") {
|
||||
Start-Process "https://aka.ms/olksideload"
|
||||
Write-Step "Browser geoeffnet."
|
||||
Write-Host " Bitte Add-in wie oben beschrieben hinzufuegen." -ForegroundColor White
|
||||
Write-Host " Manifest-Datei: $manifestFile" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 6: Installationsinfo speichern
|
||||
# ============================================================
|
||||
|
||||
$installInfo = @{
|
||||
installDir = $InstallDir
|
||||
localPort = $localPort
|
||||
taskName = $taskName
|
||||
installedAt = (Get-Date).ToString("o")
|
||||
manifestDir = $manifestDir
|
||||
manifestFile = $manifestFile
|
||||
manifestUrl = "https://localhost:$localPort"
|
||||
caThumbprint = $caCert.Thumbprint
|
||||
localhostThumbprint = $localhostCert.Thumbprint
|
||||
}
|
||||
$installInfo | ConvertTo-Json | Set-Content (Join-Path $InstallDir "install-info.json") -Encoding UTF8
|
||||
|
||||
# ============================================================
|
||||
# Zusammenfassung
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Installation abgeschlossen!"
|
||||
|
||||
Write-Host " Installationsverzeichnis: $InstallDir" -ForegroundColor White
|
||||
Write-Host " Lokaler Server: https://localhost:$localPort" -ForegroundColor White
|
||||
Write-Host " Manifest: $manifestFile" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " [!] Jeder Benutzer muss das Add-in einmalig in Outlook" -ForegroundColor Yellow
|
||||
Write-Host " hinzufuegen: https://aka.ms/olksideload" -ForegroundColor Yellow
|
||||
Write-Host " Manifest-Datei: $manifestFile" -ForegroundColor Yellow
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " Naechster Schritt: Im Add-in ein Sync-Profil mit den" -ForegroundColor White
|
||||
Write-Host " Starface-Zugangsdaten einrichten." -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host " Weitere Starface-Anlagen einbinden? Zertifikat importieren mit:" -ForegroundColor Gray
|
||||
Write-Host " .\import-cert.ps1 -StarfaceHost <host> [-Port <port>]" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Deinstallation: uninstall.ps1 als Administrator ausfuehren" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Firewall-Regel fuer den lokalen Port (nur localhost, rein vorsichtshalber)
|
||||
New-NetFirewallRule -DisplayName "Starface Outlook Sync" -Direction Inbound -LocalPort $localPort -Protocol TCP -Action Allow -Profile Private -ErrorAction SilentlyContinue | Out-Null
|
||||
|
||||
Read-Host "Eingabetaste zum Beenden"
|
||||
@@ -1,148 +0,0 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Deinstalliert das Starface Outlook Sync Add-in.
|
||||
.DESCRIPTION
|
||||
Entfernt Server, Zertifikate, Scheduled Task, Registry-Eintraege und Dateien.
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$InstallDir = "$env:ProgramFiles\StarfaceOutlookSync"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Write-Header($text) {
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host " $text" -ForegroundColor Cyan
|
||||
Write-Host "============================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Write-Step($text) {
|
||||
Write-Host " [OK] $text" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Write-Warn($text) {
|
||||
Write-Host " [!] $text" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Header "Starface Outlook Sync - Deinstallation"
|
||||
|
||||
# Sicherheitsabfrage
|
||||
Write-Host " Dies entfernt das Starface Outlook Sync Add-in vollstaendig." -ForegroundColor Yellow
|
||||
Write-Host " Installationsverzeichnis: $InstallDir" -ForegroundColor Yellow
|
||||
$confirm = Read-Host " Fortfahren? (j/n)"
|
||||
if ($confirm -ne "j") {
|
||||
Write-Host " Abgebrochen." -ForegroundColor Gray
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 1: Scheduled Task stoppen und entfernen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 1: Server stoppen"
|
||||
|
||||
$taskName = "StarfaceOutlookSyncServer"
|
||||
$task = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
|
||||
if ($task) {
|
||||
if ($task.State -eq "Running") {
|
||||
Stop-ScheduledTask -TaskName $taskName
|
||||
Write-Step "Server gestoppt."
|
||||
}
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
|
||||
Write-Step "Scheduled Task entfernt."
|
||||
} else {
|
||||
Write-Warn "Scheduled Task '$taskName' nicht gefunden."
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 2: Zertifikate entfernen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 2: Zertifikate entfernen"
|
||||
|
||||
$certInfoPath = Join-Path $InstallDir "cert-info.json"
|
||||
if (Test-Path $certInfoPath) {
|
||||
$certInfo = Get-Content $certInfoPath -Raw | ConvertFrom-Json
|
||||
|
||||
# Localhost-Zertifikat aus dem persoenlichen Store entfernen
|
||||
if ($certInfo.localhostThumbprint) {
|
||||
$cert = Get-ChildItem "Cert:\LocalMachine\My" | Where-Object { $_.Thumbprint -eq $certInfo.localhostThumbprint }
|
||||
if ($cert) {
|
||||
Remove-Item $cert.PSPath -Force
|
||||
Write-Step "Localhost-Zertifikat entfernt."
|
||||
}
|
||||
}
|
||||
|
||||
# Lokale CA aus dem Root Store entfernen
|
||||
if ($certInfo.caThumbprint) {
|
||||
$caCert = Get-ChildItem "Cert:\LocalMachine\Root" | Where-Object { $_.Thumbprint -eq $certInfo.caThumbprint }
|
||||
if ($caCert) {
|
||||
Remove-Item $caCert.PSPath -Force
|
||||
Write-Step "Lokale CA entfernt."
|
||||
}
|
||||
|
||||
# Auch aus dem persoenlichen Store
|
||||
$caCertMy = Get-ChildItem "Cert:\LocalMachine\My" | Where-Object { $_.Thumbprint -eq $certInfo.caThumbprint }
|
||||
if ($caCertMy) {
|
||||
Remove-Item $caCertMy.PSPath -Force
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Warn "cert-info.json nicht gefunden. Zertifikate muessen ggf. manuell entfernt werden."
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Schritt 3: Outlook Add-in Registrierung entfernen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 3: Outlook Add-in Registrierung"
|
||||
|
||||
Write-Warn "Das Add-in ist pro Benutzer am Microsoft 365 Konto registriert."
|
||||
Write-Host " Jeder Benutzer muss es selbst in Outlook entfernen:" -ForegroundColor Gray
|
||||
Write-Host " 1. https://aka.ms/olksideload oeffnen" -ForegroundColor Gray
|
||||
Write-Host " 2. Unter 'Meine Add-Ins' das Add-in entfernen" -ForegroundColor Gray
|
||||
Write-Host " Oder in Outlook: Add-Ins verwalten -> Add-In entfernen" -ForegroundColor Gray
|
||||
|
||||
# ============================================================
|
||||
# Schritt 4: Firewall-Regel entfernen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 4: Firewall-Regel entfernen"
|
||||
|
||||
Remove-NetFirewallRule -DisplayName "Starface Outlook Sync" -ErrorAction SilentlyContinue
|
||||
Write-Step "Firewall-Regel entfernt."
|
||||
|
||||
# ============================================================
|
||||
# Schritt 5: Dateien entfernen
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Schritt 5: Dateien entfernen"
|
||||
|
||||
if (Test-Path $InstallDir) {
|
||||
Remove-Item -Path $InstallDir -Recurse -Force
|
||||
Write-Step "Installationsverzeichnis entfernt: $InstallDir"
|
||||
} else {
|
||||
Write-Warn "Verzeichnis nicht gefunden: $InstallDir"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Zusammenfassung
|
||||
# ============================================================
|
||||
|
||||
Write-Header "Deinstallation abgeschlossen"
|
||||
|
||||
Write-Host " Das Starface Outlook Sync Add-in wurde entfernt." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host " Hinweis: Falls das Add-in im neuen Outlook manuell" -ForegroundColor Gray
|
||||
Write-Host " hinzugefuegt wurde, muss es dort auch manuell entfernt werden:" -ForegroundColor Gray
|
||||
Write-Host " Einstellungen -> Add-Ins verwalten -> Add-In entfernen" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host " Das Starface-Zertifikat wurde NICHT entfernt," -ForegroundColor Yellow
|
||||
Write-Host " da es ggf. von anderen Anwendungen benoetigt wird." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Read-Host "Eingabetaste zum Beenden"
|
||||
Reference in New Issue
Block a user