bin/Public/Install-sqmSsrsReportServer.ps1

<#
.SYNOPSIS
    Installiert SQL Server Reporting Services 2022 von einem Network Share
    und konfiguriert die Instanz anschliessend vollautomatisch.

.DESCRIPTION
    Fuehrt folgende Schritte der Reihe nach aus:

    [1] Voraussetzungen pruefen
        - Administratorrechte auf dem Zielrechner
        - Installer (.exe oder .msi) im konfigurierten Share (SsrsInstallerPath) auffindbar
        - SSRS noch nicht installiert (ueberspringbar mit -Force)

    [2] Installation
        - Kopiert den Installer in ein lokales Temp-Verzeichnis (UNC-Pfade werden
          nicht direkt als Prozess-Start unterstuetzt)
        - Fuehrt den Installer silent aus:
            SQLServerReportingServices.exe
                /quiet /IAcceptLicenseTerms /Edition=<Edition> /IAcceptLicenseTerms
        - Wertet den Exit Code aus (0 = OK, 3010 = Neustart empfohlen)
        - Wartet danach bis zu 60 Sekunden auf den SSRS-WMI-Namespace (Dienst-Startup)

    [3] Konfiguration
        - Ruft Set-sqmSsrsConfiguration mit allen uebergebenen Konfigurations-
          Parametern auf (Splatting). Nicht uebergebene Parameter verwenden die
          Standardwerte von Set-sqmSsrsConfiguration.

    Der Installer-Pfad wird bevorzugt aus dem Parameter -InstallerPath gelesen.
    Fehlt der Parameter, wird Get-sqmConfig -Key 'SsrsInstallerPath' verwendet.
    Ist auch dieser nicht gesetzt, wird ein Fehler ausgeloest.

.PARAMETER ComputerName
    Zielrechner. Standard: $env:COMPUTERNAME (Lokal).
    Remote-Installation via WinRM / PsRemoting wird unterstuetzt.

.PARAMETER InstallerPath
    Vollstaendiger UNC- oder lokaler Pfad zur Installationsdatei
    (SQLServerReportingServices.exe oder .msi).
    ueberschreibt Get-sqmConfig -Key 'SsrsInstallerPath'.

.PARAMETER Edition
    Lizenz-Edition fuer den Silent-Parameter /Edition.
    Gueltige Werte: Eval, Developer, Expr, Web, Standard, Enterprise.
    Standard: 'Developer'.

.PARAMETER ProductKey
    Produktschluessel (25 Zeichen). Wenn angegeben, wird statt -Edition der
    Parameter /IAcceptLicenseTerms /PID:<Key> verwendet.

.PARAMETER Force
    Installation auch dann durchfuehren, wenn SSRS bereits installiert ist.

.PARAMETER SkipConfiguration
    Nur installieren, Set-sqmSsrsConfiguration nicht aufrufen.

.PARAMETER InstanceName
    SSRS-Instanzname. Wird an Set-sqmSsrsConfiguration weitergereicht.
    Standard: 'MSSQLSERVER'.

.PARAMETER DatabaseServer
    SQL Server fuer die ReportServer-Datenbank.
    Wird an Set-sqmSsrsConfiguration weitergereicht.

.PARAMETER DatabaseName
    Name der ReportServer-Datenbank. Standard: 'ReportServer'.

.PARAMETER ReportServerUrl
    URL fuer den ReportServer Web Service.
    Standard: 'http://+:80/ReportServer'.

.PARAMETER ReportsUrl
    URL fuer das Reports-Portal. Standard: 'http://+:80/Reports'.

.PARAMETER ServiceAccount
    Windows-Dienstkonto fuer SSRS.

.PARAMETER ServiceAccountPassword
    Kennwort fuer -ServiceAccount (SecureString).

.PARAMETER DatabaseAuthType
    Authentifizierung fuer die DB-Verbindung: 'Windows' oder 'SQL'.

.PARAMETER DatabaseCredential
    PSCredential fuer SQL-Authentifizierung (nur bei -DatabaseAuthType SQL).

.PARAMETER EncryptionKeyFile
    Pfad fuer das Encryption Key Backup (.snk).

.PARAMETER EncryptionKeyPassword
    Kennwort fuer das Key Backup (SecureString).

.PARAMETER SkipDatabase
    Datenbankkonfiguration in Set-sqmSsrsConfiguration ueberspringen.

.PARAMETER SkipUrls
    URL-Konfiguration in Set-sqmSsrsConfiguration ueberspringen.

