Public/Set-sqmConfig.ps1

<#
.SYNOPSIS
    Sets one or more configuration values for the MSSQLTools module.
 
.DESCRIPTION
    Allows setting of LogPath, OutputPath, CentralPath, Ola job names,
    TSM management classes, the HPU domain group mapping, and the
    SSRS installer path (SsrsInstallerPath).
    Each path is validated for existence or creatability.
    The configuration is permanently saved in a JSON file in the user profile.
 
.PARAMETER LogPath
    Directory for log files (Invoke-sqmLogging).
 
.PARAMETER OutputPath
    Default output directory for reports.
 
.PARAMETER CentralPath
    Optional central storage directory (additional copy).
 
.PARAMETER OlaJobNameFull
    Name of the full backup job for user databases.
 
.PARAMETER OlaJobNameDiff
    Name of the diff backup job for user databases.
 
.PARAMETER OlaJobNameLog
    Name of the log backup job for user databases.
 
.PARAMETER OlaJobNameIndexOpt
    Name of the IndexOptimize job.
 
.PARAMETER OlaJobNameIntUserDb
    Name of the IntegrityCheck job for user databases.
 
.PARAMETER OlaJobNameIntSysDb
    Name of the IntegrityCheck job for system databases.
 
.PARAMETER OlaJobNameSysDbBackup
    Name of the full backup job for system databases.
 
.PARAMETER TsmManagementClasses
    Array of valid TSM management classes (e.g. 'MC_B_NL.NL_42.42.NA').
 
