Installation automatisieren

Geschrieben von Daniel von PhySonix

Zuletzt aktualisiert Vor etwa 1 Jahr

Einleitung

Mit Patchmanagement-Software können Sie die Installation und Aktualisierung von PhySonix Easy Connect ganz einfach automatisieren. Damit sind Sie immer Up-To-Date, und können manuellen Aufwand reduzieren.

  • Die Installer sind Standard MSI-Installer, und können mittels /quiet ohne Oberfläche ausgeführt werden (Details)

  • Die aktuellen Versionen der MSI-Installer sind über eine fixe URL erreichbar (Details)

Diese Infos sollten Ihnen einen guten Start bieten, um die Installation und Aktualisierung zu automatisieren.

Falls Sie den Easy Connect Server auf Linux installieren oder in einem Docker Container laufen lassen möchten, stimmen Sie für Easy Connect Server auf Linux oder als Docker Image ab oder hinterlassen Sie dort einen Kommentar.

PowerShell Script

Als weitere Hilfe haben wir ein PowerShell Script vorbereitet, welches folgende Funktionen unterstützt:

  • Unterstützt PhySonix Easy Connect Server und Client

  • Einstellungen vordefinieren mittels Parameter, oder Auswahl über GUI oder Konsole

  • Auswahl des Software-Kanals (Release oder Beta) (Details)

  • Herunterladen und entpacken der MSI-Installer

  • Ausführen der MSI-Installer ohne Oberfläche (mit /quiet)

############################################################################
# 1) Param-Block: Direkte Parameterverwendung
############################################################################
Param(
    [string]$InstallPath = "C:\PhySonix\Install",

    [ValidateSet("ServerAndClient","ServerOnly","ClientOnly")]
    [string]$Components = "ServerAndClient",

    [ValidateSet("Release","Beta")]
    [string]$InstallerType = "Release"
)

############################################################################
# 2) Prüfung, ob Parameter übergeben wurden
#    => Wenn $PSBoundParameters.Count > 0, direkt mit Parametern weiter.
############################################################################
$paramModeActive = $PSBoundParameters.Count -gt 0

############################################################################
# 3) Prüfen auf GUI-Verfügbarkeit (nur relevant, wenn KEIN Param-Mode aktiv)
############################################################################
$useGui = $true
if (-not $paramModeActive) {
    try {
        if (-not [System.Environment]::UserInteractive) {
            Write-Host "System ist nicht interaktiv (UserInteractive=$false). Wechsle zu Konsolen-Modus."
            $useGui = $false
        } else {
            Add-Type -AssemblyName System.Windows.Forms -ErrorAction Stop
            Add-Type -AssemblyName System.Drawing -ErrorAction Stop
        }
    }
    catch {
        Write-Host "Fehler beim Laden der WinForms-Assembly. Wechsle zu Konsolen-Modus."
        $useGui = $false
    }
}

