bin/Public/Test-sqmSsasDirectoryPermissions.ps1

<#
.SYNOPSIS
    Prueft und korrigiert die NTFS-Berechtigungen fuer SSAS-Verzeichnisse (Data, Log, Temp, Backup).
 
.DESCRIPTION
    Ermittelt fuer eine SSAS-Instanz die Verzeichnispfade aus der Registry,
    prueft, ob das SSAS-Dienstkonto Vollzugriff (FullControl) auf diese Verzeichnisse
    hat, und setzt ggf. die fehlenden Berechtigungen.
 
    Die Funktion arbeitet idempotent - bei wiederholtem Aufruf werden nur noch
    fehlende Rechte ergaenzt.
 
.PARAMETER InstanceName
    Name der SSAS-Instanz. Standard: 'MSSQLSERVER' (Standardinstanz).
    Bei benannten Instanzen z.?B. 'SSAS2019'.
 
.PARAMETER ServiceAccount
    Optional: Name des Dienstkontos (z.?B. 'NT SERVICE\MSSQLServerOLAPService').
    Wird nicht angegeben, wird das Konto automatisch aus dem Windows-Dienst ermittelt.
 
.PARAMETER WhatIf
    Zeigt, welche aenderungen vorgenommen wuerden, ohne sie auszufuehren.
 
.PARAMETER Confirm
    Fordert vor jeder aenderung eine Bestaetigung an.
 
.PARAMETER EnableException
    Loest bei Fehlern sofort eine Exception aus (sonst wird der Fehler protokolliert).
 
.PARAMETER ContinueOnError
    Setzt die Pruefung der naechsten Verzeichnisse auch bei Fehlern fort.
 
.EXAMPLE
    Test-sqmSsasDirectoryPermissions
 
    Prueft die Verzeichnisse der Standard-SSAS-Instanz und korrigiert fehlende Rechte.
 
.EXAMPLE
    Test-sqmSsasDirectoryPermissions -InstanceName "SSAS2019" -WhatIf
 
    Zeigt an, welche Berechtigungen fuer die benannte Instanz gesetzt wuerden.
 
.NOTES
    Erfordert lokale Administratorrechte auf dem SSAS-Server.
    Die Funktion nutzt die Registry unter HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSAS*.
#>