.PARAMETER HpuDomainGroupMap
    Array of PSCustomObject with fields DomainPattern (wildcard) and GroupNamePattern
    (sAMAccountName suffix of the HPU allow group). Evaluated by Get-sqmHpuAllowGroup.
    Entries are checked in order; the first match wins.
    Example:
        Set-sqmConfig -HpuDomainGroupMap @(
            [PSCustomObject]@{ DomainPattern = 'bayernlb.sfinance.net'; GroupNamePattern = 'Fg_DC_AouAllowManageAuditSecLogSrvAll_Mod' },
            [PSCustomObject]@{ DomainPattern = '*.sfinance.net'; GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' },
            [PSCustomObject]@{ DomainPattern = '*'; GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' }
        )
 
.PARAMETER SsrsInstallerPath
    Full UNC or local path to the SSRS installer file
    (SQLServerReportingServices.exe or .msi).
    Used by Install-sqmSsrsReportServer when -InstallerPath is not specified.
    Example: '\\srv-share\Software\SSRS2022\SQLServerReportingServices.exe'
 
.PARAMETER Language
    Output language of the module. Allowed values: de-DE, en-US.
    Default: de-DE.
    Example: Set-sqmConfig -Language en-US
 
.PARAMETER PassThru
    Returns the updated configuration as an object.
 
.EXAMPLE
    Set-sqmConfig -LogPath "D:\Logs" -OlaJobNameFull "Prod-FULL"
 
.EXAMPLE
    Set-sqmConfig -TsmManagementClasses @('MC_10','MC_30','MC_100')
 
.EXAMPLE
    Set-sqmConfig -HpuDomainGroupMap @(
        [PSCustomObject]@{ DomainPattern = '*.sfinance.net'; GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' },
        [PSCustomObject]@{ DomainPattern = '*'; GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' }
    )
 
.EXAMPLE
    Set-sqmConfig -SsrsInstallerPath '\\srv-share\Software\SSRS2022\SQLServerReportingServices.exe'
#>

function Set-sqmConfig
{
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $false)]
        [string]$LogPath,
        [Parameter(Mandatory = $false)]
        [string]$OutputPath,
        [Parameter(Mandatory = $false)]
        [string]$CentralPath,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameFull,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameDiff,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameLog,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameIndexOpt,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameIntUserDb,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameIntSysDb,
        [Parameter(Mandatory = $false)]
        [string]$OlaJobNameSysDbBackup,
        [Parameter(Mandatory = $false)]
        [string[]]$TsmManagementClasses,
        [Parameter(Mandatory = $false)]
        [bool]$AutoUpdate,
        [Parameter(Mandatory = $false)]
        [string]$UpdateRepository,
        [Parameter(Mandatory = $false)]
        [string]$DefaultPolicy,
        [Parameter(Mandatory = $false)]
        [PSCustomObject[]]$HpuDomainGroupMap,
        [Parameter(Mandatory = $false)]
        [string]$SsrsInstallerPath,
        [Parameter(Mandatory = $false)]
        [ValidateSet('de-DE', 'en-US')]
        [string]$Language,
        [Parameter(Mandatory = $false)]
        [switch]$PassThru
    )
    
    # Hilfsfunktion zum Pruefen/Erstellen eines Pfads
    function Test-AndCreatePath($Path, $Purpose)
    {
        if (-not $Path) { return $true }
        if ($Path -match '^\s*$')
        {
            Write-Error "Pfad fuer $Purpose darf nicht leer sein."
            return $false
        }
        try
        {
            if (-not (Test-Path $Path))
            {
                New-Item -ItemType Directory -Path $Path -Force -ErrorAction Stop | Out-Null
                Write-Verbose "Verzeichnis '$Path' ($Purpose) wurde erstellt."
            }
            $testFile = Join-Path $Path "test_$(Get-Random).tmp"
            New-Item -ItemType File -Path $testFile -Force -ErrorAction Stop | Out-Null
            Remove-Item -Path $testFile -Force -ErrorAction Stop
            return $true
        }
        catch
        {
            Write-Error "Konnte Pfad '$Path' nicht fuer $Purpose verwenden: $($_.Exception.Message)"
            return $false
        }
    }
    
    $updated = $false
    $globalConfig = $script:sqmModuleConfig
    
    # Pfad-Parameter
    if ($PSBoundParameters.ContainsKey('LogPath'))
    {
        if (Test-AndCreatePath $LogPath "LogPath")
        {
            $globalConfig['LogPath'] = $LogPath
            $updated = $true
        }
        else { return }
    }
    if ($PSBoundParameters.ContainsKey('OutputPath'))
    {
        if (Test-AndCreatePath $OutputPath "OutputPath")
        {
            $globalConfig['OutputPath'] = $OutputPath
            $updated = $true
        }
        else { return }
    }
    if ($PSBoundParameters.ContainsKey('CentralPath'))
    {
        if ($CentralPath)
        {
            if (Test-AndCreatePath $CentralPath "CentralPath")
            {
                $globalConfig['CentralPath'] = $CentralPath
                $updated = $true
            }
            else { return }
        }
        else
        {
            $globalConfig['CentralPath'] = $null
            $updated = $true
        }
    }
    
    # Ola-Job-Namen
    if ($PSBoundParameters.ContainsKey('OlaJobNameFull'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameFull))
        {
            $globalConfig['OlaJobNameFull'] = $OlaJobNameFull
            $updated = $true
        }
        else { Write-Error "OlaJobNameFull darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameDiff'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameDiff))
        {
            $globalConfig['OlaJobNameDiff'] = $OlaJobNameDiff
            $updated = $true
        }
        else { Write-Error "OlaJobNameDiff darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameLog'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameLog))
        {
            $globalConfig['OlaJobNameLog'] = $OlaJobNameLog
            $updated = $true
        }
        else { Write-Error "OlaJobNameLog darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameIndexOpt'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameIndexOpt))
        {
            $globalConfig['OlaJobNameIndexOpt'] = $OlaJobNameIndexOpt
            $updated = $true
        }
        else { Write-Error "OlaJobNameIndexOpt darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameIntUserDb'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameIntUserDb))
        {
            $globalConfig['OlaJobNameIntUserDb'] = $OlaJobNameIntUserDb
            $updated = $true
        }
        else { Write-Error "OlaJobNameIntUserDb darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameIntSysDb'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameIntSysDb))
        {
            $globalConfig['OlaJobNameIntSysDb'] = $OlaJobNameIntSysDb
            $updated = $true
        }
        else { Write-Error "OlaJobNameIntSysDb darf nicht leer sein."; return }
    }
    if ($PSBoundParameters.ContainsKey('OlaJobNameSysDbBackup'))
    {
        if (-not [string]::IsNullOrWhiteSpace($OlaJobNameSysDbBackup))
        {
            $globalConfig['OlaJobNameSysDbBackup'] = $OlaJobNameSysDbBackup
            $updated = $true
        }
        else { Write-Error "OlaJobNameSysDbBackup darf nicht leer sein."; return }
    }
    
    # TSM Management-Klassen
    if ($PSBoundParameters.ContainsKey('TsmManagementClasses'))
    {
        if ($TsmManagementClasses -and $TsmManagementClasses.Count -gt 0)
        {
            $globalConfig['TsmManagementClasses'] = $TsmManagementClasses
            $updated = $true
        }
        else
        {
            Write-Error "TsmManagementClasses darf nicht leer sein."
            return
        }
    }
    
    # Update-Einstellungen
    if ($PSBoundParameters.ContainsKey('AutoUpdate'))
    {
        $globalConfig['AutoUpdate'] = $AutoUpdate
        $updated = $true
    }
    if ($PSBoundParameters.ContainsKey('UpdateRepository'))
    {
        $globalConfig['UpdateRepository'] = $UpdateRepository
        $updated = $true
    }
    
    # Default Policy Name
    if ($PSBoundParameters.ContainsKey('DefaultPolicy'))
    {
        if (-not [string]::IsNullOrWhiteSpace($DefaultPolicy))
        {
            $globalConfig['DefaultPolicy'] = $DefaultPolicy
            $updated = $true
        }
        else { Write-Error "DefaultPolicy darf nicht leer sein."; return }
    }
    
    # HPU-Domain-Gruppen-Mapping
    if ($PSBoundParameters.ContainsKey('HpuDomainGroupMap'))
    {
        if ($HpuDomainGroupMap -and $HpuDomainGroupMap.Count -gt 0)
        {
            # Pflichtfelder jedes Eintrags pruefen
            foreach ($entry in $HpuDomainGroupMap)
            {
                if ([string]::IsNullOrWhiteSpace($entry.DomainPattern))
                {
                    Write-Error "HpuDomainGroupMap: Jeder Eintrag benoetigt ein nicht-leeres Feld 'DomainPattern'."
                    return
                }
                if ([string]::IsNullOrWhiteSpace($entry.GroupNamePattern))
                {
                    Write-Error "HpuDomainGroupMap: Jeder Eintrag benoetigt ein nicht-leeres Feld 'GroupNamePattern'."
                    return
                }
            }
            $globalConfig['HpuDomainGroupMap'] = $HpuDomainGroupMap
            $updated = $true
        }
        else
        {
            Write-Error "HpuDomainGroupMap darf nicht leer sein."
            return
        }
    }
    
    # SSRS-Installer-Pfad
    if ($PSBoundParameters.ContainsKey('SsrsInstallerPath'))
    {
        if (-not [string]::IsNullOrWhiteSpace($SsrsInstallerPath))
        {
            $ext = [System.IO.Path]::GetExtension($SsrsInstallerPath).ToLower()
            if ($ext -notin @('.exe', '.msi'))
            {
                Write-Error "SsrsInstallerPath: Nur .exe oder .msi-Dateien sind gueltig (angegeben: '$SsrsInstallerPath')."
                return
            }
            $globalConfig['SsrsInstallerPath'] = $SsrsInstallerPath
            $updated = $true
        }
        else
        {
            Write-Error "SsrsInstallerPath darf nicht leer sein."
            return
        }
    }
    
    # Ausgabe-Sprache
    if ($PSBoundParameters.ContainsKey('Language'))
    {
        $globalConfig['Language'] = $Language
        $script:_strings = $null    # String-Cache invalidieren
        $updated = $true
    }

    if (-not $updated)
    {
        Write-Warning "Es wurde kein gueltiger Konfigurationsparameter angegeben."
        return
    }
    
    # Persistenz: JSON-Datei schreiben
    $configFile = Join-Path $env:APPDATA "MSSQLTools\config.json"
    $configDir = Split-Path $configFile -Parent
    if (-not (Test-Path $configDir))
    {
        New-Item -ItemType Directory -Path $configDir -Force | Out-Null
    }
    $globalConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $configFile -Force
    Write-Verbose "Konfiguration gespeichert: $configFile"
    
    if ($PassThru)
    {
        return Get-sqmConfig
    }
}