.PARAMETER SkipServiceAccount
    Dienstkonto-Konfiguration in Set-sqmSsrsConfiguration ueberspringen.

.PARAMETER SkipEncryptionKeyBackup
    Key-Backup in Set-sqmSsrsConfiguration ueberspringen.

.PARAMETER Credential
    PSCredential fuer die WinRM-Verbindung zum Zielrechner (Remote-Betrieb).

.PARAMETER OutputPath
    Ausgabeverzeichnis fuer den Konfigurationsbericht.

.PARAMETER WmiWaitSeconds
    Maximale Wartezeit in Sekunden auf den SSRS-WMI-Namespace nach der
    Installation. Standard: 60.

.PARAMETER ContinueOnError
    Konfigurationsfehler nicht als Abbruch werten.

.PARAMETER EnableException
    Ausnahmen sofort ausloesen.

.OUTPUTS
    [PSCustomObject] mit den Feldern:
        ComputerName, InstallerUsed, Edition, InstallExitCode,
        RebootRequired, InstallResult, ConfigResult, OverallStatus, Message

.EXAMPLE
    Install-sqmSsrsReportServer

    Installiert SSRS mit dem in sqmConfig hinterlegten Installer-Pfad,
    Edition Developer, anschliessend Vollkonfiguration mit Standardwerten.

