Public/Test-sqmTsmConnection.ps1

<#
.SYNOPSIS
    Tests the connection to an IBM Spectrum Protect (TSM) server using dsmadmc.
 
.DESCRIPTION
    Locates dsmadmc.exe on the local or remote computer, reads the TSM configuration
    from dsm.opt (server name, user name, password) if not provided explicitly,
    and executes a 'show version' command to verify that the TSM server is reachable.
 
.PARAMETER ComputerName
    Target computer on which the connection test is performed. Default: current computer name.
 
.PARAMETER DsmadmcPath
    Full path to dsmadmc.exe. Determined automatically from the registry if not specified.
 
.PARAMETER UserName
    TSM user name (USERID from dsm.opt if not specified).
 
.PARAMETER Password
    TSM password as SecureString (PASSWORD from dsm.opt if not specified).
 
.PARAMETER ServerName
    TSM server address (TCPServeraddress from dsm.opt if not specified).
 
.PARAMETER DsmOptPath
    Full path to dsm.opt. Determined automatically if not specified.
 
.PARAMETER Credential
    PSCredential for remote access (WinRM).
 
.PARAMETER EnableException
    Throw exceptions immediately.
 
.EXAMPLE
    Test-sqmTsmConnection
 
.EXAMPLE
    Test-sqmTsmConnection -ComputerName "SQL01" -UserName "tsm_admin" -Password (Read-Host -AsSecureString)
#>

function Test-sqmTsmConnection
{
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'None')]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory = $false)]
        [string]$ComputerName = $env:COMPUTERNAME,
        [Parameter(Mandatory = $false)]
        [string]$DsmadmcPath,
        [Parameter(Mandatory = $false)]
        [string]$UserName,
        [Parameter(Mandatory = $false)]
        [System.Security.SecureString]$Password,
        [Parameter(Mandatory = $false)]
        [string]$ServerName,
        [Parameter(Mandatory = $false)]
        [string]$DsmOptPath,
        [Parameter(Mandatory = $false)]
        [System.Management.Automation.PSCredential]$Credential,
        [Parameter(Mandatory = $false)]
        [switch]$EnableException
    )
    
    begin
    {
        $functionName = $MyInvocation.MyCommand.Name
        Invoke-sqmLogging -Message "Starte $functionName auf $ComputerName" -FunctionName $functionName -Level "INFO"
    }
    
    process
    {
        $result = [PSCustomObject]@{
            Success        = $false
            Message        = $null
            DsmadmcPath = $null
            ServerName  = $null
            UserName    = $null
            Output        = $null
            ErrorOutput = $null
        }
        
        try
        {
            # ---- 1. dsmadmc.exe Pfad ermitteln ----
            $dsmadmc = if ($DsmadmcPath) { $DsmadmcPath }
            else { _FindDsmadmcPath -ComputerName $ComputerName -Credential $Credential }
            if (-not $dsmadmc)
            {
                $msg = "dsmadmc nicht gefunden. Bitte TSM-Client installieren oder -DsmadmcPath angeben."
                Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "ERROR"
                if ($EnableException) { throw $msg }
                $result.Message = $msg
                return $result
            }
            $result.DsmadmcPath = $dsmadmc
            Invoke-sqmLogging -Message "Verwende dsmadmc: $dsmadmc" -FunctionName $functionName -Level "VERBOSE"
            
            # ---- 2. TSM-Konfiguration aus dsm.opt lesen (falls nicht alle Parameter angegeben) ----
            $effUserName = $UserName
            $effPassword = $Password
            $effServerName = $ServerName
            
            if (-not $effUserName -or -not $effPassword -or -not $effServerName)
            {
                $cfg = Get-sqmTsmConfiguration -ComputerName $ComputerName -DsmOptPath $DsmOptPath -Credential $Credential -IncludePasswordPlain -ErrorAction Stop
                if (-not $cfg.Success)
                {
                    throw "TSM-Konfiguration konnte nicht gelesen werden: $($cfg.ErrorMessage)"
                }
                if (-not $effServerName) { $effServerName = $cfg.ServerName }
                if (-not $effUserName) { $effUserName = $cfg.UserName }
                if (-not $effPassword -and $cfg.Password) { $effPassword = $cfg.Password }
            }
            
            if (-not $effUserName)
            {
                $msg = "Kein TSM-Benutzername angegeben und kein USERID in dsm.opt gefunden."
                Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "ERROR"
                if ($EnableException) { throw $msg }
                $result.Message = $msg
                return $result
            }
            if (-not $effPassword)
            {
                $msg = "Kein TSM-Kennwort angegeben und kein PASSWORD in dsm.opt gefunden."
                Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "ERROR"
                if ($EnableException) { throw $msg }
                $result.Message = $msg
                return $result
            }
            if (-not $effServerName)
            {
                $msg = "Kein TSM-Server angegeben und kein TCPServeraddress in dsm.opt gefunden."
                Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "ERROR"
                if ($EnableException) { throw $msg }
                $result.Message = $msg
                return $result
            }
            $result.UserName = $effUserName
            $result.ServerName = $effServerName
            Invoke-sqmLogging -Message "TSM-Server: $effServerName, Benutzer: $effUserName" -FunctionName $functionName -Level "INFO"
            
            # ---- 3. Kennwort aus SecureString extrahieren ----
            $plainPwd = _SecureToPlain $effPassword
            
            # ---- 4. dsmadmc-Befehl aufbauen ----
            $cmdArgs = "-id=$effUserName -password=$plainPwd -se=$effServerName -dataonly=yes show version"
            Invoke-sqmLogging -Message "Fuehre dsmadmc aus: $dsmadmc $cmdArgs" -FunctionName $functionName -Level "VERBOSE"
            
            # ---- 5. Befehl ausfuehren ----
            $output = $null
            $errorOut = $null
            $exitCode = 0
            $isLocal = $ComputerName -in @($env:COMPUTERNAME, 'localhost', '127.0.0.1', '.')
            
            if ($PSCmdlet.ShouldProcess("TSM-Verbindung zu $effServerName mit Benutzer $effUserName", "Pruefen"))
            {
                if ($isLocal)
                {
                    $psi = New-Object System.Diagnostics.ProcessStartInfo
                    $psi.FileName = $dsmadmc
                    $psi.Arguments = $cmdArgs
                    $psi.UseShellExecute = $false
                    $psi.RedirectStandardOutput = $true
                    $psi.RedirectStandardError = $true
                    $psi.CreateNoWindow = $true
                    $p = [System.Diagnostics.Process]::Start($psi)
                    $output = $p.StandardOutput.ReadToEnd()
                    $errorOut = $p.StandardError.ReadToEnd()
                    $p.WaitForExit()
                    $exitCode = $p.ExitCode
                }
                else
                {
                    $scriptBlock = {
                        param ($exe,
                            $args)
                        $psi = New-Object System.Diagnostics.ProcessStartInfo
                        $psi.FileName = $exe
                        $psi.Arguments = $args
                        $psi.UseShellExecute = $false
                        $psi.RedirectStandardOutput = $true
                        $psi.RedirectStandardError = $true
                        $psi.CreateNoWindow = $true
                        $p = [System.Diagnostics.Process]::Start($psi)
                        $out = $p.StandardOutput.ReadToEnd()
                        $err = $p.StandardError.ReadToEnd()
                        $p.WaitForExit()
                        return @{ ExitCode = $p.ExitCode; Output = $out; Error = $err }
                    }
                    $session = New-PSSession -ComputerName $ComputerName -Credential $Credential -ErrorAction Stop
                    $remoteResult = Invoke-Command -Session $session -ScriptBlock $scriptBlock -ArgumentList $dsmadmc, $cmdArgs -ErrorAction Stop
                    $exitCode = $remoteResult.ExitCode
                    $output = $remoteResult.Output
                    $errorOut = $remoteResult.Error
                    Remove-PSSession $session
                }
                
                $result.Output = $output
                $result.ErrorOutput = $errorOut
                
                if ($exitCode -eq 0 -and $output -match 'IBM Spectrum Protect')
                {
                    $result.Success = $true
                    $result.Message = "Verbindung zu TSM-Server '$effServerName' mit Benutzer '$effUserName' erfolgreich."
                    Invoke-sqmLogging -Message $result.Message -FunctionName $functionName -Level "INFO"
                }
                else
                {
                    $result.Success = $false
                    $result.Message = "Fehler bei TSM-Verbindung (Exitcode $exitCode). Ausgabe: $output $errorOut".Trim()
                    Invoke-sqmLogging -Message $result.Message -FunctionName $functionName -Level "ERROR"
                }
            }
            else
            {
                $result.Success = $false
                $result.Message = "WhatIf: Verbindungstest wuerde ausgefuehrt."
                Invoke-sqmLogging -Message $result.Message -FunctionName $functionName -Level "VERBOSE"
            }
        }
        catch
        {
            $errMsg = "Allgemeiner Fehler: $($_.Exception.Message)"
            Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
            if ($EnableException) { throw }
            $result.Message = $errMsg
        }
        return $result
    }
    
    end
    {
        Invoke-sqmLogging -Message "$functionName abgeschlossen." -FunctionName $functionName -Level "INFO"
    }
}