############################################################################
# 4) GUI-Funktion
############################################################################
function Show-InstallUI {
    # Hauptformular erzeugen
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "PhySonix Easy Connect Installer"
    $form.Size = New-Object System.Drawing.Size(520, 300)
    $form.StartPosition = "CenterScreen"

    # --- Label & TextBox: Installationspfad ---
    $lblInstallPath = New-Object System.Windows.Forms.Label
    $lblInstallPath.Text = "Download- und Arbeitsverzeichnis:"
    $lblInstallPath.AutoSize = $true
    $lblInstallPath.Location = New-Object System.Drawing.Point(10, 10)
    $form.Controls.Add($lblInstallPath)

    $txtInstallPath = New-Object System.Windows.Forms.TextBox
    $txtInstallPath.Text = "C:\PhySonix\Install"
    $txtInstallPath.Width = 400
    $txtInstallPath.Location = New-Object System.Drawing.Point(10, 30)
    $form.Controls.Add($txtInstallPath)

    # --- Label & ComboBox: Komponenten (Server/Client) ---
    $lblComponents = New-Object System.Windows.Forms.Label
    $lblComponents.Text = "Zu installierende Komponenten:"
    $lblComponents.AutoSize = $true
    $lblComponents.Location = New-Object System.Drawing.Point(10, 70)
    $form.Controls.Add($lblComponents)

    $cboComponents = New-Object System.Windows.Forms.ComboBox
    $cboComponents.DropDownStyle = "DropDownList"
    $cboComponents.Width = 200
    $cboComponents.Location = New-Object System.Drawing.Point(10, 90)
    $cboComponents.Items.Add("ServerAndClient")
    $cboComponents.Items.Add("ServerOnly")
    $cboComponents.Items.Add("ClientOnly")
    # Standard-Auswahl = "ServerAndClient"
    $cboComponents.SelectedIndex = 0
    $form.Controls.Add($cboComponents)

    # --- Label & ComboBox: Release / Beta ---
    $lblInstallerType = New-Object System.Windows.Forms.Label
    $lblInstallerType.Text = "Release- oder Beta-Version?"
    $lblInstallerType.AutoSize = $true
    $lblInstallerType.Location = New-Object System.Drawing.Point(10, 130)
    $form.Controls.Add($lblInstallerType)

    $cboInstallerType = New-Object System.Windows.Forms.ComboBox
    $cboInstallerType.DropDownStyle = "DropDownList"
    $cboInstallerType.Width = 120
    $cboInstallerType.Location = New-Object System.Drawing.Point(10, 150)
    $cboInstallerType.Items.Add("Release")
    $cboInstallerType.Items.Add("Beta")
    $cboInstallerType.SelectedIndex = 0
    $form.Controls.Add($cboInstallerType)

    # --- Buttons: OK / Abbrechen ---
    $okButton = New-Object System.Windows.Forms.Button
    $okButton.Text = "OK"
    $okButton.Width = 80
    $okButton.Location = New-Object System.Drawing.Point(10, 200)
    $form.Controls.Add($okButton)

    $cancelButton = New-Object System.Windows.Forms.Button
    $cancelButton.Text = "Abbrechen"
    $cancelButton.Width = 80
    $cancelButton.Location = New-Object System.Drawing.Point(100, 200)
    $form.Controls.Add($cancelButton)

    $script:FormResult = $null

    # --- Event: OK-Button ---
    $okButton.Add_Click({
        $result = [PSCustomObject]@{
            InstallPath   = $txtInstallPath.Text
            Components    = $cboComponents.SelectedItem
            InstallerType = $cboInstallerType.SelectedItem
        }
        $script:FormResult = $result
        $form.Close()
    })

    # --- Event: Abbrechen-Button ---
    $cancelButton.Add_Click({
        # Wir geben $null zurück und schließen die Form
        $script:FormResult = $null
        $form.Close()
    })

    [void]$form.ShowDialog()
    return $script:FormResult
}

############################################################################
# 5) Konsolen-Fallback-Funktion (Read-Host)
############################################################################
function Show-InstallConsole {
    param(
        [string]$DefaultInstallPath = "C:\PhySonix\Install"
    )

    Write-Host "=== Konsolenmodus ==="

    $obj = [PSCustomObject]@{
        InstallPath   = $DefaultInstallPath
        Components    = "ServerAndClient"
        InstallerType = "Release"
    }

    # InstallPath
    $installPathInput = Read-Host "Bitte geben Sie das Download- und Arbeitsverzeichnis an (Standard: $($DefaultInstallPath))"
    if (-not [string]::IsNullOrWhiteSpace($installPathInput)) {
        $obj.InstallPath = $installPathInput
    }

    # Components
    Write-Host "1) ServerAndClient (Standard)"
    Write-Host "2) ServerOnly"
    Write-Host "3) ClientOnly"
    $compInput = Read-Host "Bitte Auswahl eingeben (1/2/3)"
    switch ($compInput) {
        {$_ -eq "" -or $_ -eq "1"} { $obj.Components = "ServerAndClient" }
        "2"                         { $obj.Components = "ServerOnly" }
        "3"                         { $obj.Components = "ClientOnly" }
        default {
            Write-Error "Ungültige Auswahl."
            exit 1
        }
    }

    # InstallerType
    Write-Host "1) Release (Standard)"
    Write-Host "2) Beta"
    $typeInput = Read-Host "Bitte Auswahl eingeben (1/2)"
    switch ($typeInput) {
        {$_ -eq "" -or $_ -eq "1"} { $obj.InstallerType = "Release" }
        "2"                         { $obj.InstallerType = "Beta" }
        default {
            Write-Error "Ungültige Auswahl."
            exit 1
        }
    }

    return $obj
}