.EXAMPLE
    Install-sqmSsrsReportServer `
        -InstallerPath '\\srv-share\Software\SSRS2022\SQLServerReportingServices.exe' `
        -Edition Standard `
        -DatabaseServer 'SQL-AG-Listener' `
        -ServiceAccount 'DOMAIN\svc_ssrs' `
        -EncryptionKeyPassword (Read-Host -AsSecureString 'Key-Passwort')

.EXAMPLE
    Install-sqmSsrsReportServer -SkipConfiguration -WhatIf

    Zeigt, was installiert wuerde, ohne aenderungen vorzunehmen.

.NOTES
    Voraussetzungen : Invoke-sqmLogging, Set-sqmSsrsConfiguration, lokale Adminrechte
    Unterstuetzte Versionen: SSRS 2022 (SQLServerReportingServices.exe)
    Exit Codes : 0 = Erfolg, 3010 = Neustart empfohlen, sonstige = Fehler
    WMI-Namespace : root\Microsoft\SqlServer\ReportServer
#>

function Install-sqmSsrsReportServer
{
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    [OutputType([PSCustomObject])]
    param (
        # ?? Zielrechner ????????????????????????????????????????????????????
        [Parameter(Mandatory = $false)]
        [string]$ComputerName = $env:COMPUTERNAME,

        # ?? Installer-Quelle ???????????????????????????????????????????????
        [Parameter(Mandatory = $false)]
        [string]$InstallerPath,

        [Parameter(Mandatory = $false)]
        [ValidateSet('Eval', 'Developer', 'Expr', 'Web', 'Standard', 'Enterprise')]
        [string]$Edition = 'Developer',

        [Parameter(Mandatory = $false)]
        [string]$ProductKey,

        # ?? Installations-Steuerung ????????????????????????????????????????
        [Parameter(Mandatory = $false)]
        [switch]$Force,

        [Parameter(Mandatory = $false)]
        [switch]$SkipConfiguration,

        [Parameter(Mandatory = $false)]
        [int]$WmiWaitSeconds = 60,

        # ?? Konfigurations-Parameter (Durchreich an Set-sqmSsrsConfiguration) ??
        [Parameter(Mandatory = $false)]
        [string]$InstanceName = 'MSSQLSERVER',

        [Parameter(Mandatory = $false)]
        [string]$DatabaseServer,

        [Parameter(Mandatory = $false)]
        [string]$DatabaseName = 'ReportServer',

        [Parameter(Mandatory = $false)]
        [string]$ReportServerUrl = 'http://+:80/ReportServer',

        [Parameter(Mandatory = $false)]
        [string]$ReportsUrl = 'http://+:80/Reports',

        [Parameter(Mandatory = $false)]
        [string]$ServiceAccount,

        [Parameter(Mandatory = $false)]
        [System.Security.SecureString]$ServiceAccountPassword,

        [Parameter(Mandatory = $false)]
        [ValidateSet('Windows', 'SQL')]
        [string]$DatabaseAuthType = 'Windows',

        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]$DatabaseCredential,

        [Parameter(Mandatory = $false)]
        [string]$EncryptionKeyFile,

        [Parameter(Mandatory = $false)]
        [System.Security.SecureString]$EncryptionKeyPassword,

        [Parameter(Mandatory = $false)]
        [switch]$SkipDatabase,

        [Parameter(Mandatory = $false)]
        [switch]$SkipUrls,

        [Parameter(Mandatory = $false)]
        [switch]$SkipServiceAccount,

        [Parameter(Mandatory = $false)]
        [switch]$SkipEncryptionKeyBackup,

        # ?? Verbindung / Ausgabe ???????????????????????????????????????????
        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]$Credential,

        [Parameter(Mandatory = $false)]
        [string]$OutputPath = (Get-sqmConfig -Key 'OutputPath'),

        # ?? Fehlerbehandlung ???????????????????????????????????????????????
        [Parameter(Mandatory = $false)]
        [switch]$ContinueOnError,

        [Parameter(Mandatory = $false)]
        [switch]$EnableException
    )

    begin
    {
        $functionName = $MyInvocation.MyCommand.Name
        $isLocal      = $ComputerName -in @($env:COMPUTERNAME, 'localhost', '127.0.0.1', '.')

        # ?? Rueckgabe-Objekt vorab befuellen ?????????????????????????????????
        $result = [PSCustomObject]@{
            ComputerName     = $ComputerName
            InstallerUsed    = $null
            Edition          = $Edition
            InstallExitCode  = $null
            RebootRequired   = $false
            InstallResult    = 'NotStarted'
            ConfigResult     = 'Skipped'
            OverallStatus    = 'Unknown'
            Message          = $null
        }

        # ?? Hilfsfunktion: einheitliches Fehlerhandling ???????????????????
        function _Fail ([string]$msg)
        {
            Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'ERROR'
            $result.OverallStatus = 'Failed'
            $result.Message       = $msg
            if ($EnableException) { throw $msg }
            Write-Error $msg
            return $result
        }

        Invoke-sqmLogging -Message "Starte $functionName auf '$ComputerName'" `
                          -FunctionName $functionName -Level 'INFO'
    }

    process
    {
        # ??????????????????????????????????????????????????????????????????
        # [1] Installer-Pfad aufloesen
        # ??????????????????????????????????????????????????????????????????
        $effectiveInstaller = $InstallerPath
        if (-not $effectiveInstaller)
        {
            $effectiveInstaller = Get-sqmConfig -Key 'SsrsInstallerPath'
        }

        if ([string]::IsNullOrWhiteSpace($effectiveInstaller))
        {
            return (_Fail ("Kein Installer-Pfad angegeben und 'SsrsInstallerPath' ist nicht in der " +
                           "Modulkonfiguration gesetzt. Bitte -InstallerPath angeben oder " +
                           "Set-sqmConfig -SsrsInstallerPath '<UNC-Pfad>' ausfuehren."))
        }

        $installerExtension = [System.IO.Path]::GetExtension($effectiveInstaller).ToLower()
        if ($installerExtension -notin @('.exe', '.msi'))
        {
            return (_Fail "Installer-Datei '$effectiveInstaller' hat keine unterstuetzte Erweiterung (.exe / .msi).")
        }

        if (-not (Test-Path -LiteralPath $effectiveInstaller))
        {
            return (_Fail "Installer-Datei nicht erreichbar: '$effectiveInstaller'")
        }

        $result.InstallerUsed = $effectiveInstaller
        Invoke-sqmLogging -Message "Installer: '$effectiveInstaller'" `
                          -FunctionName $functionName -Level 'INFO'

        # ??????????????????????????????????????????????????????????????????
        # [2] Voraussetzungen pruefen
        # ??????????????????????????????????????????????????????????????????

        # 2a. Administratorrechte (nur bei lokaler Ausfuehrung direkt pruefbar)
        if ($isLocal)
        {
            $principal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
            if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
            {
                return (_Fail "Keine lokalen Administratorrechte - Installation nicht moeglich. PowerShell als Administrator starten.")
            }
        }

        # 2b. Ist SSRS bereits installiert?
        $ssrsAlreadyInstalled = $false
        try
        {
            $cimParams = @{ Namespace = 'root\Microsoft\SqlServer\ReportServer'; ErrorAction = 'Stop' }
            if (-not $isLocal)
            {
                $sessionOpts         = New-CimSessionOption -Protocol Wsman
                $cimConnParams       = @{ ComputerName = $ComputerName; SessionOption = $sessionOpts }
                if ($Credential) { $cimConnParams['Credential'] = $Credential }
                $checkSession        = New-CimSession @cimConnParams -ErrorAction Stop
                $cimParams['CimSession'] = $checkSession
            }
            $nsCheck = Get-CimInstance @cimParams -ClassName '__NAMESPACE' -ErrorAction SilentlyContinue
            $ssrsAlreadyInstalled = $null -ne $nsCheck
            if (isset $checkSession) { Remove-CimSession $checkSession -ErrorAction SilentlyContinue }
        }
        catch
        {
            # Namespace nicht vorhanden = SSRS nicht installiert, das ist der Normalfall
            $ssrsAlreadyInstalled = $false
        }

        if ($ssrsAlreadyInstalled -and -not $Force)
        {
            $msg = "SSRS ist auf '$ComputerName' bereits installiert. " +
                   "Verwenden Sie -Force um die Installation trotzdem durchzufuehren."
            Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'WARNING'
            Write-Warning $msg
            $result.InstallResult = 'AlreadyInstalled'
            $result.OverallStatus = 'AlreadyInstalled'
            $result.Message       = $msg

            # Wenn SSRS schon da und SkipConfiguration nicht gesetzt:
            # direkt zur Konfiguration springen
            if (-not $SkipConfiguration)
            {
                Invoke-sqmLogging -Message "ueberspringe Installation - fahre direkt mit Konfiguration fort." `
                                  -FunctionName $functionName -Level 'INFO'
                # Goto Konfigurations-Block (ueber $skipInstall-Flag)
            }
            else
            {
                return $result
            }
        }

        # ??????????????????????????????????????????????????????????????????
        # [3] Installation
        # ??????????????????????????????????????????????????????????????????
        $skipInstall = ($ssrsAlreadyInstalled -and -not $Force)

        if (-not $skipInstall)
        {
            if ($PSCmdlet.ShouldProcess($ComputerName, "SSRS 2022 installieren von '$effectiveInstaller'"))
            {
                try
                {
                    # Installer in lokales Temp kopieren
                    # (UNC-Pfade koennen nicht direkt als Prozess gestartet werden)
                    $tempDir       = Join-Path $env:TEMP "SsrsInstall_$(Get-Random)"
                    $tempInstaller = Join-Path $tempDir ([System.IO.Path]::GetFileName($effectiveInstaller))
                    New-Item -ItemType Directory -Path $tempDir -Force | Out-Null

                    Invoke-sqmLogging -Message "Kopiere Installer nach '$tempInstaller'..." `
                                      -FunctionName $functionName -Level 'INFO'
                    Write-Host " [1/2] Installer kopieren von Share..." -ForegroundColor Gray
                    Copy-Item -LiteralPath $effectiveInstaller -Destination $tempInstaller -Force -ErrorAction Stop

                    # Silent-Parameter zusammenstellen
                    # SSRS 2022 EXE: /quiet /IAcceptLicenseTerms /Edition=<X>
                    # SSRS 2022 MSI: /quiet /norestart IACCEPTLICENSETERMS=YES
                    $isMsi = $installerExtension -eq '.msi'

                    if ($isMsi)
                    {
                        $installArgs = @(
                            '/i', "`"$tempInstaller`"",
                            '/quiet',
                            '/norestart',
                            'IACCEPTLICENSETERMS=YES'
                        )
                        if ($ProductKey)
                        {
                            $installArgs += "PIDKEY=$ProductKey"
                        }
                        else
                        {
                            $installArgs += "EDITION=$Edition"
                        }
                        $installExe = 'msiexec.exe'
                    }
                    else
                    {
                        $installArgs = @(
                            '/quiet',
                            '/IAcceptLicenseTerms',
                            '/norestart'
                        )
                        if ($ProductKey)
                        {
                            $installArgs += "/PID=$ProductKey"
                        }
                        else
                        {
                            $installArgs += "/Edition=$Edition"
                        }
                        $installExe = $tempInstaller
                    }

                    $argString = $installArgs -join ' '
                    Invoke-sqmLogging -Message "Starte Installation: $installExe $argString" `
                                      -FunctionName $functionName -Level 'INFO'
                    Write-Host " [2/2] SSRS installieren (silent)..." -ForegroundColor Gray

                    $proc = Start-Process -FilePath $installExe `
                                         -ArgumentList $installArgs `
                                         -Wait -PassThru -NoNewWindow `
                                         -ErrorAction Stop

                    $result.InstallExitCode = $proc.ExitCode

                    switch ($proc.ExitCode)
                    {
                        0
                        {
                            $result.InstallResult  = 'OK'
                            $result.RebootRequired = $false
                            Write-Host " ? SSRS installiert (ExitCode 0)." -ForegroundColor Green
                            Invoke-sqmLogging -Message "Installation erfolgreich (ExitCode 0)." `
                                              -FunctionName $functionName -Level 'INFO'
                        }
                        3010
                        {
                            $result.InstallResult  = 'OK'
                            $result.RebootRequired = $true
                            Write-Host " ? SSRS installiert (ExitCode 3010 - Neustart empfohlen)." -ForegroundColor Yellow
                            Write-Warning "SSRS wurde installiert, ein Neustart wird empfohlen."
                            Invoke-sqmLogging -Message "Installation erfolgreich, Neustart empfohlen (ExitCode 3010)." `
                                              -FunctionName $functionName -Level 'WARNING'
                        }
                        default
                        {
                            throw "Installer beendet mit ExitCode $($proc.ExitCode). Installation fehlgeschlagen."
                        }
                    }
                }
                catch
                {
                    $errMsg = "Installations-Fehler: $($_.Exception.Message)"
                    Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level 'ERROR'
                    $result.InstallResult = 'Failed'
                    $result.OverallStatus = 'Failed'
                    $result.Message       = $errMsg
                    if ($EnableException) { throw }
                    Write-Error $errMsg
                    return $result
                }
                finally
                {
                    if (Test-Path $tempDir)
                    {
                        Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue
                    }
                }

                # ?? WMI-Namespace abwarten ????????????????????????????????
                # SSRS-Dienst braucht nach dem Installer-Start einige Sekunden
                # bis der WMI-Provider registriert ist.
                Invoke-sqmLogging -Message "Warte auf SSRS-WMI-Namespace (max. $WmiWaitSeconds s)..." `
                                  -FunctionName $functionName -Level 'INFO'
                Write-Host " Warte auf SSRS-WMI-Namespace..." -ForegroundColor Gray

                $wmiReady    = $false
                $waitStart   = [datetime]::UtcNow
                $wmiNs       = 'root\Microsoft\SqlServer\ReportServer'
                $wmiPollBase = @{ Namespace = $wmiNs; ClassName = '__NAMESPACE'; ErrorAction = 'SilentlyContinue' }
                if (-not $isLocal -and $checkSession)
                {
                    $wmiPollBase['CimSession'] = $checkSession
                }

                while (-not $wmiReady -and ([datetime]::UtcNow - $waitStart).TotalSeconds -lt $WmiWaitSeconds)
                {
                    Start-Sleep -Seconds 3
                    try
                    {
                        $ns      = Get-CimInstance @wmiPollBase
                        $wmiReady = $null -ne $ns
                    }
                    catch { $wmiReady = $false }
                }

                if (-not $wmiReady)
                {
                    $warnMsg = "SSRS-WMI-Namespace nach $WmiWaitSeconds s noch nicht vorhanden. " +
                               "Konfiguration wird trotzdem versucht."
                    Invoke-sqmLogging -Message $warnMsg -FunctionName $functionName -Level 'WARNING'
                    Write-Warning $warnMsg
                }
                else
                {
                    Invoke-sqmLogging -Message "SSRS-WMI-Namespace verfuegbar nach $([int]([datetime]::UtcNow - $waitStart).TotalSeconds) s." `
                                      -FunctionName $functionName -Level 'INFO'
                    Write-Host " ? SSRS-WMI-Namespace bereit." -ForegroundColor Green
                }
            }
            else
            {
                # WhatIf-Pfad
                $result.InstallResult = 'WhatIf'
                Invoke-sqmLogging -Message "WhatIf: Installation wuerde gestartet werden." `
                                  -FunctionName $functionName -Level 'INFO'
            }
        }

        # ??????????????????????????????????????????????????????????????????
        # [4] Konfiguration via Set-sqmSsrsConfiguration
        # ??????????????????????????????????????????????????????????????????
        if ($SkipConfiguration)
        {
            $result.ConfigResult  = 'Skipped'
            $result.OverallStatus = $result.InstallResult
            $result.Message       = "Installation: $($result.InstallResult) | Konfiguration: uebersprungen (-SkipConfiguration)."
            Invoke-sqmLogging -Message $result.Message -FunctionName $functionName -Level 'INFO'
            return $result
        }

        if ($result.InstallResult -eq 'WhatIf')
        {
            $result.ConfigResult  = 'WhatIf'
            $result.OverallStatus = 'WhatIf'
            $result.Message       = 'WhatIf: Installation und Konfiguration wuerden durchgefuehrt.'
            return $result
        }

        Write-Host ""
        Write-Host "[$ComputerName] Starte SSRS-Konfiguration..." -ForegroundColor Cyan
        Invoke-sqmLogging -Message "Starte Set-sqmSsrsConfiguration auf '$ComputerName'." `
                          -FunctionName $functionName -Level 'INFO'

        # Nur explizit uebergebene Parameter weiterreichen (kein ueberschreiben der
        # Standardwerte in Set-sqmSsrsConfiguration durch leere Werte)
        $configSplat = @{
            ComputerName   = $ComputerName
            InstanceName   = $InstanceName
            DatabaseName   = $DatabaseName
            ReportServerUrl = $ReportServerUrl
            ReportsUrl     = $ReportsUrl
            DatabaseAuthType = $DatabaseAuthType
        }

        if ($PSBoundParameters.ContainsKey('DatabaseServer')          -and $DatabaseServer)          { $configSplat['DatabaseServer']          = $DatabaseServer }
        if ($PSBoundParameters.ContainsKey('ServiceAccount')          -and $ServiceAccount)          { $configSplat['ServiceAccount']          = $ServiceAccount }
        if ($PSBoundParameters.ContainsKey('ServiceAccountPassword')  -and $ServiceAccountPassword)  { $configSplat['ServiceAccountPassword']  = $ServiceAccountPassword }
        if ($PSBoundParameters.ContainsKey('DatabaseCredential')      -and $DatabaseCredential)      { $configSplat['DatabaseCredential']      = $DatabaseCredential }
        if ($PSBoundParameters.ContainsKey('EncryptionKeyFile')       -and $EncryptionKeyFile)       { $configSplat['EncryptionKeyFile']       = $EncryptionKeyFile }
        if ($PSBoundParameters.ContainsKey('EncryptionKeyPassword')   -and $EncryptionKeyPassword)   { $configSplat['EncryptionKeyPassword']   = $EncryptionKeyPassword }
        if ($PSBoundParameters.ContainsKey('Credential')              -and $Credential)              { $configSplat['Credential']              = $Credential }
        if ($PSBoundParameters.ContainsKey('OutputPath')              -and $OutputPath)              { $configSplat['OutputPath']              = $OutputPath }

        # Skip-Schalter
        if ($SkipDatabase)            { $configSplat['SkipDatabase']            = $true }
        if ($SkipUrls)                { $configSplat['SkipUrls']                = $true }
        if ($SkipServiceAccount)      { $configSplat['SkipServiceAccount']      = $true }
        if ($SkipEncryptionKeyBackup) { $configSplat['SkipEncryptionKeyBackup'] = $true }
        if ($ContinueOnError)         { $configSplat['ContinueOnError']         = $true }
        if ($EnableException)         { $configSplat['EnableException']         = $true }

        try
        {
            $configResult = Set-sqmSsrsConfiguration @configSplat
            $result.ConfigResult = $configResult.OverallStatus

            $result.OverallStatus = switch ($true)
            {
                ($result.InstallResult -in @('OK', 'AlreadyInstalled') -and
                 $configResult.OverallStatus -eq 'Success')            { 'Success' }
                ($configResult.OverallStatus -eq 'PartialSuccess')     { 'PartialSuccess' }
                default                                                 { 'Failed' }
            }

            $result.Message = "Installation: $($result.InstallResult) | " +
                              "Konfiguration: $($configResult.OverallStatus) | " +
                              $configResult.Message
        }
        catch
        {
            $errMsg = "Konfigurationsfehler: $($_.Exception.Message)"
            Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level 'ERROR'
            $result.ConfigResult  = 'Failed'
            $result.OverallStatus = 'PartialSuccess'   # Installiert, aber Konfig fehlgeschlagen
            $result.Message       = "Installation: $($result.InstallResult) | Konfiguration: Failed | $errMsg"
            if ($EnableException) { throw }
            Write-Error $errMsg
        }

        Write-Host ""
        Write-Host "[$ComputerName] $functionName : $($result.OverallStatus)" `
                   -ForegroundColor $(if ($result.OverallStatus -eq 'Success') { 'Green' } else { 'Yellow' })

        return $result
    }
}