function Test-sqmSsasDirectoryPermissions
{
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'None')]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory = $false)]
        [string]$InstanceName = 'MSSQLSERVER',
        [Parameter(Mandatory = $false)]
        [string]$ServiceAccount,
        [Parameter(Mandatory = $false)]
        [switch]$EnableException,
        [Parameter(Mandatory = $false)]
        [switch]$ContinueOnError
    )
    
    begin
    {
        $functionName = $MyInvocation.MyCommand.Name
        $results = [System.Collections.Generic.List[PSCustomObject]]::new()
        
        Invoke-sqmLogging -Message "Starte $functionName fuer SSAS-Instanz '$InstanceName'" -FunctionName $functionName -Level "INFO"
    }
    
    process
    {
        try
        {
            # 1. Registry-Pfad fuer SSAS-Instanz finden
            $basePath = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server"
            $instances = Get-ChildItem -Path $basePath -ErrorAction Stop | Where-Object { $_.PSChildName -like 'MSAS*' }
            if (-not $instances)
            {
                throw "Keine SSAS-Instanzen in der Registry gefunden."
            }
            
            $found = $null
            foreach ($inst in $instances)
            {
                $regPath = Join-Path $inst.PSPath "Setup"
                if (Test-Path $regPath)
                {
                    $instId = (Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue).InstanceName
                    if ($instId -eq $InstanceName)
                    {
                        $found = $regPath
                        break
                    }
                }
            }
            if (-not $found)
            {
                throw "SSAS-Instanz '$InstanceName' nicht in der Registry gefunden."
            }
            $setupProps = Get-ItemProperty -Path $found -ErrorAction Stop
            $directories = @{
                DataDir = $setupProps.DataDir
                LogDir  = $setupProps.LogDir
                TempDir = $setupProps.TempDir
                BackupDir = $setupProps.BackupDir
            }
            
            # 2. Dienstkonto ermitteln
            if (-not $ServiceAccount)
            {
                $serviceName = if ($InstanceName -eq 'MSSQLSERVER')
                {
                    'MSSQLServerOLAPService'
                }
                else
                {
                    "MSOLAP`$$InstanceName"
                }
                $svc = Get-CimInstance -ClassName Win32_Service -Filter "Name='$serviceName'" -ErrorAction Stop
                if (-not $svc)
                {
                    throw "SSAS-Dienst '$serviceName' nicht gefunden."
                }
                $ServiceAccount = $svc.StartName
                Invoke-sqmLogging -Message "Dienstkonto automatisch ermittelt: $ServiceAccount" -FunctionName $functionName -Level "INFO"
            }
            
            # 3. Berechtigungen pruefen/korrigieren
            foreach ($dirName in @('DataDir', 'LogDir', 'TempDir', 'BackupDir'))
            {
                $dirPath = $directories[$dirName]
                if (-not $dirPath)
                {
                    $msg = "Registry-Eintrag fuer $dirName ist leer oder nicht vorhanden."
                    Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "WARNING"
                    $results.Add([PSCustomObject]@{
                            InstanceName = $InstanceName
                            Directory    = $dirName
                            Path         = $null
                            Status         = 'NotFound'
                            Message         = $msg
                        })
                    continue
                }
                if (-not (Test-Path $dirPath))
                {
                    $msg = "Verzeichnis '$dirPath' existiert nicht."
                    Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "ERROR"
                    $results.Add([PSCustomObject]@{
                            InstanceName = $InstanceName
                            Directory    = $dirName
                            Path         = $dirPath
                            Status         = 'Missing'
                            Message         = $msg
                        })
                    if (-not $ContinueOnError) { throw $msg }
                    continue
                }
                
                # ACL auslesen
                $acl = Get-Acl -Path $dirPath -ErrorAction Stop
                $identity = $ServiceAccount
                $accessRules = $acl.Access | Where-Object {
                    $_.IdentityReference -eq $identity -and
                    $_.FileSystemRights -eq 'FullControl' -and
                    $_.IsInherited -eq $false
                }
                $hasFullControl = ($accessRules.Count -gt 0)
                
                if ($hasFullControl)
                {
                    $msg = "OK: Vollzugriff fuer $identity bereits vorhanden."
                    Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "VERBOSE"
                    $results.Add([PSCustomObject]@{
                            InstanceName = $InstanceName
                            Directory    = $dirName
                            Path         = $dirPath
                            Status         = 'OK'
                            Message         = $msg
                        })
                }
                else
                {
                    $msg = "Fehlender Vollzugriff fuer $identity auf '$dirPath'."
                    Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "WARNING"
                    if ($PSCmdlet.ShouldProcess($dirPath, "Vollzugriff fuer $identity hinzufuegen"))
                    {
                        try
                        {
                            $rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
                                $identity, 'FullControl',
                                'ContainerInherit, ObjectInherit',
                                'None', 'Allow'
                            )
                            $acl.SetAccessRule($rule)
                            Set-Acl -Path $dirPath -AclObject $acl -ErrorAction Stop
                            $successMsg = "Vollzugriff fuer $identity auf '$dirPath' wurde hinzugefuegt."
                            Invoke-sqmLogging -Message $successMsg -FunctionName $functionName -Level "INFO"
                            $results.Add([PSCustomObject]@{
                                    InstanceName = $InstanceName
                                    Directory    = $dirName
                                    Path         = $dirPath
                                    Status         = 'Fixed'
                                    Message         = $successMsg
                                })
                        }
                        catch
                        {
                            $errMsg = "Fehler beim Setzen der Berechtigung auf '$dirPath': $($_.Exception.Message)"
                            Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
                            if ($EnableException) { throw }
                            $results.Add([PSCustomObject]@{
                                    InstanceName = $InstanceName
                                    Directory    = $dirName
                                    Path         = $dirPath
                                    Status         = 'Failed'
                                    Message         = $errMsg
                                })
                            if (-not $ContinueOnError) { throw $errMsg }
                        }
                    }
                    else
                    {
                        $skipMsg = "WhatIf: Berechtigung wuerde hinzugefuegt."
                        $results.Add([PSCustomObject]@{
                                InstanceName = $InstanceName
                                Directory    = $dirName
                                Path         = $dirPath
                                Status         = 'WhatIf'
                                Message         = $skipMsg
                            })
                    }
                }
            }
        }
        catch
        {
            $errMsg = "Schwerer Fehler: $($_.Exception.Message)"
            Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
            if ($EnableException) { throw }
            $results.Add([PSCustomObject]@{
                    InstanceName = $InstanceName
                    Directory    = 'Global'
                    Path         = $null
                    Status         = 'Error'
                    Message         = $errMsg
                })
        }
        return $results
    }
}