############################################################################
# 6) Ermittlung der finalen Parameter (GUI / Konsole / Direkt)
############################################################################

if ($paramModeActive) {
    # --- Direkte Parameter-Übergabe ---
    Write-Host "Parameter-Modus erkannt. Verwende übergebene Werte:"
    Write-Host "InstallPath   = $InstallPath"
    Write-Host "Components    = $Components"
    Write-Host "InstallerType = $InstallerType"
}
else {
    # --- Keine Parameter => GUI oder Konsole ---
    if ($useGui) {
        Write-Host "GUI-Modus wird verwendet..."
        $uiResult = Show-InstallUI

        # 1) Prüfung: Hat der/die Benutzer*in auf Abbrechen geklickt?
        if (-not $uiResult) {
            Write-Host "Installation abgebrochen (GUI)."
            [System.Windows.Forms.Application]::Exit()
            exit 0
        }
        # 2) Prüfung: Sind irgendwelche Felder leer?
        elseif (
            [string]::IsNullOrWhiteSpace($uiResult.InstallPath)   -or
            [string]::IsNullOrWhiteSpace($uiResult.Components)    -or
            [string]::IsNullOrWhiteSpace($uiResult.InstallerType)
        ) {
            Write-Host "Installation abgebrochen: Mindestens ein Feld wurde leer gelassen."
            [System.Windows.Forms.Application]::Exit()
            exit 0
        }

        # Werte übernehmen
        $InstallPath   = $uiResult.InstallPath
        $Components    = $uiResult.Components
        $InstallerType = $uiResult.InstallerType
    }
    else {
        Write-Host "Konsolen-Modus wird verwendet..."
        $consoleResult = Show-InstallConsole
        if (-not $consoleResult) {
            Write-Host "Installation abgebrochen (Konsole)."
            exit 0
        }
        elseif (
            [string]::IsNullOrWhiteSpace($consoleResult.InstallPath)   -or
            [string]::IsNullOrWhiteSpace($consoleResult.Components)    -or
            [string]::IsNullOrWhiteSpace($consoleResult.InstallerType)
        ) {
            Write-Host "Installation abgebrochen: Mindestens ein Feld wurde leer gelassen."
            exit 0
        }

        $InstallPath   = $consoleResult.InstallPath
        $Components    = $consoleResult.Components
        $InstallerType = $consoleResult.InstallerType
    }
}

############################################################################
# 7) Haupt-Logik: Download, Entpacken, Installieren
############################################################################

Write-Host "`n=== INSTALLATION START ==="
Write-Host "InstallPath   = $InstallPath"
Write-Host "Components    = $Components"
Write-Host "InstallerType = $InstallerType"
Write-Host "================================`n"

# Pfad anlegen (falls nicht vorhanden)
if (-not (Test-Path $InstallPath)) {
    New-Item -ItemType Directory -Path $InstallPath -Force | Out-Null
}

# URLs definieren
$releaseUrls = @{
    Server = "https://physonix.blob.core.windows.net/downloads/updates/easy-connect-server/PhySonix%20Easy%20Connect%20Server%20Installer.zip"
    Client = "https://physonix.blob.core.windows.net/downloads/updates/easy-connect/PhySonix%20Easy%20Connect%20Installer.zip"
}
$betaUrls = @{
    Server = "https://physonix.blob.core.windows.net/downloads/updates/easy-connect-server/PhySonix%20Easy%20Connect%20Server%20Installer%20(Beta).zip"
    Client = "https://physonix.blob.core.windows.net/downloads/updates/easy-connect/PhySonix%20Easy%20Connect%20Installer%20(Beta).zip"
}

switch ($InstallerType) {
    "Release" { $urls = $releaseUrls; Write-Host "Release-Version ausgewählt." }
    "Beta"    { $urls = $betaUrls;    Write-Host "Beta-Version ausgewählt."    }
}