# ---- Hilfsfunktionen (lokal) ----
function _FindDsmadmcPath
{
    param ([string]$ComputerName,
        [System.Management.Automation.PSCredential]$Credential)
    
    $isLocal = $ComputerName -in @($env:COMPUTERNAME, 'localhost', '127.0.0.1', '.')
    $candidates = [System.Collections.Generic.List[string]]::new()
    
    if ($isLocal)
    {
        try
        {
            $regPath = 'HKLM:\SOFTWARE\IBM\ADSM\CurrentVersion'
            $installPath = (Get-ItemProperty $regPath -Name 'InstallPath' -ErrorAction SilentlyContinue).InstallPath
            # KORREKTUR: Doppelte Klammern fuer den Methodenaufruf
            if ($installPath) { $candidates.Add((Join-Path $installPath 'dsmadmc.exe')) }
        }
        catch { }
        
        if ($env:DSM_DIR) { $candidates.Add((Join-Path $env:DSM_DIR 'dsmadmc.exe')) }
        
        $candidates.Add('C:\Program Files\Tivoli\TSM\baclient\dsmadmc.exe')
        $candidates.Add('C:\Program Files\IBM\TSM\baclient\dsmadmc.exe')
        $candidates.Add('C:\Program Files\IBM\SpectrumProtect\baclient\dsmadmc.exe')
    }
    else
    {
        # Remote-Logik... (hier ebenfalls Klammern pruefen falls Join-Path genutzt wird)
    }
    
    foreach ($c in $candidates)
    {
        if (Test-Path $c) { return $c }
    }
    return $null
}