# Welche Komponenten sollen installiert werden?
switch ($Components) {
    "ServerAndClient" {
        $installServer = $true
        $installClient = $true
    }
    "ServerOnly" {
        $installServer = $true
        $installClient = $false
    }
    "ClientOnly" {
        $installServer = $false
        $installClient = $true
    }
}

# Entpackpfad
$extractPath = Join-Path -Path $InstallPath -ChildPath "PhySonix Easy Connect Extracted"
if (Test-Path $extractPath) {
    Remove-Item -Path "$extractPath\*" -Recurse -Force -ErrorAction SilentlyContinue
} else {
    New-Item -ItemType Directory -Path $extractPath -Force | Out-Null
}

# Download-Funktion
function Download-File {
    param (
        [string]$url,
        [string]$outputPath
    )
    try {
        Write-Host "Lade Datei herunter von: $url"
        Invoke-WebRequest -Uri $url -OutFile $outputPath -ErrorAction Stop
        Write-Host "Datei erfolgreich heruntergeladen: $outputPath"
    }
    catch {
        Write-Error "Fehler beim Herunterladen: $url - $_"
        exit 1
    }
}

# Entpack-Funktion
function Extract-Zip {
    param (
        [string]$zipFilePath,
        [string]$destinationPath
    )
    try {
        Write-Host "Entpacke Datei: $zipFilePath nach $destinationPath"
        Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
        [System.IO.Compression.ZipFile]::ExtractToDirectory($zipFilePath, $destinationPath)
        Write-Host "Datei erfolgreich entpackt: $zipFilePath"
        Remove-Item -Path $zipFilePath -Force
        Write-Host "ZIP-Datei gelöscht: $zipFilePath"
    }
    catch {
        Write-Error "Fehler beim Entpacken: $zipFilePath - $_"
        exit 1
    }
}

# MSI-Installation
function Install-MSI {
    param (
        [string]$msiFilePath
    )
    try {
        Write-Host "Starte Installation der MSI: $msiFilePath"
        $process = Start-Process -FilePath $msiFilePath -ArgumentList "/quiet" -PassThru -ErrorAction Stop
        $process.WaitForExit()
        if ($process.ExitCode -eq 0) {
            Write-Host "Installation erfolgreich: $msiFilePath"
        }
        else {
            Write-Warning "Fehler bei der Installation: $msiFilePath (Exit-Code: $($process.ExitCode))"
        }
    }
    catch {
        Write-Error "Fehler beim Installieren der MSI-Datei: $msiFilePath - $_"
    }
}

# == Server-Installation ==
if ($installServer) {
    $zipFile = Join-Path -Path $InstallPath -ChildPath "PhySonix Easy Connect Server.zip"
    Download-File -url $urls["Server"] -outputPath $zipFile
    Extract-Zip -zipFilePath $zipFile -destinationPath $extractPath

    $serverMsi = Get-ChildItem -Path $extractPath -Filter "*.msi" `
                 | Where-Object { $_.Name -match "Server" } `
                 | Select-Object -First 1

    if ($serverMsi) {
        Write-Host "Stoppe ggf. vorhandenen Dienst 'PhySonixEasyConnectServer'..."
        Stop-Service -Name "PhySonixEasyConnectServer" -ErrorAction SilentlyContinue
        Install-MSI -msiFilePath $serverMsi.FullName
    }
    else {
        Write-Warning "Server-MSI-Datei nicht gefunden."
    }
}

# == Client-Installation ==
if ($installClient) {
    $zipFile = Join-Path -Path $InstallPath -ChildPath "PhySonix Easy Connect Client.zip"
    Download-File -url $urls["Client"] -outputPath $zipFile
    Extract-Zip -zipFilePath $zipFile -destinationPath $extractPath

    $clientMsi = Get-ChildItem -Path $extractPath -Filter "*.msi" `
                 | Where-Object { $_.Name -match "Client|Easy Connect" } `
                 | Select-Object -First 1
    if ($clientMsi) {
        Install-MSI -msiFilePath $clientMsi.FullName
    }
    else {
        Write-Warning "Client-MSI-Datei nicht gefunden."
    }
}

Write-Host "`nSkript abgeschlossen."