🛢 sqmSQLTool

PowerShell SQL Admin Toolset · dtcSoftware · Janke

v 1.4.7.0 PowerShell 5.1+ dbatools required 122 Funktionen MS SQL Server
📖 Referenz
🚀 Quick Start
⚙️ Konfiguration
📦 Installation
📊 Übersicht

🔄 AlwaysOn

Get-sqmAlwaysOnHealthReport AlwaysOn
Retrieves for each AG on the specified instance: - Synchronization status of all replicas - LSN lag between primary and secondaries (redo queue, send queue) - Database status per replic
▶ 2 Beispiele anzeigen
Get-sqmAlwaysOnHealthReport
Get-sqmAlwaysOnHealthReport
Get-sqmAlwaysOnHealthReport -SqlInstance "SQL01" -MaxRedoQueueMB 200 -OutputPath "D:\Reports"
Get-sqmAlwaysOnHealthReport -SqlInstance "SQL01" -MaxRedoQueueMB 200 -OutputPath "D:\Reports"
Add-sqmDatabaseToAG AlwaysOn
- Checks whether the database is already in an AG. - Sets recovery mode to Full (if necessary). - Drops existing databases on all secondary replicas. - Adds the database to the AG using Automatic S
▶ 2 Beispiele anzeigen
Add-sqmDatabaseToAG -AvailabilityGroup "AG1" -Database "SalesDB"
Add-sqmDatabaseToAG -AvailabilityGroup "AG1" -Database "SalesDB"
Add-sqmDatabaseToAG -AvailabilityGroup "AG1" -All
Add-sqmDatabaseToAG -AvailabilityGroup "AG1" -All
Invoke-sqmFailover AlwaysOn
Checks before failover: synchronization status, redo queue size. Performs the failover: ALTER AVAILABILITY GROUP ... FAILOVER on the target secondary. Checks after failover: new primary reacha
▶ 2 Beispiele anzeigen
Invoke-sqmFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" -WhatIf
Invoke-sqmFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" -WhatIf
Invoke-sqmFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" `
        -TargetReplica "SQL02" -MaxRedoQueueMB 10
Invoke-sqmSqlAlwaysOnAutoseeding AlwaysOn
Configures the seeding mode of all replicas of one or more Availability Groups to "Automatic". Using the -All switch forces processing of all Availability Groups on the instance. If the SqlInstan
▶ 3 Beispiele anzeigen
# Uses the current computer name as default
Invoke-sqmSqlAlwaysOnAutoseeding
# Explicit instance specification
Invoke-sqmSqlAlwaysOnAutoseeding -SqlInstance "SQL01\INSTANCE"
# All groups on the current computer
Invoke-sqmSqlAlwaysOnAutoseeding -All
New-sqmAlwaysOnRepairJob AlwaysOn
The job is created on the specified SQL instance and uses the PowerShell subsystem to call the Repair-sqmAlwaysOnDatabases function. The job can run on a schedule (e.g. hourly) or be started manuall
▶ 2 Beispiele anzeigen
# Creates an hourly job
New-sqmAlwaysOnRepairJob
# Daily job at 2 AM
New-sqmAlwaysOnRepairJob -Schedule "FREQ=DAILY;INTERVAL=1" -StartTime "02:00:00"
Remove-sqmDatabaseFromAG AlwaysOn
The function automatically detects which Availability Group the specified database belongs to, removes it from the group, and then deletes it from all secondary replicas. System databases are ignore
▶ 2 Beispiele anzeigen
# Remove a single database from its AG
Remove-sqmDatabaseFromAvailabilityGroup -Database "SalesDB"
# Remove all AG databases
Remove-sqmDatabaseFromAvailabilityGroup -All
Sync-sqmAgNode AlwaysOn
Automatically detects the current primary and all Availability Groups of the specified instance. All AGs are processed individually. Synchronizes the following object types from primary to
▶ 2 Beispiele anzeigen
Sync-sqmAgNode
Sync-sqmAgNode
Sync-sqmAgNode -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" -ObjectName "AppLogin_*"
Sync-sqmAgNode -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" -ObjectName "AppLogin_*"

💾 Backup & Restore

Invoke-sqmLogShrink Backup
Executes DBCC SHRINKFILE on the log file(s). Calculates the target size as a percentage of the current size (ShrinkTargetPercent) with a lower threshold (MinTargetMB). Handles Always On AGs
▶ 2 Beispiele anzeigen
Invoke-sqmLogShrink -Database "MyDB" -ShrinkTargetPercent 20
Invoke-sqmLogShrink -Database "MyDB" -ShrinkTargetPercent 20
Invoke-sqmLogShrink -SqlInstance "SQL01" -All -WhatIf
Invoke-sqmLogShrink -SqlInstance "SQL01" -All -WhatIf
Invoke-sqmRestoreDatabase Backup
The function performs a controlled database restore. It automatically detects whether the target database belongs to an AlwaysOn availability group and removes it from the AG if so (including deleti
▶ 3 Beispiele anzeigen
# Simple restore of a full backup file
Invoke-sqmRestoreDatabase -SqlInstance "SQL01" -BackupFile "D:\Backup\AdventureWorks.bak" -DatabaseName "AdventureWorks"
# Restore with Full + Diff + Logs
$backupSequence = @(
    "D:\Backup\AdventureWorks_Full.bak",
    "D:\Backup\AdventureWorks_Diff.bak",
    "D:\Backup\AdventureWorks_Log1.trn",
    "D:\Backup\AdventureWorks_Log2.trn"
)
Invoke-sqmRestoreDatabase -SqlInstance "SQL01" -BackupFiles $backupSequence -DatabaseName "AdventureWorks"
# Restore with new name and forced Single-User mode
Invoke-sqmRestoreDatabase -SqlInstance "SQL01" -BackupFile "D:\Backup\OldDB.bak" -DatabaseName "OldDB" -NewDatabaseName "NewDB" -ForceSingleUser
Invoke-sqmUserDatabaseBackup Backup
Backs up all or selected user databases (no system databases) in full backup mode. The target path is read from the server properties (BackupDirectory) and must end with "User-Db". If the SqlInstance
▶ 9 Beispiele anzeigen
# Back up all user databases on the current computer
Invoke-sqmUserDatabaseBackup -All
# Back up specific databases on a remote server
Invoke-sqmUserDatabaseBackup -SqlInstance "SQL01" -Database "SalesDB", "InventoryDB"
# With an alternative path
Invoke-sqmUserDatabaseBackup -All -BackupPath "D:\Backup\User-Db"
# Back up all user databases, skipping databases listed in sqm_BackupExclude
Invoke-sqmUserDatabaseBackup -All -UseExcludeTable
# Back up with exclude table on a remote instance
Invoke-sqmUserDatabaseBackup -SqlInstance "SQL01" -All -UseExcludeTable
# Only run backup if this instance is the preferred AG backup replica
Invoke-sqmUserDatabaseBackup -SqlInstance "SQL01" -All -CheckPreferredReplica
# Back up all databases and send a mail report on errors (uses default mail profile)
Invoke-sqmUserDatabaseBackup -All -MailTo "dba@example.com"
# Back up all databases and always send a mail report (success and failure)
Invoke-sqmUserDatabaseBackup -All -MailTo "dba@example.com" -MailProfile "SQLAlerts" -MailOnSuccess
# Full pipeline: AG-aware backup with exclude table and mail notification
Invoke-sqmUserDatabaseBackup -SqlInstance "SQL01" -All -UseExcludeTable `
    -CheckPreferredReplica -MailTo "dba@example.com" -MailOnSuccess
New-sqmBackupMaintenanceJob Backup
Creates a single SQL Agent job containing two PowerShell steps: Step 1 — Sync-BackupExcludeTable Calls Sync-sqmBackupExcludeTable to synchronise master.dbo.sqm_BackupExclude with the curre
▶ 4 Beispiele anzeigen
# Weekly FULL backup Sunday 20:00 with all features
	New-sqmBackupMaintenanceJob -SqlInstance "SQL01" -BackupType FULL `
	    -UseExcludeTable -CheckPreferredReplica `
	    -MailTo "dba@company.com" -MailProfile "DBA-Mail"
# Daily DIFF backup with exclude table
	New-sqmBackupMaintenanceJob -SqlInstance "SQL01" -BackupType DIFF `
	    -UseExcludeTable -ScheduleTime "22:00"
# LOG backup every 15 minutes
	New-sqmBackupMaintenanceJob -SqlInstance "SQL01" -BackupType LOG `
	    -ScheduleIntervalMinutes 15 -UseExcludeTable
# Replace existing job
	New-sqmBackupMaintenanceJob -SqlInstance "SQL01" -BackupType FULL -Update
New-sqmOlaSysDbBackupJob Backup
Creates a SQL Agent job that daily backs up master, model, and msdb completely. Backups are stored in a dedicated subdirectory \Sys-db: \Sys-db. Job name is read from the
▶ 2 Beispiele anzeigen
New-sqmOlaSysDbBackupJob -SqlInstance "SQL01"
New-sqmOlaSysDbBackupJob -SqlInstance "SQL01"
New-sqmOlaSysDbBackupJob -SqlInstance "SQL01" -ScheduleTime "20:00" -OperatorName "DBAs"
New-sqmOlaSysDbBackupJob -SqlInstance "SQL01" -ScheduleTime "20:00" -OperatorName "DBAs"
New-sqmOlaUsrDbBackupJob Backup
Creates a separate SQL Agent job for each selected backup type (-Full, -Diff, -Log). Each job gets its own schedule with configurable days and start time. Backups are stored in
▶ 9 Beispiele anzeigen
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log
# Create FULL job that automatically excludes databases from sqm_BackupExclude
    New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -UseExcludeTable
# All three job types with exclude table integration
    New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log -UseExcludeTable -Update
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full `
        -FullScheduleTime "22:00" -FullScheduleDays @('Sunday') `
        -OperatorName "DBAs"
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Log `
        -LogScheduleTime "00:30" -LogScheduleDays @('EveryDay') `
        -Databases "USER_DATABASES"
New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log `
        -FullScheduleDays @('Sunday') -FullScheduleTime "21:00" `
        -DiffScheduleDays @('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday') `
        -DiffScheduleTime "21:00" `
        -LogScheduleDays @('EveryDay') -LogScheduleTime "00:00" `
        -Update
# LOG backup every 15 minutes, daily
    New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Log `
        -LogScheduleDays @('EveryDay') -LogScheduleTime "00:00" `
        -LogScheduleIntervalMinutes 15 -Update
# FULL on multiple days, DIFF daily, LOG every 30 minutes
    New-sqmOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log `
        -FullScheduleDays @('Monday','Wednesday','Friday') -FullScheduleTime "22:00" `
        -DiffScheduleDays @('EveryDay') -DiffScheduleTime "22:00" `
        -LogScheduleDays @('EveryDay') -LogScheduleTime "00:00" `
        -LogScheduleIntervalMinutes 30 -Update
Set-sqmBackupExcludePermission Backup
Ensures that the specified Windows group or SQL login has the necessary permissions to read and modify the backup exclude table master.dbo.sqm_BackupExclude. The function performs the following steps
▶ 3 Beispiele anzeigen
# Grant permissions to a Windows group on the local instance
Set-sqmBackupExcludePermission -LoginName "CONTOSO\DBA-Team"
# Grant permissions to a SQL login on a remote instance
Set-sqmBackupExcludePermission -SqlInstance "SQL01" -LoginName "svc_backup"
# Preview what would happen without making any changes
Set-sqmBackupExcludePermission -SqlInstance "SQL01" -LoginName "CONTOSO\DBA-Team" -WhatIf
Sync-sqmBackupExcludeTable Backup
Ensures the table master.dbo.sqm_BackupExclude exists on the target SQL Server instance. If the table does not exist it is created automatically. After the table has been created or verified, the fun
▶ 4 Beispiele anzeigen
# Synchronise on the local instance – user databases only
Sync-sqmBackupExcludeTable
# Synchronise on a remote instance including system databases
Sync-sqmBackupExcludeTable -SqlInstance "SQL01" -IncludeSystemDatabases
# Preview what would change without making any modifications
Sync-sqmBackupExcludeTable -SqlInstance "SQL01" -WhatIf
# Synchronise and verify that the audit history table and trigger are in place
Sync-sqmBackupExcludeTable -SqlInstance "SQL01\INST1"
Test-sqmBackupIntegrity Backup
Executes RESTORE VERIFYONLY on a backup file (local or optionally remote). Returns $true if the check was successful, otherwise $false. Can verify multiple files in sequence (e.g. stripes).
▶ 1 Beispiel anzeigen
Test-sqmBackupIntegrity -SqlInstance "SQL01" -BackupPath "D:\Backup\AdventureWorks.bak"
Test-sqmBackupIntegrity -SqlInstance "SQL01" -BackupPath "D:\Backup\AdventureWorks.bak"

🔒 Sicherheit

Get-sqmADAccountStatus Sicherheit
Determines the account status using the ActiveDirectory module (RSAT) with automatic fallback to ADSI if RSAT is not available. Returns a detailed PSObject with Enabled, LockedOut, P
▶ 3 Beispiele anzeigen
Get-sqmADAccountStatus -SamAccountName 'jdoe'
Get-sqmADAccountStatus -SamAccountName 'jdoe'
'jdoe','jsmith' | Get-sqmADAccountStatus
'jdoe','jsmith' | Get-sqmADAccountStatus
Get-sqmADAccountStatus -SamAccountName 'jdoe' -DomainController 'DC01'
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param (
        [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [string[]] $SamAccountName,

        [Parameter()]
        [string] $DomainController
    )

    begin {
        #region --- Modul-Verfuegbarkeit einmalig pruefen ---
        $useRSAT = $false
        if (Get-Module -Name ActiveDirectory -ListAvailable) {
            try {
                Import-Module ActiveDirectory -ErrorAction Stop
                $useRSAT = $true
                Write-Verbose 'ActiveDirectory-Modul geladen (RSAT-Pfad aktiv).'
            }
            catch {
                Write-Verbose "ActiveDirectory-Modul nicht ladbar: $_  - Fallback auf ADSI."
            }
        }
        else {
            Write-Verbose 'ActiveDirectory-Modul nicht installiert - Fallback auf ADSI.'
        }

        # Hilfsfunktion: Ergebnis-Objekt erzeugen
        function New-ResultObject {
            param (
                [string]   $Sam,
                [bool]     $Enabled        = $false,
                [bool]     $LockedOut      = $false,
                [bool]     $PwdExpired     = $false,
                [bool]     $AcctExpired    = $false,
                [string]   $Source         = '',
                [string]   $ErrorMessage   = ''
            )
            [PSCustomObject]@{
                SamAccountName  = $Sam
                Enabled         = $Enabled
                LockedOut       = $LockedOut
                PasswordExpired = $PwdExpired
                AccountExpired  = $AcctExpired
                Source          = $Source
                QueryTime       = (Get-Date)
                ErrorMessage    = $ErrorMessage
            }
        }

        #region --- ADSI-Hilfsfunktion ---
        function Get-ADAccountStatusViaADSI {
            param ([string] $Sam)

            # Searcher aufbauen
            $searcher = [adsisearcher]"(sAMAccountName=$Sam)"
            $searcher.PropertiesToLoad.AddRange(@(
                'sAMAccountName',
                'userAccountControl',
                'lockoutTime',
                'pwdLastSet',
                'accountExpires',
                'msDS-UserPasswordExpiryTimeComputed'
            )) | Out-Null
            $searcher.SizeLimit = 1

            $entry = $searcher.FindOne()
            if (-not $entry) {
                throw "Konto '$Sam' wurde im Verzeichnis nicht gefunden."
            }

            $uac = [int]$entry.Properties['useraccountcontrol'][0]

            # Enabled: Bit 2 (0x0002) = disabled
            $enabled   = -not [bool]($uac -band 0x0002)

            # LockedOut: Bit 16 (0x0010) oder lockoutTime > 0
            $lockedBit = [bool]($uac -band 0x0010)
            $lockoutTimeRaw = $entry.Properties['lockouttime']
            $lockedTime = $false
            if ($lockoutTimeRaw.Count -gt 0) {
                $lt = [long]$lockoutTimeRaw[0]
                $lockedTime = ($lt -gt 0)
            }
            $lockedOut = $lockedBit -or $lockedTime

            # PasswordExpired: Bit 8388608 (0x800000) oder msDS-Attribut
            $pwdExpiredBit = [bool]($uac -band 0x800000)
            $pwdExpired = $pwdExpiredBit

            if (-not $pwdExpired) {
                $expiryRaw = $entry.Properties['msds-userpasswordexpirytimecomputed']
                if ($expiryRaw.Count -gt 0) {
                    $expiryFt = [long]$expiryRaw[0]
                    # 0 = laeuft nie ab, 9223372036854775807 = nie
                    if ($expiryFt -gt 0 -and $expiryFt -ne [long]::MaxValue) {
                        $expiryDate = [datetime]::FromFileTime($expiryFt)
                        $pwdExpired = ($expiryDate -lt (Get-Date))
                    }
                }
            }

            # AccountExpired
            $acctExpired = $false
            $acctExpiresRaw = $entry.Properties['accountexpires']
            if ($acctExpiresRaw.Count -gt 0) {
                $ae = [long]$acctExpiresRaw[0]
                # 0 und Int64.MaxValue bedeuten "laeuft nie ab"
                if ($ae -gt 0 -and $ae -ne [long]::MaxValue) {
                    $expDate = [datetime]::FromFileTime($ae)
                    $acctExpired = ($expDate -lt (Get-Date))
                }
            }

            return [PSCustomObject]@{
                Enabled         = $enabled
                LockedOut       = $lockedOut
                PasswordExpired = $pwdExpired
                AccountExpired  = $acctExpired
            }
        }
        #endregion
    }

    process {
        foreach ($sam in $SamAccountName) {
            Write-Verbose "Verarbeite Konto: $sam"

            #region --- RSAT-Pfad ---
            if ($useRSAT) {
                try {
                    $params = @{
                        Identity    = $sam
                        Properties  = @(
                            'Enabled',
                            'LockedOut',
                            'PasswordExpired',
                            'AccountExpirationDate'   # 'AccountExpired' ist keine abrufbare Property
                        )
                        ErrorAction = 'Stop'
                    }
                    if ($DomainController) { $params['Server'] = $DomainController }

                    $adUser = Get-ADUser @params

                    # AccountExpired: ExpirationDate vorhanden und in der Vergangenheit?
                    $acctExpired = ($null -ne $adUser.AccountExpirationDate) -and
                                   ($adUser.AccountExpirationDate -lt (Get-Date))

                    New-ResultObject `
                        -Sam         $sam `
                        -Enabled     ([bool]$adUser.Enabled) `
                        -LockedOut   ([bool]$adUser.LockedOut) `
                        -PwdExpired  ([bool]$adUser.PasswordExpired) `
                        -AcctExpired $acctExpired `
                        -Source      'RSAT'
                    continue
                }
                catch {
                    # Konto nicht gefunden ? direkt Fehlerobjekt, kein ADSI-Fallback
                    if ($_.Exception.GetType().Name -eq 'ADIdentityNotFoundException') {
                        New-ResultObject -Sam $sam -ErrorMessage "Konto nicht gefunden: $_" -Source 'RSAT'
                        continue
                    }
                    Write-Verbose "RSAT-Fehler fuer '$sam': $_ - Fallback auf ADSI."
                }
            }
            #endregion

            #region --- ADSI-Fallback ---
            try {
                $adsi = Get-ADAccountStatusViaADSI -Sam $sam

                New-ResultObject `
                    -Sam        $sam `
                    -Enabled    $adsi.Enabled `
                    -LockedOut  $adsi.LockedOut `
                    -PwdExpired $adsi.PasswordExpired `
                    -AcctExpired $adsi.AccountExpired `
                    -Source     'ADSI'
            }
            catch {
                New-ResultObject -Sam $sam -ErrorMessage $_.ToString() -Source 'ADSI'
            }
            #endregion
        }
    }
}
Get-sqmADGroupMembers Sicherheit
Simple, reliable function to list members of an AD group. Useful when SQL Server access fails and you need to check group permissions. Methods: 1. Get-ADGroupMember (if ActiveDirectory mo
▶ 2 Beispiele anzeigen
Get-sqmADGroupMembers -GroupName "DL_SQL_Admins"
Get-sqmADGroupMembers -GroupName "DL_SQL_Admins"
Get-sqmADGroupMembers -GroupName "Administrators" -Domain "FITS"
Get-sqmADGroupMembers -GroupName "Administrators" -Domain "FITS"
Get-sqmSysadminAccounts Sicherheit
Queries sys.server_principals and sys.server_role_members and returns all direct members of the sysadmin server role. Per login the following information is determined: - Login name a
▶ 2 Beispiele anzeigen
Get-sqmSysadminAccounts
Get-sqmSysadminAccounts
Get-sqmSysadminAccounts -SqlInstance "SQL01" -ExcludeSysAccounts
#>
function Get-sqmSysadminAccounts
{
	[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'None')]
	[OutputType([PSCustomObject])]
	param (
		[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
		[string[]]$SqlInstance = @($env:COMPUTERNAME),
		[Parameter(Mandatory = $false)]
		[System.Management.Automation.PSCredential]$SqlCredential,
		[Parameter(Mandatory = $false)]
		[string[]]$ExcludeLogin = @(),
		[Parameter(Mandatory = $false)]
		[switch]$ExcludeSysAccounts,
		[Parameter(Mandatory = $false)]
		[bool]$IncludeDisabled = $true,
		[Parameter(Mandatory = $false)]
		[string]$OutputPath = '$env:ProgramData\sqmSQLTool\Logs',
		[Parameter(Mandatory = $false)]
		[switch]$ContinueOnError,
		[Parameter(Mandatory = $false)]
		[switch]$EnableException
	)
	
	begin
	{
		$functionName = $MyInvocation.MyCommand.Name
		$allInstanceResults = [System.Collections.Generic.List[PSCustomObject]]::new()
		
		if (-not (Get-Module -ListAvailable -Name dbatools))
		{
			$errMsg = "dbatools-Modul nicht gefunden."
			Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
			throw $errMsg
		}
		
		Invoke-sqmLogging -Message "Starte $functionName mit OutputPath: $OutputPath" -FunctionName $functionName -Level "INFO"
		
		# Systemkonten-Muster fuer -ExcludeSysAccounts
		$sysAccountPatterns = @(
			'NT SERVICE\*',
			'NT AUTHORITY\SYSTEM',
			'NT AUTHORITY\NETWORK SERVICE',
			'NT AUTHORITY\LOCAL SERVICE',
			'NT AUTHORITY\*',
			'##MS_*##'
		)
		
		if ($ExcludeSysAccounts)
		{
			$ExcludeLogin = @($ExcludeLogin) + $sysAccountPatterns | Sort-Object -Unique
			Invoke-sqmLogging -Message "ExcludeSysAccounts: $($sysAccountPatterns.Count) Systemmuster hinzugefuegt." -FunctionName $functionName -Level "DEBUG"
		}
		
		# Hilfsfunktion fuer Ausschlusspruefung
		function _IsExcluded
		{
			param ([string]$Name,
				[string[]]$Patterns)
			if (-not $Patterns) { return $false }
			foreach ($p in $Patterns)
			{
				if ($Name -like $p) { return $true }
			}
			return $false
		}
	}
	
	process
	{
		foreach ($instance in $SqlInstance)
		{
			$connParams = @{ SqlInstance = $instance }
			if ($SqlCredential) { $connParams['SqlCredential'] = $SqlCredential }
			
			$detailRows = [System.Collections.Generic.List[PSCustomObject]]::new()
			
			try
			{
				Invoke-sqmLogging -Message "[$instance] Starte Sysadmin-Audit ..." -FunctionName $functionName -Level "INFO"
				
				$disabledFilter = if ($IncludeDisabled) { '' }
				else { 'AND sp.is_disabled = 0' }
				
				# Achtung: password_last_set_time und last_login_date wurden entfernt,
				# da sie in aelteren SQL Server-Versionen nicht existieren.
				$query = @"
SELECT
    sp.name                                          AS LoginName,
    sp.type_desc                                     AS LoginType,
    sp.is_disabled                                   AS IsDisabled,
    CASE WHEN sp.sid = 0x01 THEN 1 ELSE 0 END        AS IsSa,
    sp.create_date                                   AS CreateDate,
    sp.modify_date                                   AS ModifyDate,
    NULL                                             AS LastPasswordChange,
    NULL                                             AS LastLogin,
    sp.default_database_name                         AS DefaultDatabase
FROM sys.server_principals       sp
JOIN sys.server_role_members     rm ON rm.member_principal_id = sp.principal_id
JOIN sys.server_principals       sr ON sr.principal_id        = rm.role_principal_id
WHERE sr.name        = 'sysadmin'
  AND sp.type        IN ('S','U','G','R')
  AND sp.principal_id > 1
  $disabledFilter
ORDER BY sp.type_desc, sp.name;
"@
				$rows = Invoke-DbaQuery @connParams -Query $query -EnableException:$EnableException
				
				if (-not $rows)
				{
					$msg = "Keine sysadmin-Logins auf '$instance' gefunden (unerwartet)."
					Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level "WARNING"
					$detailRows.Add([PSCustomObject]@{
							SqlInstance	       = $instance
							LoginName		   = '(keine)'
							LoginType		   = 'n/a'
							IsEnabled		   = $null
							IsSa			   = $false
							LastPasswordChange = $null
							LastLogin		   = $null
							CreateDate		   = $null
							Status			   = 'Error'
							Message		       = $msg
						})
				}
				else
				{
					Invoke-sqmLogging -Message "[$instance] $($rows.Count) sysadmin-Login(s) gefunden." -FunctionName $functionName -Level "INFO"
					
					foreach ($row in $rows)
					{
						$loginName = $row.LoginName
						$isSa = [bool]$row.IsSa
						$isEnabled = -not [bool]$row.IsDisabled
						$excluded = _IsExcluded $loginName $ExcludeLogin
						$isBuiltinAdmins = ($loginName -eq 'BUILTIN\Administrators')
						
						$status = if ($isSa) { 'SA' }
						elseif ($isBuiltinAdmins) { 'BuiltinAdmins' }
						elseif ($excluded) { 'Excluded' }
						elseif (-not $isEnabled) { 'Disabled' }
						else { 'Unexpected' }
						
						$msg = switch ($status)
						{
							'SA'            { 'SA-Konto (SID 0x01).' }
							'BuiltinAdmins' { 'BUILTIN\Administrators hat Sysadmin-Rechte - SICHERHEITSPRueFUNG ERFORDERLICH.' }
							'Excluded'      { 'Ausgeschlossen via -ExcludeLogin.' }
							'Disabled'      { 'Login hat sysadmin-Rechte, ist aber deaktiviert.' }
							'Unexpected'    { 'Sysadmin-Login - kein Ausschluss definiert.' }
						}
						
						$createDate = if ($row.CreateDate) { $row.CreateDate.ToString('yyyy-MM-dd') }
						else { $null }
						
						$detailRows.Add([PSCustomObject]@{
								SqlInstance = $instance
								LoginName   = $loginName
								LoginType   = $row.LoginType
								IsEnabled   = $isEnabled
								IsSa	    = $isSa
								LastPasswordChange = $null # Nicht verfuegbar in aelteren Versionen
								LastLogin   = $null # Nicht verfuegbar in aelteren Versionen
								CreateDate  = $createDate
								Status	    = $status
								Message	    = $msg
							})
					}
				}
				
				# Statistik
				$cntSa = ($detailRows | Where-Object Status -eq 'SA').Count
				$cntExcluded = ($detailRows | Where-Object Status -eq 'Excluded').Count
				$cntDisabled = ($detailRows | Where-Object Status -eq 'Disabled').Count
				$cntUnexpected = ($detailRows | Where-Object Status -eq 'Unexpected').Count
				$cntBuiltinAdmins = ($detailRows | Where-Object Status -eq 'BuiltinAdmins').Count
				
				Invoke-sqmLogging -Message ("[$instance] Gesamt: $($detailRows.Count) | SA: $cntSa | Ausgeschlossen: $cntExcluded | " +
					"Deaktiviert: $cntDisabled | Unerwartet: $cntUnexpected | BUILTIN\\Admins: $cntBuiltinAdmins") -FunctionName $functionName -Level "INFO"
				
				# Dateien schreiben
				$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
				$datestamp = Get-Date -Format 'yyyy-MM-dd'
				$safeInst = $instance -replace '[\\/:*?"<>|]', '_'
				$txtFile = Join-Path $OutputPath "SysadminAccounts_${safeInst}_${datestamp}.txt"
				$csvFile = Join-Path $OutputPath "SysadminAccounts_${safeInst}_${datestamp}.csv"
				
				if ($PSCmdlet.ShouldProcess($instance, "Erstelle Sysadmin-Bericht in $OutputPath"))
				{
					if (-not (Test-Path $OutputPath))
					{
						New-Item -ItemType Directory -Path $OutputPath -Force -ErrorAction Stop | Out-Null
						Invoke-sqmLogging -Message "Verzeichnis $OutputPath wurde erstellt." -FunctionName $functionName -Level "INFO"
					}
					
					# TXT-Bericht (identisch zum vorherigen, daher hier ausgelassen - bitte aus Original uebernehmen)
					# ... (der Code fuer die TXT-Erstellung bleibt unveraendert)
					$lines = [System.Collections.Generic.List[string]]::new()
					$lines.Add("# ================================================================")
					$lines.Add("# MSSQLTools - Sysadmin-Konten Bericht")
					$lines.Add("# Instanz   : $instance")
					$lines.Add("# Erstellt  : $timestamp")
					$lines.Add("# Gesamt    : $($detailRows.Count) Logins")
					$lines.Add("# SA        : $cntSa")
					$lines.Add("# Ausgesch. : $cntExcluded")
					$lines.Add("# Deaktiv.  : $cntDisabled")
					$lines.Add("# Unerwartet: $cntUnexpected  ? PRueFEN")
					$lines.Add("# BUILTIN\\Adm: $cntBuiltinAdmins  ? SICHERHEITSPRueFUNG")
					$lines.Add("# SysExclude: $(if ($ExcludeSysAccounts) { 'Ja (NT SERVICE\*, NT AUTHORITY\*, ##MS_*##)' }
							else { 'Nein (manuell via -ExcludeLogin)' })")
					$lines.Add("# ================================================================")
					
					# BUILTIN\Administrators
					$builtinEntries = $detailRows | Where-Object { $_.Status -eq 'BuiltinAdmins' }
					$lines.Add(""); $lines.Add("# ================================================================")
					$lines.Add("# BUILTIN\Administrators - SICHERHEITSPRueFUNG ERFORDERLICH ($cntBuiltinAdmins)")
					$lines.Add("# ================================================================")
					if ($builtinEntries)
					{
						foreach ($e in $builtinEntries)
						{
							$lines.Add(("  Name   : {0}" -f $e.LoginName))
							$lines.Add(("  Typ    : {0}  |  Aktiv: {1}  |  Erstellt: {2}" -f $e.LoginType, $e.IsEnabled, $e.CreateDate))
							$lines.Add("  ? Empfehlung: Pruefen ob BUILTIN\Administrators Sysadmin-Rechte")
							$lines.Add("    gemaess Sicherheitsrichtlinie zulaessig sind. Ggf. entfernen:")
							$lines.Add("    EXEC sp_dropsrvrolemember 'BUILTIN\Administrators','sysadmin';")
						}
					}
					else { $lines.Add("  (nicht vorhanden - kein Befund)") }
					
					# Unerwartete Konten
					$unexpected = $detailRows | Where-Object { $_.Status -eq 'Unexpected' }
					$lines.Add(""); $lines.Add("# ----------------------------------------------------------------")
					$lines.Add("# UNERWARTETE SYSADMIN-KONTEN ($cntUnexpected)  ? PRueFEN")
					$lines.Add("# ----------------------------------------------------------------")
					if ($unexpected)
					{
						foreach ($e in ($unexpected | Sort-Object LoginType, LoginName))
						{
							$lines.Add(("  {0,-40} {1,-20} Enabled:{2,-5} Erstellt:{3}" -f $e.LoginName, $e.LoginType, $e.IsEnabled, $e.CreateDate))
						}
					}
					else { $lines.Add("  (keine)") }
					
					# Deaktivierte Konten
					$disabledEntries = $detailRows | Where-Object { $_.Status -eq 'Disabled' }
					$lines.Add(""); $lines.Add("# ----------------------------------------------------------------")
					$lines.Add("# DEAKTIVIERTE SYSADMIN-KONTEN ($cntDisabled)")
					$lines.Add("# ----------------------------------------------------------------")
					if ($disabledEntries)
					{
						foreach ($e in ($disabledEntries | Sort-Object LoginName))
						{
							$lines.Add("  $($e.LoginName)  [$($e.LoginType)]  Erstellt: $($e.CreateDate)")
						}
					}
					else { $lines.Add("  (keine)") }
					
					# SA-Konto
					$saEntry = $detailRows | Where-Object { $_.Status -eq 'SA' }
					$lines.Add(""); $lines.Add("# ----------------------------------------------------------------")
					$lines.Add("# SA-KONTO (SID 0x01)")
					$lines.Add("# ----------------------------------------------------------------")
					if ($saEntry)
					{
						foreach ($e in $saEntry)
						{
							$lines.Add(("  Name: {0,-40} Enabled: {1}" -f $e.LoginName, $e.IsEnabled))
						}
					}
					else { $lines.Add("  (nicht gefunden)") }
					
					# Ausgeschlossene Konten
					$excludedEntries = $detailRows | Where-Object { $_.Status -eq 'Excluded' }
					$lines.Add(""); $lines.Add("# ----------------------------------------------------------------")
					$lines.Add("# AUSGESCHLOSSENE KONTEN ($cntExcluded)")
					$lines.Add("# ----------------------------------------------------------------")
					if ($excludedEntries)
					{
						foreach ($e in ($excludedEntries | Sort-Object LoginType, LoginName))
						{
							$lines.Add(("  {0,-40} {1,-20} Enabled:{2}" -f $e.LoginName, $e.LoginType, $e.IsEnabled))
						}
					}
					else { $lines.Add("  (keine)") }
					
					$lines | Out-File -FilePath $txtFile -Encoding UTF8 -Force
					$detailRows | Export-Csv -Path $csvFile -Encoding UTF8 -NoTypeInformation -Force
					
					Invoke-sqmLogging -Message "[$instance] Bericht erstellt: $txtFile" -FunctionName $functionName -Level "INFO"
				}
				else
				{
					Invoke-sqmLogging -Message "[$instance] WhatIf: Berichtsdateien wuerden erstellt werden." -FunctionName $functionName -Level "VERBOSE"
					$txtFile = $null
					$csvFile = $null
				}
				
				if ($cntBuiltinAdmins -gt 0)
				{
					Invoke-sqmLogging -Message ("[$instance] BUILTIN\Administrators hat Sysadmin-Rechte - Sicherheitspruefung erforderlich!") -FunctionName $functionName -Level "WARNING"
				}
				if ($cntUnexpected -gt 0)
				{
					Invoke-sqmLogging -Message ("[$instance] $cntUnexpected unerwartete(s) sysadmin-Konto(en) gefunden.") -FunctionName $functionName -Level "WARNING"
				}
				
				$instanceResult = [PSCustomObject]@{
					SqlInstance							     = $instance
					Timestamp							     = $timestamp
					DetailRows							     = $detailRows
					TxtFile								     = $txtFile
					CsvFile								     = $csvFile
					Status								     = if ($cntUnexpected -gt 0 -or $cntBuiltinAdmins -gt 0) { 'Warning' } else { 'OK' }
				}
				$allInstanceResults.Add($instanceResult)
			}
			catch
			{
				$errMsg = "Fehler auf '$instance': $($_.Exception.Message)"
				Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR"
				$allInstanceResults.Add([PSCustomObject]@{
						SqlInstance = $instance
						Status	    = 'Error'
						Message	    = $errMsg
						DetailRows  = $null
						TxtFile	    = $null
						CsvFile	    = $null
					})
				if ($EnableException) { throw }
				if (-not $ContinueOnError) { throw $_ }
			}
		}
	}
	
	end
	{
		Invoke-sqmLogging -Message "$functionName abgeschlossen. $($allInstanceResults.Count) Instanzen verarbeitet." -FunctionName $functionName -Level "INFO"
		return $allInstanceResults
	}
}
Invoke-sqmLoginAudit Sicherheit
Checks per login: - POLICY VIOLATIONS (CHECK_POLICY/EXPIRATION/MUST_CHANGE) - Password age and whether it was never changed - Inactive / never-used logins - Duplicate SIDs (failed
▶ 2 Beispiele anzeigen
Invoke-sqmLoginAudit
Invoke-sqmLoginAudit
Invoke-sqmLoginAudit -SqlInstance "SQL01" -CheckAdOrphans -IncludeSystemLogins
Invoke-sqmLoginAudit -SqlInstance "SQL01" -CheckAdOrphans -IncludeSystemLogins
Invoke-sqmSaObfuscation Sicherheit
Performs the following steps: 1. Checks that at least one other active login with sysadmin rights exists (aborts otherwise). 2. Identifies the SA account via its fixed SID 0x01 (rename-safe)
▶ 2 Beispiele anzeigen
Invoke-sqmSaObfuscation -SqlInstance "SQL01"
Invoke-sqmSaObfuscation -SqlInstance "SQL01"
Invoke-sqmSaObfuscation -SqlInstance "SQL01" -NewName "hidden_sa" -PasswordLength 24
Invoke-sqmSaObfuscation -SqlInstance "SQL01" -NewName "hidden_sa" -PasswordLength 24
Set-sqmDatabaseOwner Sicherheit
Checks and corrects the database owner on one or more SQL Server instances. Typical use case: after restores or migrations the owner is often a login that no longer exists or is incorrect. T
▶ 4 Beispiele anzeigen
# Set sa account on all user databases
    Set-sqmDatabaseOwner -SqlInstance "SQL01"
# Specific databases with a custom login
    Set-sqmDatabaseOwner -SqlInstance "SQL01" -Database "Prod*" -OwnerLogin "svc_sqlowner"
# Pipeline across multiple instances
    'SQL01','SQL02' | Set-sqmDatabaseOwner
# WhatIf - only show what would be changed
    Set-sqmDatabaseOwner -SqlInstance "SQL01" -WhatIf

🩺 Diagnose & Health

Copy-sqmNTFSPermissions Diagnose
Reads the explicit NTFS permissions for each file system object (folder/file) below the source path and applies them to the corresponding object below the destination path. The target structur
▶ 2 Beispiele anzeigen
Copy-sqmNTFSPermissions -SourcePath "D:\" -DestinationPath "E:\" -Recurse
    Copies all permissions from D: to E: (recursively).
Copy-sqmNTFSPermissions -SourcePath "D:\Daten" -DestinationPath "E:\Daten" -Recurse -CreateMissingFolders
    Copies permissions and creates missing target folders.
Get-sqmConnectionStats Diagnose
Reads sys.dm_exec_sessions and sys.dm_exec_connections and groups by application, login, host or database. Shows connection load, active requests, CPU usage and oldest connections.
▶ 3 Beispiele anzeigen
Get-sqmConnectionStats -SqlInstance "SQL01"
Get-sqmConnectionStats -SqlInstance "SQL01"
Get-sqmConnectionStats -SqlInstance "SQL01" -GroupBy Login -TopN 10
Get-sqmConnectionStats -SqlInstance "SQL01" -GroupBy Login -TopN 10
Get-sqmConnectionStats -SqlInstance "SQL01" -GroupBy Database -IncludeSystemConnections
Get-sqmConnectionStats -SqlInstance "SQL01" -GroupBy Database -IncludeSystemConnections
Get-sqmDatabaseHealth Diagnose
Checks per database: - Recovery model - Last DBCC CHECKDB execution and whether it was error-free - Last backup times (Full / Diff / Log) - AutoGrowth events in the last -HistoryDa
▶ 2 Beispiele anzeigen
Get-sqmDatabaseHealth
Get-sqmDatabaseHealth
Get-sqmDatabaseHealth -SqlInstance "SQL01" -IncludeSystemDatabases -OutputPath "D:\Reports"
Get-sqmDatabaseHealth -SqlInstance "SQL01" -IncludeSystemDatabases -OutputPath "D:\Reports"
Get-sqmDiskInfoByDriveLetter Diagnose
Accepts a drive letter, determines the associated disk number (disk number) and returns the total size, free space, percentage free and the serial number (LUN serial number) of the physical di
▶ 3 Beispiele anzeigen
Get-sqmDiskInfoByDriveLetter -DriveLetter "C"
    Returns disk information for drive C: and copies it to the clipboard.
Get-sqmDiskInfoByDriveLetter "D:" -NoClipboard
    Returns disk information for drive D: without clipboard output.
"C","D","E" | ForEach-Object { Get-sqmDiskInfoByDriveLetter $_ }
    Returns disk information for multiple drives.
Get-sqmDiskSpaceReport Diagnose
Queries sys.dm_os_volume_stats for all database files and determines: - Free disk space per volume - Total size of database files on the volume - AutoGrowth volume over the last -Histor
▶ 2 Beispiele anzeigen
Get-sqmDiskSpaceReport
Get-sqmDiskSpaceReport
Get-sqmDiskSpaceReport -SqlInstance "SQL01" -WarnThresholdPct 15 -OutputPath "D:\Reports"
Get-sqmDiskSpaceReport -SqlInstance "SQL01" -WarnThresholdPct 15 -OutputPath "D:\Reports"
Get-sqmOperationStatus Diagnose
The function monitors active SQL Server operations (backup, restore, AutoSeed) and calculates the progress and estimated remaining time. It combines information from: - Backup and restore progress:
▶ 3 Beispiele anzeigen
# Show all active operations on the local instance
Get-sqmOperationStatus
# Only active AutoSeed operations on a remote instance
Get-sqmOperationStatus -SqlInstance "SQL01" -OperationType AutoSeed
# Continuous refresh every 10 seconds
Get-sqmOperationStatus -Continuous -RefreshSeconds 10
Get-sqmOrphanedFiles Diagnose
Reads all registered database files from sys.master_files and compares them with the files actually present in the directories. Files that exist on the file system but are not registered in sy
▶ 2 Beispiele anzeigen
Get-sqmOrphanedFiles -SqlInstance "SQL01"
Get-sqmOrphanedFiles -SqlInstance "SQL01"
Get-sqmOrphanedFiles -SqlInstance "SQL01" -SearchPath "D:\SQLData","E:\SQLLog" -Recurse
Get-sqmOrphanedFiles -SqlInstance "SQL01" -SearchPath "D:\SQLData","E:\SQLLog" -Recurse
Get-sqmSpnReport Diagnose
Automatically determines all SQL Server services on the specified computer, identifies the service account per instance and derives the AD account for the SPN check. Supported service acc
▶ 4 Beispiele anzeigen
Get-sqmSpnReport
    Checks all SQL Server instances on the local computer.
Get-sqmSpnReport -ComputerName 'SQL01' -InstanceFilter 'MSSQLSERVER'
    Checks only the default instance on SQL01.
'SQL01','SQL02' | Get-sqmSpnReport -ContinueOnError
    Checks all instances on two servers; errors are skipped.
$result = Get-sqmSpnReport -ComputerName 'SQL01'
    $result.DetailRows | Where-Object Status -eq 'Missing' | Select-Object Spn, SetSpnCommand
    Returns only missing SPNs with the ready-to-use setspn command.
Get-sqmSQLInstanceCheck Diagnose
The function performs a series of best practice checks: - Max Degree of Parallelism (MAXDOP) - recommendation based on number of cores - Max Server Memory - should not be too high (reserve for OS)
▶ 2 Beispiele anzeigen
Get-sqmSQLInstanceCheck
Get-sqmSQLInstanceCheck
Get-sqmSQLInstanceCheck -SqlInstance "SQL01\INSTANCE" -Detailed
Get-sqmSQLInstanceCheck -SqlInstance "SQL01\INSTANCE" -Detailed
Get-sqmTempDbRecommendation Diagnose
Checks the number and size of TempDB files, autogrow settings and the path. Recommends file count (matching CPU core count, max 8), equal sizes, MB-based autogrow, and separate drives where po
▶ 1 Beispiel anzeigen
Get-sqmTempDbRecommendation -SqlInstance "SQL01"
#>
function Get-sqmTempDbRecommendation
{
	[CmdletBinding()]
	[OutputType([PSCustomObject])]
	param (
		[Parameter(Mandatory = $false)]
		[string]$SqlInstance = $env:COMPUTERNAME,
		[Parameter(Mandatory = $false)]
		[System.Management.Automation.PSCredential]$SqlCredential,
		[Parameter(Mandatory = $false)]
		[string]$OutputPath,
		[Parameter(Mandatory = $false)]
		[switch]$EnableException
	)
	
	begin
	{
		$functionName = $MyInvocation.MyCommand.Name
		if (-not (Get-Module -ListAvailable -Name dbatools))
		{
			throw "dbatools-Modul nicht gefunden."
		}
	}
	
	process
	{
		try
		{
			$server = Connect-DbaInstance -SqlInstance $SqlInstance -SqlCredential $SqlCredential -ErrorAction Stop
			$tempdb = $server.Databases['tempdb']
			$cpuCount = $server.Processors
			$idealFileCount = [Math]::Min($cpuCount, 8)
			
			$files = $tempdb.FileGroups[0].Files
			$fileCount = $files.Count
			$fileSizeMB = $files | ForEach-Object { [math]::Round($_.Size / 1024, 2) }
			$fileGrowth = $files.ForEach('Growth') | ForEach-Object { ($_ / 1024) } # in MB
			$growthTypes = $files.ForEach('GrowthType')
			$paths = $files.ForEach('FileName') | ForEach-Object { Split-Path $_ -Parent }
			
			# Bewertung
			$status = 'OK'
			$messages = [System.Collections.Generic.List[string]]::new()
			if ($fileCount -ne $idealFileCount)
			{
				$status = 'Warning'
				$messages.Add("Anzahl TempDB-Dateien: $fileCount (empfohlen $idealFileCount).")
			}
			$sizeDifferences = ($fileSizeMB | Select-Object -Unique).Count -gt 1
			if ($sizeDifferences)
			{
				$status = 'Warning'
				$messages.Add("TempDB-Dateien haben unterschiedliche Groessen: $($fileSizeMB -join ', ') MB.")
			}
			$hasPercent = $growthTypes -contains 'Percent'
			if ($hasPercent)
			{
				$status = 'Warning'
				$messages.Add("Autogrow in Prozent wird verwendet (MB empfohlen).")
			}
			$hasLargeGrow = $fileGrowth -gt 1024
			if ($hasLargeGrow)
			{
				$status = 'Warning'
				$messages.Add("Autogrow-Schrittweite >1024 MB: $($fileGrowth -join ', ') MB.")
			}
			$uniquePaths = $paths | Select-Object -Unique
			if ($uniquePaths.Count -eq 1)
			{
				$messages.Add("Alle TempDB-Dateien liegen auf demselben Laufwerk ($($uniquePaths[0])) - fuer optimale Leistung separate Laufwerke empfehlenswert.")
				if ($status -eq 'OK') { $status = 'Info' }
			}
			if ($messages.Count -eq 0) { $messages.Add("TempDB-Konfiguration ist optimal.") }
			
			$result = [PSCustomObject]@{
				SqlInstance	     = $SqlInstance
				Status		     = $status
				FileCount	     = $fileCount
				RecommendedCount = $idealFileCount
				FileSizesMB	     = $fileSizeMB
				GrowthMB		 = $fileGrowth
				Paths		     = $paths
				Recommendations  = ($messages -join ' ')
			}
			
			if ($OutputPath) { $result | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 -Force }
			return $result
		}
		catch
		{
			Invoke-sqmLogging -Message $_.Exception.Message -FunctionName $functionName -Level "ERROR"
			if ($EnableException) { throw }
			return $null
		}
	}
}
Invoke-sqmPatchAnalysis Diagnose
Reads the installed SQL Server version (ProductVersion) and compares it against an embedded reference table of known builds. Indicates whether the instance is current, how many builds it lags
▶ 3 Beispiele anzeigen
Invoke-sqmPatchAnalysis -SqlInstance "SQL01"
Invoke-sqmPatchAnalysis -SqlInstance "SQL01"
"SQL01","SQL02","SQL03" | Invoke-sqmPatchAnalysis
"SQL01","SQL02","SQL03" | Invoke-sqmPatchAnalysis
Invoke-sqmPatchAnalysis -SqlInstance "SQL01","SQL02" -OutputPath "D:\Reports"
Invoke-sqmPatchAnalysis -SqlInstance "SQL01","SQL02" -OutputPath "D:\Reports"
Invoke-sqmSetupReport Diagnose
Fuehrt alle konfigurierten Setup-Checks durch und erzeugt einen HTML-Report mit OK/WARN/ERROR-Badges. Welche Checks ausgefuehrt werden haengt vom CheckProfile in der Modulkonfiguration ab:
▶ 3 Beispiele anzeigen
# Am Ende von PostInstall - CheckProfile aus Modulkonfiguration
    Invoke-sqmSetupReport -SqlInstance "SQL01"
# FI-TS-Checks erzwingen (z.B. fuer Tests ausserhalb der Domaene)
    Invoke-sqmSetupReport -SqlInstance "SQL01" -CheckProfile FiTs -PassThru
# Nur generische Checks - kein FI-TS-Profil
    Invoke-sqmSetupReport -SqlInstance "SQL01" -CheckProfile Generic
New-sqmAgentProxy Diagnose
Legt in einem Schritt einen neuen SQL Server Credential an und erstellt darauf basierend einen SQL Server Agent Proxy. Die Windows-Credentials werden interaktiv per Get-Credential abgefragt. D
▶ 5 Beispiele anzeigen
# Einzeiler - Credential-Dialog erscheint automatisch
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "DOMAIN\SqlServiceAccount" `
        -ProxyName "SSIS Proxy"
    # Credential direkt uebergeben - kein Dialog
    $cred = Get-Credential "DOMAIN\SvcSSIS"
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "DOMAIN\SvcSSIS" `
        -ProxyName "SSIS Proxy" -WindowsCredential $cred
# Nur SSIS - Benutzername vorausgewaehlt im Dialog
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "DOMAIN\SvcSSIS" `
        -ProxyName "SSIS Only Proxy" -Subsystem SSIS
# CmdExec und PowerShell
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "DOMAIN\SvcPS" `
        -ProxyName "Script Proxy" -Subsystem CmdExec, PowerShell
# Abweichender Windows-Account und Force
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "ProxyCred_SSIS" `
        -ProxyName "SSIS Proxy" -WindowsUserName "DOMAIN\SvcSSIS" -Force
# Unattended / Skript-Betrieb mit SecureString aus Vault
    $secPwd = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
    $cred   = New-Object System.Management.Automation.PSCredential("DOMAIN\SvcSSIS", $secPwd)
    New-sqmAgentProxy -SqlInstance "SQL01" -CredentialName "DOMAIN\SvcSSIS" `
        -ProxyName "SSIS Proxy" -WindowsCredential $cred -Subsystem SSIS
    New-sqmAgentProxy -SqlInstance "SQL01\INST1" -CredentialName "DOMAIN\SvcSSIS" `
        -ProxyName "SSIS Execution Proxy" -ProxyDescription "Fuehrt SSIS-Pakete aus" `
        -WindowsCredential $winCred -Force
Test-sqmCostThreshold Diagnose
Liest den aktuellen Wert von CostThresholdForParallelism per SMO und vergleicht ihn mit dem konfigurierbaren Mindestwert (Standard: 50). Der SQL Server Default von 5 ist fuer moderne Systeme i
▶ 2 Beispiele anzeigen
Test-sqmCostThreshold -SqlInstance "SQL01"
Test-sqmCostThreshold -SqlInstance "SQL01"
Test-sqmCostThreshold -SqlInstance "SQL01" -MinRecommendedValue 25
Test-sqmCostThreshold -SqlInstance "SQL01" -MinRecommendedValue 25
Test-sqmTempDbFileCount Diagnose
Liest die Anzahl der TempDB-Datendateien (Typ = Rows, ohne Log) per SMO und vergleicht sie mit der Anzahl der CPU-Kerne des Servers (max 8 gemaess Microsoft-Empfehlung). Hintergrund: Zu w
▶ 2 Beispiele anzeigen
Test-sqmTempDbFileCount -SqlInstance "SQL01"
Test-sqmTempDbFileCount -SqlInstance "SQL01"
Test-sqmTempDbFileCount -SqlInstance "SQL01\INST1" -MaxFiles 4
Test-sqmTempDbFileCount -SqlInstance "SQL01\INST1" -MaxFiles 4

⚡ Performance

Get-sqmAutoGrowthReport Performance
Analyzes all data and log files of the accessible databases and evaluates their AutoGrowth settings. Returns warnings for percent-based growth, growth values that are too small or too large, and
▶ 2 Beispiele anzeigen
Get-sqmAutoGrowthReport -SqlInstance "SQL01"
Get-sqmAutoGrowthReport -SqlInstance "SQL01"
Get-sqmAutoGrowthReport -SqlInstance "SQL01" -Detailed -IncludeSystem
Get-sqmAutoGrowthReport -SqlInstance "SQL01" -Detailed -IncludeSystem
Get-sqmBlockingReport Performance
Reads sys.dm_exec_requests, sys.dm_exec_sessions and sys.dm_exec_sql_text and builds complete blocking chains. For each blocked session the following is returned: - Blocking SPID and its S
▶ 4 Beispiele anzeigen
Get-sqmBlockingReport
Get-sqmBlockingReport
Get-sqmBlockingReport -SqlInstance "SQL01" -MinWaitSeconds 30
Get-sqmBlockingReport -SqlInstance "SQL01" -MinWaitSeconds 30
# Check whether blocking is currently occurring
    if ((Get-sqmBlockingReport -SqlInstance "SQL01").HasBlocking) { Write-Warning "Blocking detected!" }
# Regular snapshot via Agent job
    Get-sqmBlockingReport -SqlInstance "SQL01" -OutputPath "$env:ProgramData\sqmSQLTool\Logs\Blocking"
Get-sqmDeadlockReport Performance
The System Health session (always active since SQL Server 2008) logs all deadlocks as XML in the ring buffer. This function reads that buffer, parses the deadlock graphs and returns for each
▶ 4 Beispiele anzeigen
Get-sqmDeadlockReport
Get-sqmDeadlockReport
Get-sqmDeadlockReport -SqlInstance "SQL01" -StartTime (Get-Date).AddDays(-7)
Get-sqmDeadlockReport -SqlInstance "SQL01" -StartTime (Get-Date).AddDays(-7)
# Save deadlocks as XDL files for SSMS
    Get-sqmDeadlockReport -SqlInstance "SQL01" -OutputPath "$env:ProgramData\sqmSQLTool\Logs\Deadlocks"
# Only deadlocks from the last hour, show number of affected statements
    Get-sqmDeadlockReport -StartTime (Get-Date).AddHours(-1) |
        Select-Object Timestamp, VictimLogin, VictimStatement, ProcessCount
Get-sqmIndexFragmentation Performance
Returns the fragmentation level (%) for all indexes and recommends an action: - 5-30% -> REORGANIZE - >30% -> REBUILD Output can be restricted to specific databases, tables or a
▶ 2 Beispiele anzeigen
Get-sqmIndexFragmentation -Database 'AdventureWorks' -MinFragmentationPercent 10
Get-sqmIndexFragmentation -Database 'AdventureWorks' -MinFragmentationPercent 10
Get-sqmIndexFragmentation -SqlInstance 'SQL01' -MinFragmentationPercent 30
Get-sqmIndexFragmentation -SqlInstance 'SQL01' -MinFragmentationPercent 30
Get-sqmLongRunningQueries Performance
Reads sys.dm_exec_requests, sys.dm_exec_sessions, sys.dm_exec_sql_text and sys.dm_exec_query_plan and returns all active requests that exceed the configured thresholds. Per query the
▶ 4 Beispiele anzeigen
Get-sqmLongRunningQueries
Get-sqmLongRunningQueries
Get-sqmLongRunningQueries -SqlInstance "SQL01" -MinDurationSeconds 60
Get-sqmLongRunningQueries -SqlInstance "SQL01" -MinDurationSeconds 60
# Top 10 by duration
    Get-sqmLongRunningQueries -MinDurationSeconds 10 | Sort-Object DurationSeconds -Descending | Select-Object -First 10
# Regular snapshot via Agent job
    Get-sqmLongRunningQueries -MinDurationSeconds 120 -OutputPath "$env:ProgramData\sqmSQLTool\Logs\LongRunning"
Get-sqmMissingIndexes Performance
Reads sys.dm_db_missing_index_details, sys.dm_db_missing_index_groups and sys.dm_db_missing_index_group_stats and calculates an impact score (using the Microsoft formula) and a ready-to-use
▶ 4 Beispiele anzeigen
Get-sqmMissingIndexes -SqlInstance "SQL01"
Get-sqmMissingIndexes -SqlInstance "SQL01"
# Only high-impact recommendations
    Get-sqmMissingIndexes -SqlInstance "SQL01" -MinImpactScore 50 -MinSeeks 500
# Show top 10 and save as CSV
    Get-sqmMissingIndexes -SqlInstance "SQL01" -Top 10 -OutputPath "D:\Reports"
# Output CREATE INDEX statements directly
    Get-sqmMissingIndexes -SqlInstance "SQL01" -MinImpactScore 30 |
        Select-Object DatabaseName, TableName, ImpactScore, CreateIndexStatement |
        Format-List
Get-sqmPerfCounters Performance
Returns the most important SQL Server performance counters: Buffer Cache Hit Ratio, Page Life Expectancy, Batch Requests/sec, compilations, lock waits, memory, connections, scans and more.
▶ 2 Beispiele anzeigen
Get-sqmPerfCounters -SqlInstance "SQL01"
Get-sqmPerfCounters -SqlInstance "SQL01"
Get-sqmPerfCounters -SqlInstance "SQL01" -Category "Buffer","Memory"
Get-sqmPerfCounters -SqlInstance "SQL01" -Category "Buffer","Memory"
Get-sqmWaitStatistics Performance
Reads the cumulative wait statistics of the instance, filters out known idle waits and returns the top-N waits with category and recommended action. Optional: snapshot comparison (before/after
▶ 2 Beispiele anzeigen
Get-sqmWaitStatistics -SqlInstance "SQL01" -TopN 20
Get-sqmWaitStatistics -SqlInstance "SQL01" -TopN 20
$before = Get-sqmWaitStatistics -SqlInstance "SQL01" -SaveSnapshot
    Get-sqmWaitStatistics -SqlInstance "SQL01" -SnapshotBefore $before
Invoke-sqmExtendedEvents Performance
Creates, starts, stops, reads and evaluates Extended Events sessions. Operating modes (switches, combinable): -Create Creates a new XEvent session based on a template. -Start S
▶ 4 Beispiele anzeigen
# Create AllInOne session and start immediately
    Invoke-sqmExtendedEvents -SqlInstance SQL01 -Create -Start
# Record Slow Queries > 2 seconds, save to file
    Invoke-sqmExtendedEvents -SqlInstance SQL01 -Template SlowQueries -SlowQueryThresholdMs 2000 -TargetType File -Create -Start
# Read running session and create report
    Invoke-sqmExtendedEvents -SqlInstance SQL01 -Read -Diagnose
# Stop session and remove it
    Invoke-sqmExtendedEvents -SqlInstance SQL01 -Stop -Drop
Invoke-sqmPerfBaseline Performance
Capture: Saves the current snapshot of sys.dm_os_wait_stats and sys.dm_os_performance_counters as a JSON file. Compare: Calculates the delta between two baselines. List: Lists all saved
▶ 3 Beispiele anzeigen
# Capture baseline
    Invoke-sqmPerfBaseline -SqlInstance "SQL01" -BaselineName "before_patch"
# Capture baseline after change and compare
    Invoke-sqmPerfBaseline -SqlInstance "SQL01" -BaselineName "after_patch"
    Invoke-sqmPerfBaseline -SqlInstance "SQL01" -Action Compare
# List all baselines
    Invoke-sqmPerfBaseline -SqlInstance "SQL01" -Action List
Invoke-sqmQueryStore Performance
Comprehensive Query Store management for one, multiple or all user databases. Operating modes (switches, combinable): -Configure Enables and configures the Query Store (ALTER DATABASE SET
▶ 4 Beispiele anzeigen
# Report for all databases (Query + Diagnose)
    Invoke-sqmQueryStore -All
# Configure Query Store and query immediately
    Invoke-sqmQueryStore -Database "SalesDB","CRM" -Configure -Query -Diagnose
# Top 50 queries by CPU consumption, last 48 hours
    Invoke-sqmQueryStore -Database "SalesDB" -Query -TopN 50 -OrderBy CPU -LookbackHours 48
# Diagnostics with storage warning from 70% and save report
    Invoke-sqmQueryStore -All -Diagnose -StorageWarningPct 70 -OutputPath "D:\Reports\QS"
Invoke-sqmUpdateStatistics Performance
Executes UPDATE STATISTICS with configurable options (scan percentage, only modified statistics, etc.). Can be restricted to specific databases, tables, or statistics.
▶ 1 Beispiel anzeigen
Invoke-sqmUpdateStatistics -Database 'SalesDB' -SamplePercent 10
Invoke-sqmUpdateStatistics -Database 'SalesDB' -SamplePercent 10

🔧 Wartung

Invoke-sqmFormatDrive64k Wartung
Process: 1. Safety checks (not C:, NTFS, one primary partition). 2. Save drive metadata (letter, label, partition size). 3. Check allocation unit via Get-Volume / fsutil.
▶ 3 Beispiele anzeigen
Invoke-sqmFormatDrive64k -DriveLetter D
    Checks drive D: and formats it with 64 KB clusters if needed.
    Data is backed up to C:\Temp\DriveBackup first.
Invoke-sqmFormatDrive64k -DriveLetter E -BackupPath "C:\Backup\DriveTemp" -Force
    Same as above, without confirmation prompt, using a different backup path.
Invoke-sqmFormatDrive64k -DriveLetter D -WhatIf
    Simulates the entire process without making any changes.
Test-sqmOlaInstallation Wartung
Tests for the presence of the stored procedure 'DatabaseBackup' in the 'master' schema. Optionally checks whether the 'CommandLog' table and 'DatabaseIntegrityCheck' etc. are also present.
Test-sqmSQLFirewall Wartung
Attempts to establish a TCP connection to the specified SQL Server and port. By default, port 1433 (default instance) is used. For named instances, the SQL Browser service (UDP 1434) can addi
▶ 4 Beispiele anzeigen
Test-sqmSQLFirewall -Server "SQL01"
    Tests the default instance on TCP port 1433.
Test-sqmSQLFirewall -Server "SQL01" -Port 54321
    Tests a custom port.
Test-sqmSQLFirewall -Server "SQL01" -Instance "SAGE"
    Determines the dynamic port of the "SAGE" instance via SQL Browser (UDP 1434)
    and then tests the TCP connection.
"SQL01","SQL02","SQL03" | Test-sqmSQLFirewall -Instance "PROD" -TimeoutSeconds 3
    Tests the "PROD" instance on three servers via pipeline.

⚙️ Konfiguration

Compare-sqmServerConfiguration Konfiguration
Displays differences in the following areas: sp_configure, instance properties (Collation, Version, MaxMemory), database settings (optional). Output as a list with old/new values.
▶ 1 Beispiel anzeigen
Compare-sqmServerConfiguration -SourceInstance "SQL01" -TargetInstance "SQL02"
Compare-sqmServerConfiguration -SourceInstance "SQL01" -TargetInstance "SQL02"
Get-sqmConfig Konfiguration
Without parameters, the entire configuration is returned as a hashtable. With -Key, the value of the requested key is returned. If the key does not exist, a warning is shown and $null is ret
▶ 2 Beispiele anzeigen
Get-sqmConfig
Get-sqmConfig
Get-sqmConfig -Key 'OutputPath'
#>
function Get-sqmConfig
{
	[CmdletBinding()]
	param (
		[Parameter(Mandatory = $false)]
		[string]$Key
	)
	if ($Key)
	{
		if ($script:sqmModuleConfig.ContainsKey($Key))
		{
			return $script:sqmModuleConfig[$Key]
		}
		else
		{
			Write-Warning "Konfigurationsschluessel '$Key' existiert nicht. Verfuegbare Schluessel: $($script:sqmModuleConfig.Keys -join ', ')"
			return $null
		}
	}
	return $script:sqmModuleConfig
}
Get-sqmServerSetting Konfiguration
The function queries either a named property value (e.g. "BackupDirectory") from the object returned by Connect-DbaInstance, or lists all properties with -All. If no SqlInstance parameter is speci
▶ 3 Beispiele anzeigen
# Read BackupDirectory from the local server
$backupPath = Get-sqmServerSetting -Name "BackupDirectory"
# Show all properties
Get-sqmServerSetting -All
# All properties from a remote instance with credentials
$cred = Get-Credential
Get-sqmServerSetting -SqlInstance "SQL01" -SqlCredential $cred -All
Invoke-sqmCollationChange Konfiguration
Changes the SQL Server instance collation using the undocumented method "sqlservr.exe -m -T4022 -T3659 -q ''". This function is only suitable for local standalone instances (no AG
▶ 2 Beispiele anzeigen
Invoke-sqmCollationChange -NewCollation "Latin1_General_CI_AS"
Invoke-sqmCollationChange -NewCollation "Latin1_General_CI_AS"
Invoke-sqmCollationChange -SqlInstance "SQL01\INST2" -NewCollation "German_CI_AS" -IncludeUserDatabases -BackupBeforeChange
Invoke-sqmCollationChange -SqlInstance "SQL01\INST2" -NewCollation "German_CI_AS" -IncludeUserDatabases -BackupBeforeChange
Invoke-sqmSetDatabaseRecoveryMode Konfiguration
Sets the recovery mode (Simple, Full, BulkLogged) for all or selected user databases on a SQL Server instance. System databases are automatically excluded. If the SqlInstance parameter is not spec
▶ 2 Beispiele anzeigen
# Set all user databases to Full (without prompting)
Invoke-sqmSetDatabaseRecoveryMode -All -RecoveryMode Full
# With confirmation prompt (passed to Set-DbaDbRecoveryModel)
Invoke-sqmSetDatabaseRecoveryMode -Database "SalesDB" -RecoveryMode Simple -Confirm
Invoke-sqmSplunkConfiguration Konfiguration
Detects all SQL Server instances, sets machine-wide environment variables for the ErrorLog path (MSSQL1_Log, MSSQL2_Log, ...) and manages the SplunkForwarder service — locally or remot
▶ 5 Beispiele anzeigen
Invoke-sqmSplunkConfiguration
Invoke-sqmSplunkConfiguration
Invoke-sqmSplunkConfiguration -Mode Test
Invoke-sqmSplunkConfiguration -Mode Test
Invoke-sqmSplunkConfiguration -Remote -SearchOU "OU=DB-Server,DC=contoso,DC=com"
Invoke-sqmSplunkConfiguration -Remote -SearchOU "OU=DB-Server,DC=contoso,DC=com"
Invoke-sqmSplunkConfiguration -ComputerList "SRV-SQL01","SRV-SQL02"
Invoke-sqmSplunkConfiguration -ComputerList "SRV-SQL01","SRV-SQL02"
Invoke-sqmSplunkConfiguration -ComputerList "C:\Listen\db-server.txt" -Mode Test
Invoke-sqmSplunkConfiguration -ComputerList "C:\Listen\db-server.txt" -Mode Test
Invoke-sqmSsisConfiguration Konfiguration
Performs a complete initial or re-configuration of SSIS: 1. SSIS service (service account + startup type) 2. SSISDB catalog (incl. CLR activation, properties) 3. AlwaysOn AG integration
▶ 2 Beispiele anzeigen
$pwd = Read-Host "SSISDB-Kennwort" -AsSecureString
    Invoke-sqmSsisConfiguration -SqlInstance "SQL01" -CatalogPassword $pwd
$pwd = Read-Host "SSISDB-Kennwort" -AsSecureString
    Invoke-sqmSsisConfiguration -SqlInstance "SQL01" -AgName "AG_SSIS" -CatalogPassword $pwd
Set-sqmConfig Konfiguration
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 va
▶ 4 Beispiele anzeigen
Set-sqmConfig -LogPath "D:\Logs" -OlaJobNameFull "Prod-FULL"
Set-sqmConfig -LogPath "D:\Logs" -OlaJobNameFull "Prod-FULL"
Set-sqmConfig -TsmManagementClasses @('MC_10','MC_30','MC_100')
Set-sqmConfig -TsmManagementClasses @('MC_10','MC_30','MC_100')
Set-sqmConfig -HpuDomainGroupMap @(
        [PSCustomObject]@{ DomainPattern = '*.sfinance.net'; GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' },
        [PSCustomObject]@{ DomainPattern = '*';              GroupNamePattern = 'Rg_DC_AouAllowManageAuditSecLogSrvAll_Mod' }
    )
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('Auto', 'FiTs', 'Generic')]
		[string]$CheckProfile,
		[Parameter(Mandatory = $false)]
		[ValidateRange(1, 1000)]
		[int]$CheckCostThresholdMin,
		[Parameter(Mandatory = $false)]
		[ValidateRange(1, 64)]
		[int]$CheckTempDbMaxFiles,
		[Parameter(Mandatory = $false)]
		[ValidateSet(4096, 8192, 16384, 32768, 65536, 131072)]
		[int]$CheckDiskBlockSize,
		[Parameter(Mandatory = $false)]
		[ValidateSet('de-DE', 'en-US')]
		[string]$Language,
		[Parameter(Mandatory = $false)]
		[switch]$PassThru
	)
	
	# Hilfsfunktion zum Pruefen/Erstellen eines Pfads
	# Pfad-Existenz und Schreibbarkeit werden geprueft wenn moeglich.
	# Nicht-erreichbare Pfade erzeugen nur eine Warnung - kein Fehler.
	# Konfiguration wird trotzdem gespeichert (Pfad kann spaeter entstehen).
	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."
			}
			# Schreibtest nur wenn Pfad erreichbar - Fehler hier ist nicht kritisch
			try
			{
				$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 SilentlyContinue
			}
			catch
			{
				Write-Warning "Pfad '$Path' ($Purpose) ist nicht beschreibbar: $($_.Exception.Message). Konfiguration wird trotzdem gespeichert."
			}
			return $true
		}
		catch
		{
			# Verzeichnis konnte nicht erstellt werden - nur warnen, nicht abbrechen
			Write-Warning "Pfad '$Path' ($Purpose) konnte nicht erstellt werden: $($_.Exception.Message). Wird spaeter automatisch angelegt. Konfiguration wird gespeichert."
			return $true
		}
	}
	
	$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
		}
	}
	
	# Check-Profil und Grenzwerte
	if ($PSBoundParameters.ContainsKey('CheckProfile'))
	{
		$globalConfig['CheckProfile'] = $CheckProfile
		$updated = $true
	}
	if ($PSBoundParameters.ContainsKey('CheckCostThresholdMin'))
	{
		$globalConfig['CheckCostThresholdMin'] = $CheckCostThresholdMin
		$updated = $true
	}
	if ($PSBoundParameters.ContainsKey('CheckTempDbMaxFiles'))
	{
		$globalConfig['CheckTempDbMaxFiles'] = $CheckTempDbMaxFiles
		$updated = $true
	}
	if ($PSBoundParameters.ContainsKey('CheckDiskBlockSize'))
	{
		$globalConfig['CheckDiskBlockSize'] = $CheckDiskBlockSize
		$updated = $true
	}

	# 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
	}
}
Set-sqmSsrsConfiguration Konfiguration
Performs a complete initial or re-configuration of SSRS. Supports Native Mode and SharePoint Integrated Mode (automatic detection). Configurable areas (individually disableable):
▶ 2 Beispiele anzeigen
Set-sqmSsrsConfiguration
Set-sqmSsrsConfiguration
Set-sqmSsrsConfiguration -ComputerName "SSRS01" -DatabaseServer "AG_Listener" -PbmPolicyName "Password Policy"
Set-sqmSsrsConfiguration -ComputerName "SSRS01" -DatabaseServer "AG_Listener" -PbmPolicyName "Password Policy"
Set-sqmTcpPort Konfiguration
Setzt den statischen TCP-Port fuer eine SQL Server-Instanz. Der Port wird aus BasePort und PortIncrement berechnet: - Default-Instanz (MSSQLSERVER): Port = BasePort - Named Instanc
▶ 2 Beispiele anzeigen
Set-sqmTcpPort -SqlInstance 'MSSQLSERVER' -BasePort 1433
Set-sqmTcpPort -SqlInstance 'MSSQLSERVER' -BasePort 1433
Set-sqmTcpPort -SqlInstance 'INST01' -BasePort 1433 -PortIncrement 10
Set-sqmTcpPort -SqlInstance 'INST01' -BasePort 1433 -PortIncrement 10
Export-sqmServerConfiguration Konfiguration
Exports all SQL Server configuration settings to a JSON snapshot file. Captures sp_configure, instance properties, services, TempDB, Database Mail and linked servers. Use before changes for rollback capability.
► 1 Beispiel anzeigen
Export-sqmServerConfiguration -SqlInstance "SQL01" -Label "vor MaxMemory Aenderung"
Export-sqmServerConfiguration -SqlInstance "SQL01" -Label "vor MaxMemory Aenderung"
Invoke-sqmConfigRollback Konfiguration
Restores SQL Server configuration from a previously exported JSON snapshot. Supports -WhatIf to preview changes. Rolls back sp_configure, instance properties and service start modes.
► 1 Beispiel anzeigen
Invoke-sqmConfigRollback -SqlInstance "SQL01" -SnapshotPath "C:\...\SQL01.json" -WhatIf
Invoke-sqmConfigRollback -SqlInstance "SQL01" -SnapshotPath "C:\...\SQL01.json" -WhatIf

📋 Inventar & Suche

Export-sqmDatabaseDocumentation Inventar
Documents per database: - General properties (status, recovery model, collation, owner, creation date, compatibility level) - Size (data, log, total in MB) - Filegroups and files (name,
▶ 4 Beispiele anzeigen
Export-sqmDatabaseDocumentation
Export-sqmDatabaseDocumentation
Export-sqmDatabaseDocumentation -SqlInstance "SQL01" -Database "SalesDB","HRApp" -OutputPath "D:\Reports"
Export-sqmDatabaseDocumentation -SqlInstance "SQL01" -Database "SalesDB","HRApp" -OutputPath "D:\Reports"
Export-sqmDatabaseDocumentation -SqlInstance "SQL01" -IncludeSystemDatabases -ContinueOnError
Export-sqmDatabaseDocumentation -SqlInstance "SQL01" -IncludeSystemDatabases -ContinueOnError
# Multiple instances via pipeline
    "SQL01","SQL02","SQL03" | Export-sqmDatabaseDocumentation -ContinueOnError
Find-sqmDatabaseObject Inventar
Searches user databases for tables, views, procedures, functions, triggers, synonyms. Returns the location (database, schema, object type, name). Can filter by SQL text (full definition).
▶ 2 Beispiele anzeigen
Find-sqmDatabaseObject -SqlInstance "SQL01" -ObjectName "sp_GetOrders"
Find-sqmDatabaseObject -SqlInstance "SQL01" -ObjectName "sp_GetOrders"
Find-sqmDatabaseObject -SqlInstance "SQL01" -ObjectName "*log*" -ObjectType "TABLE","VIEW" -Database "Sales*"
Find-sqmDatabaseObject -SqlInstance "SQL01" -ObjectName "*log*" -ObjectType "TABLE","VIEW" -Database "Sales*"
Get-sqmLinkedServerUsage Inventar
Searches the definitions of all user databases for references to linked servers. Shows the referenced linked server, the object and the database. Optionally includes dependent jobs.
▶ 1 Beispiel anzeigen
Get-sqmLinkedServerUsage -SqlInstance "SQL01" -LinkedServer "PROD_SRV"
Get-sqmLinkedServerUsage -SqlInstance "SQL01" -LinkedServer "PROD_SRV"
Invoke-sqmInstanceInventory Inventar
Documents the following areas: - Instance (version, edition, patch level, collation, memory, CPU, sp_configure) - Databases (name, status, recovery, size, last backups, owner, collation)
▶ 2 Beispiele anzeigen
Invoke-sqmInstanceInventory
Invoke-sqmInstanceInventory
Invoke-sqmInstanceInventory -SqlInstance "SQL01", "SQL02" -ContinueOnError
Invoke-sqmInstanceInventory -SqlInstance "SQL01", "SQL02" -ContinueOnError

🖥️ Cluster & Dienste

Get-sqmClusterInfo Cluster
This function queries a Windows Failover Cluster and returns an object containing the cluster name, a list of nodes, and a list of roles (cluster groups). For each role, the associated IP ad
▶ 2 Beispiele anzeigen
$info = Get-sqmClusterInfo -ClusterName "MYCLUSTER"
    if (-not $info.Success) { Write-Error $info.ErrorMessage; return }
    $info.ClusterName
    $info.Nodes | Format-Table
    $info.Roles | Where-Object OwnerNode -eq "Node1" | Select Name, IPAddresses
Get-sqmClusterInfo -IncludeCoreGroup
    Queries the local cluster and returns all roles including the core group.
Test-sqmSsasDirectoryPermissions Cluster
Determines the directory paths for an SSAS instance from the registry, checks whether the SSAS service account has FullControl access to these directories, and sets any missing permissions a
▶ 2 Beispiele anzeigen
Test-sqmSsasDirectoryPermissions
    Checks the directories of the default SSAS instance and corrects missing permissions.
Test-sqmSsasDirectoryPermissions -InstanceName "SSAS2019" -WhatIf
    Shows which permissions would be set for the named instance.
Test-sqmSSISPackageCompatibility Cluster
Tests whether SSIS packages will run in a target SQL Server version. Checks deprecated features, encoding issues, and connection types. Supports two package sources: 1. SSISDB Catalog (de
▶ 3 Beispiele anzeigen
# Check deployed packages on target server
    Test-sqmSSISPackageCompatibility -SqlInstance "NewServer2025" -TargetVersion 2025
# Check old package files before deployment
    Test-sqmSSISPackageCompatibility -PackagePath "C:\OldPackages" -TargetVersion 2025 -Recurse
# Compare deployed vs. backup packages
    Test-sqmSSISPackageCompatibility -SqlInstance "NewServer2025" `
      -PackagePath "C:\OldPackages" -TargetVersion 2025

🔐 TLS & Zertifikate

Get-sqmCertificateReport TLS
Checks all security-relevant certificates on one or more instances: MASTER KEY - Checks whether a Database Master Key exists in master (required for certificates) - Checks whether
▶ 4 Beispiele anzeigen
Get-sqmCertificateReport
Get-sqmCertificateReport
Get-sqmCertificateReport -SqlInstance "SQL01","SQL02" -WarningThresholdDays 180
Get-sqmCertificateReport -SqlInstance "SQL01","SQL02" -WarningThresholdDays 180
# Show only expiring certificates
    Get-sqmCertificateReport -SqlInstance "SQL01" |
        Select-Object -ExpandProperty Certificates |
        Where-Object { $_.ExpiryStatus -ne 'OK' } |
        Select-Object SqlInstance, DatabaseName, CertificateName, ExpiryDate, DaysRemaining, ExpiryStatus, Purpose
# Pipeline across multiple instances
    'SQL01','SQL02','SQL03' | Get-sqmCertificateReport -OutputPath "D:\Reports\Certs"
Get-sqmTlsStatus TLS
Get-sqmTlsStatus connects to each target computer (locally or via Invoke-Command for remotes), reads the SQL Server instance list from the registry, and for each instance checks: - The TLS ce
▶ 3 Beispiele anzeigen
Get-sqmTlsStatus
    Audits all SQL Server instances on the local computer and saves results to the default log folder.
Get-sqmTlsStatus -ComputerName "SQL01", "SQL02" -OutputPath "D:\Reports"
    Audits SQL01 and SQL02, saves reports to D:\Reports.
$cred = Get-Credential
    Get-sqmTlsStatus -ComputerName "SQL01" -Credential $cred | Where-Object Status -ne "OK"
    Audits SQL01 with explicit credentials and filters for non-OK results.
Install-sqmCertificate TLS
Supports three input formats: PFX (.pfx) - Certificate + private key in one file (CA-signed or exported) CER+PVK - Certificate (.cer) + encrypted private key (.pvk) separately
▶ 4 Beispiele anzeigen
# Import PFX from CA and bind to AlwaysOn endpoint
    Install-sqmCertificate -SqlInstance "SQL01" -CertFile "C:\Certs\sql01.pfx" `
        -CertPassword (Read-Host -AsSecureString) -Purpose AlwaysOn
# Install public-key certificate on AlwaysOn replica (no private key)
    Install-sqmCertificate -SqlInstance "SQL02" -CertFile "C:\Certs\SQL01_AG_CERT.cer" `
        -CertificateName "SQL01_AG_CERT" -Purpose AlwaysOn
# Install CER + PVK and bind TDE
    Install-sqmCertificate -SqlInstance "SQL01" `
        -CertFile "C:\Certs\tde_new.cer" `
        -PrivateKeyFile "C:\Certs\tde_new.pvk" `
        -CertPassword (Read-Host -AsSecureString "PVK password") `
        -Purpose TDE -TdeDatabaseName "ProdDB"
# Install SSL certificate (Windows Store + SQL Server network)
    Install-sqmCertificate -SqlInstance "SQL01" -CertFile "C:\Certs\ssl.pfx" `
        -CertPassword (Read-Host -AsSecureString) -Purpose SSL -SetSqlServerSslCert
Install-sqmCertificateToStore TLS
Reads a certificate file (.cer, .crt, or .pfx) and installs it into the specified Windows certificate store (LocalMachine) on one or more computers. Use cases: - Distribute a CA root ce
▶ 4 Beispiele anzeigen
# Install a CA root certificate to the Trusted Root store on all AlwaysOn replica nodes
    $nodes = 'SQL-AG-01', 'SQL-AG-02', 'SQL-AG-03'
    Install-sqmCertificateToStore -CertFile 'C:\Certs\CompanyRootCA.cer' `
        -StoreName Root -ComputerName $nodes
# Distribute a SQL Server self-signed certificate to an admin workstation
    Install-sqmCertificateToStore -CertFile 'C:\Certs\SQL-PROD-01.cer' `
        -StoreName TrustedPeople -ComputerName 'ADMINWS-01'
# Distribute an AlwaysOn partner certificate (CER without private key) to replica machines
    $replicas = 'SQL-AG-02', 'SQL-AG-03'
    Install-sqmCertificateToStore -CertFile 'C:\Certs\SQL-AG-01_AG_CERT.cer' `
        -StoreName My -ComputerName $replicas
# Install a PFX certificate with password into the Personal store on the local machine
    $pwd = Read-Host -AsSecureString 'PFX password'
    Install-sqmCertificateToStore -CertFile 'C:\Certs\sql-ssl.pfx' `
        -StoreName My -CertPassword $pwd
New-sqmCertificateRequest TLS
Reads all relevant properties of the existing certificate from SQL Server (Subject, SANs, purpose, endpoint binding) and creates: 1. INF file (certreq configuration) with all fields from t
▶ 3 Beispiele anzeigen
# CSR based on an existing certificate
    New-sqmCertificateRequest -SqlInstance "SQL01" -CertificateName "AG_CERT"
# New CSR without template, all fields specified manually
    New-sqmCertificateRequest -SqlInstance "SQL01" -Purpose "SSL" `
        -Subject "CN=SQL01.firma.de,O=Firma GmbH,L=Muenchen,C=DE" `
        -SubjectAlternativeNames @("sql01.firma.de","sql01","192.168.1.10") `
        -KeyLength 4096 -ValidityYears 2
# CSR with output to a specific directory
    New-sqmCertificateRequest -SqlInstance "SQL01" -CertificateName "TLS_CERT" `
        -OutputPath "D:\CertRequests"
New-sqmSqlCertificate TLS
Reads all relevant properties of the existing certificate (Subject, purpose, endpoint binding, TDE binding) and creates a new self-signed certificate directly in SQL Server using CREATE CERT
▶ 3 Beispiele anzeigen
# Simple renewal without automatic binding
    New-sqmSqlCertificate -SqlInstance "SQL01" -CertificateName "AG_CERT" -BackupEncryptionPassword (Read-Host -AsSecureString)
# With automatic endpoint binding and 10-year validity
    New-sqmSqlCertificate -SqlInstance "SQL01" -CertificateName "AG_CERT" `
        -ValidityYears 10 -BindEndpoint `
        -BackupEncryptionPassword (Read-Host -AsSecureString "Backup-Passwort")
# Renew TDE certificate
    New-sqmSqlCertificate -SqlInstance "SQL01" -CertificateName "TDE_PROD" `
        -BindTde -BackupEncryptionPassword (Read-Host -AsSecureString "Backup-Passwort")
Set-sqmSqlTlsCertificate TLS
Replaces the default self-signed auto-generated SQL Server TLS certificate with a proper certificate from the LocalMachine\My store. This eliminates SSL/TLS connection warnings in client appli
▶ 3 Beispiele anzeigen
Set-sqmSqlTlsCertificate -SqlInstance "SQL01" -Thumbprint "A1B2C3D4E5F6..."
    Binds the specified certificate to the default instance on SQL01.
    Service restart must be performed manually.
Set-sqmSqlTlsCertificate -SqlInstance "SQL01\INST1" -Thumbprint "A1B2C3D4E5F6..." -ForceEncryption -Restart
    Binds the certificate to the named instance INST1, enables Force Encryption,
    and restarts the SQL Server service automatically.
Set-sqmSqlTlsCertificate -Thumbprint "A1 B2 C3 D4 E5 F6" -WhatIf
    Shows what would be done for the local default instance without making changes.
    Thumbprint spaces are stripped automatically.
Set-sqmSsrsHttpsCertificate TLS
Eliminates browser security warnings by binding a valid certificate to the SSRS or Power BI Report Server (PBIRS) HTTPS endpoint via the WMI configuration interface. The function performs the fol
▶ 3 Beispiele anzeigen
Set-sqmSsrsHttpsCertificate -Thumbprint "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2"
		Binds the specified certificate to SSRS on the local machine on port 443.
		The SSRS instance is auto-detected.
Set-sqmSsrsHttpsCertificate -ComputerName "REPSERVER01" -Thumbprint "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2" -Port 8443 -InstanceName "RS_PBIRS" -RequireSSL
		Binds the certificate to Power BI Report Server on REPSERVER01, port 8443,
		and requires HTTPS (SecureConnectionLevel = 1).
$cred = Get-Credential
		Set-sqmSsrsHttpsCertificate -ComputerName "REPSERVER02" -Thumbprint "A1B2C3D4E5F6A1B2C3D4E5F6A1B2C3D4E5F6A1B2" -Credential $cred -WhatIf
		Shows what changes would be made on REPSERVER02 without applying them.

📼 TSM / IBM Spectrum

Get-sqmTsmConfiguration TSM
Invoke-sqmTsmConfiguration TSM
Reads the existing dsm.opt, adds or replaces the relevant entries, and writes the file back. Before each change a backup copy (dsm.opt.bak) is automatically created. Configured sectio
▶ 3 Beispiele anzeigen
Invoke-sqmTsmConfiguration -ManagementClass MC_B_NL.NL_42.42.NA
Invoke-sqmTsmConfiguration -ManagementClass MC_B_NL.NL_42.42.NA
Invoke-sqmTsmConfiguration -ComputerName "SQL01" -UseDiff
Invoke-sqmTsmConfiguration -ComputerName "SQL01" -UseDiff
Invoke-sqmTsmConfiguration -ComputerName "SQL01" -AdditionalIncludePaths "E:\Archive"
Invoke-sqmTsmConfiguration -ComputerName "SQL01" -AdditionalIncludePaths "E:\Archive"
Test-sqmTsmConnection TSM
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' com
▶ 2 Beispiele anzeigen
Test-sqmTsmConnection
Test-sqmTsmConnection
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
}

🚀 Deployment

Invoke-sqmDeployScripts Deployment
Runs all SQL script files whose filename starts with a numeric prefix (e.g. 001_CreateTable.sql) in ascending numeric order against the specified database. Before execution the function: - Va
▶ 6 Beispiele anzeigen
# Basic deploy with automatic backup
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy"
# Deploy with job number embedded in log filename
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy" -JobNumber "AU-2026-042"
# Skip backup - requires interactive confirmation
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy" -SkipBackup
# WhatIf dry run - no SQL executed, only pre-checks and summary table
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy" -WhatIf
# No outer transaction - scripts manage their own transactions
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy" -NoWrapTransaction
# SQL Server authentication
    $cred = Get-Credential
    Invoke-sqmDeployScripts -SqlInstance "SQLSERVER01" -Database "SalesDB" `
        -ScriptPath "D:\Deploy\v2.3" -LogPath "D:\Logs\Deploy" -SqlCredential $cred
Invoke-sqmSignModule Deployment
Signs .ps1, .psm1, and .psd1 files (configurable) under a module root directory recursively. Works with any code signing certificate: commercial OV cert, self-signed cert, or a SignPath-export
▶ 5 Beispiele anzeigen
# 1. Sign with a specific certificate from the store
    Invoke-sqmSignModule -ModulePath "C:\Dev\MyModule" `
        -CertificateThumbprint "AB12CD34EF56..."
# 2. Sign with a PFX file
    $pwd = ConvertTo-SecureString "secret" -AsPlainText -Force
    Invoke-sqmSignModule -ModulePath "C:\Dev\MyModule" `
        -CertificatePath "C:\Certs\CodeSign.pfx" -CertificatePassword $pwd
# 3. Auto-detect certificate (no parameters needed if cert is in store)
    Invoke-sqmSignModule -ModulePath "C:\Dev\MyModule"
# 4. WhatIf dry run - show which files would be signed
    Invoke-sqmSignModule -ModulePath "C:\Dev\MyModule" -WhatIf
# 5. Force re-sign all files, even those already signed
    Invoke-sqmSignModule -ModulePath "C:\Dev\MyModule" -Force

🔹 Sonstige

Copy-sqmLogins Sonstige
Transfers SQL and Windows logins from a source instance to a target instance. Process: 1. Disable policy (Set-sqmSqlPolicyState -State Disable, if -DisablePolicy $true) 2. Co
▶ 4 Beispiele anzeigen
Copy-sqmLogins -Source 'SQL01' -Destination 'SQL02'
    Copies all non-system logins. Policy is disabled/re-enabled,
    AD check and orphan repair run automatically.
Copy-sqmLogins -Source 'SQL01' -Destination 'SQL02' -AdjustAuthMode -RestartServiceIfRequired
    Copies all logins and switches the target server to Mixed Mode if needed.
    Automatically restarts the SQL service if required.
Copy-sqmLogins -Source 'SQL01' -Destination 'SQL02' -Login 'App_*' -Force
    Copies only logins starting with 'App_' and overwrites existing ones.
Copy-sqmLogins -Source 'SQL01' -Destination 'SQL02' -DisablePolicy $false -WhatIf
    Simulates the operation without policy handling.
Copy-sqmToCentralPath Sonstige
If no CentralPath is configured, the function exits without error. Source files that do not exist are skipped.
Get-sqmAgentJobHistory Sonstige
Returns the last execution(s) of all or selected SQL Agent jobs. Can filter by job name, status (success/failure) and time range. By default, the last 7 days are shown.
▶ 2 Beispiele anzeigen
Get-sqmAgentJobHistory
Get-sqmAgentJobHistory
Get-sqmAgentJobHistory -JobName '*Backup*' -Status Failure -Since (Get-Date).AddDays(-1)
Get-sqmAgentJobHistory -JobName '*Backup*' -Status Failure -Since (Get-Date).AddDays(-1)
Get-sqmDiskBlockSize Sonstige
Liest die NTFS-Allokationseinheit (Blockgroesse) der angegebenen Laufwerke per WMI (Win32_Volume) und prueft ob die fuer SQL Server empfohlenen 64 KB (65536 Bytes) konfiguriert sind. Kann
▶ 4 Beispiele anzeigen
# Einzelne Laufwerke pruefen
    Get-sqmDiskBlockSize -Drive 'F', 'G', 'H'
# Automatisch alle SQL-Laufwerke der Instanz ermitteln und pruefen
    Get-sqmDiskBlockSize -SqlInstance "SQL01"
# Pipeline
    'F','G' | Get-sqmDiskBlockSize
# Nur Laufwerke mit falscher Blockgroesse anzeigen
    Get-sqmDiskBlockSize -SqlInstance "SQL01" | Where-Object { -not $_.IsRecommended }
Get-sqmHpuAllowGroup Sonstige
Reads the domain-group mapping from the module configuration (key: HpuDomainGroupMap). Each entry contains a DomainPattern (wildcard) and a GroupNamePattern (sAMAccountName filter). Th
▶ 2 Beispiele anzeigen
Get-sqmHpuAllowGroup
Get-sqmHpuAllowGroup
Get-sqmHpuAllowGroup -EnableException
#>
function Get-sqmHpuAllowGroup
{
    [CmdletBinding()]
    [OutputType([string])]
    param (
        [Parameter(Mandatory = $false)]
        [switch]$EnableException
    )
    $functionName = $MyInvocation.MyCommand.Name
    # ?? 1. Domain des lokalen Rechners ermitteln ????????????????????????????
    try
    {
        $currentDomain = (Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop).Domain
    }
    catch
    {
        $msg = "Domain konnte nicht ermittelt werden: $($_.Exception.Message)"
        Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'ERROR'
        if ($EnableException) { throw $msg }
        return $null
    }
    Invoke-sqmLogging -Message "Starte $functionName. Lokale Domain: '$currentDomain'" `
                      -FunctionName $functionName -Level 'INFO'
    # ?? 2. Mapping aus der Konfiguration lesen ??????????????????????????????
    $domainGroupMap = Get-sqmConfig -Key 'HpuDomainGroupMap'
    if (-not $domainGroupMap -or $domainGroupMap.Count -eq 0)
    {
        $msg = "Konfigurationsschluessel 'HpuDomainGroupMap' ist nicht gesetzt. " +
               "Bitte Set-sqmConfig -HpuDomainGroupMap <...> ausfuehren."
        Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'ERROR'
        if ($EnableException) { throw $msg }
        Write-Warning $msg
        return $null
    }
    # ?? 3. Passenden Mapping-Eintrag per Wildcard-Match suchen ?????????????
    $matchedEntry = $null
    foreach ($entry in $domainGroupMap)
    {
        if ($currentDomain -like $entry.DomainPattern)
        {
            $matchedEntry = $entry
            Invoke-sqmLogging -Message "Domain '$currentDomain' trifft Pattern '$($entry.DomainPattern)'." `
                              -FunctionName $functionName -Level 'INFO'
            break
        }
    }
    if (-not $matchedEntry)
    {
        $msg = "Kein Mapping-Eintrag fuer Domain '$currentDomain' gefunden."
        Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'WARNING'
        if ($EnableException) { throw $msg }
        Write-Warning $msg
        return $null
    }
    $groupNamePattern = $matchedEntry.GroupNamePattern
    # ?? 4. AD-Suche ????????????????????????????????????????????????????????
    try
    {
        $ldapFilter = "(&(objectCategory=group)(sAMAccountName=*$groupNamePattern))"
        Invoke-sqmLogging -Message "LDAP-Filter: $ldapFilter" -FunctionName $functionName -Level 'INFO'
        $searcher                    = [adsisearcher]$ldapFilter
        $searcher.PageSize           = 20
        foreach ($prop in @('name', 'distinguishedname'))
        {
            $searcher.PropertiesToLoad.Add($prop) | Out-Null
        }
        $result = $searcher.FindOne()
    }
    catch
    {
        $msg = "AD-Suche fehlgeschlagen: $($_.Exception.Message)"
        Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'ERROR'
        if ($EnableException) { throw $msg }
        Write-Warning $msg
        return $null
    }
    # ?? 5. Ergebnis auswerten ???????????????????????????????????????????????
    if ($null -eq $result)
    {
        $msg = "Keine HPU-Allow-Gruppe '*$groupNamePattern' in Domain '$currentDomain' gefunden."
        Invoke-sqmLogging -Message $msg -FunctionName $functionName -Level 'WARNING'
        if ($EnableException) { throw $msg }
        Write-Warning $msg
        return $null
    }
    $dn = ($result.Properties['distinguishedname'])[0]
    Invoke-sqmLogging -Message "Gruppe gefunden: $dn" -FunctionName $functionName -Level 'INFO'
    return $dn
}
Get-sqmServerHardwareReport Sonstige
Sammelt Systeminformationen via CIM/WMI und generiert einen detaillierten HTML-Report mit: - Betriebssystem (Windows-Version, Build, Laufzeit, Domain) - Prozessor (Modell, Sockel, physikalisch
▶ 6 Beispiele anzeigen
# Lokalen Server analysieren - Report wird automatisch im Browser geoeffnet
    Get-sqmServerHardwareReport
# Remote-Server
    Get-sqmServerHardwareReport -ComputerName "SQL01"
# Mehrere Server, eigener Report-Pfad
    Get-sqmServerHardwareReport -ComputerName "SQL01","SQL02","SQL03" -ReportPath "C:\Reports"
# Nur speichern, nicht oeffnen - Dateipfad zurueckgeben
    $path = Get-sqmServerHardwareReport -ComputerName "SQL01" -NoOpen -PassThru
    Write-Host "Report: $path"
# CSV-Export fuer Weiterverarbeitung in Excel
    Get-sqmServerHardwareReport -ComputerName "SQL01","SQL02" -OutputFormat CSV -NoOpen
# Alle Formate auf einmal (HTML + CSV + TXT)
    Get-sqmServerHardwareReport -ComputerName "SQL01" -OutputFormat All -NoOpen -PassThru
Install-sqmAdModule Sonstige
First checks whether the ActiveDirectory module is already available. If not, the function attempts installation using four methods in the following order (fallback chain): 1. Win
▶ 3 Beispiele anzeigen
Install-sqmAdModule
    Checks whether the AD module is present and installs it if necessary.
Install-sqmAdModule -ContinueOnError
    Returns $false if installation fails instead of throwing an exception.
if (-not (Install-sqmAdModule -ContinueOnError))
    {
        Write-Warning "AD module not available - AD check will be skipped."
    }
Install-sqmDb2Driver Sonstige
Prueft ob ein DB2-Treiber bereits vorhanden ist (via Test-sqmDriverInstalled -DriverType DB2). Bei Bedarf: Fuehrt den IBM-Installer still aus. Unterstuetzte Installer-Formate: - db2_o
▶ 2 Beispiele anzeigen
Install-sqmDb2Driver -SourcePath '\\srv\Treiber\DB2'
Install-sqmDb2Driver -SourcePath '\\srv\Treiber\DB2'
Install-sqmDb2Driver -SourcePath 'C:\Downloads\db2_odbc_cli_64.exe'
Install-sqmDb2Driver -SourcePath 'C:\Downloads\db2_odbc_cli_64.exe'
Install-sqmJdbcDriver Sonstige
Prueft ob der JDBC-Treiber bereits vorhanden ist (via Test-sqmDriverInstalled). Bei Bedarf: Kopiert die .jar-Datei aus dem SourcePath in den Zielpfad und setzt optional die CLASSPATH-Umgebungs
▶ 2 Beispiele anzeigen
Install-sqmJdbcDriver -SourcePath '\\srv\Treiber\JDBC'
Install-sqmJdbcDriver -SourcePath '\\srv\Treiber\JDBC'
Install-sqmJdbcDriver -SourcePath 'C:\Downloads\jdbc' -UpdateClassPath $true
Install-sqmJdbcDriver -SourcePath 'C:\Downloads\jdbc' -UpdateClassPath $true
Install-sqmOdbcDriver Sonstige
Prueft ob der ODBC-Treiber bereits vorhanden ist (via Test-sqmDriverInstalled). Bei Bedarf: Fuehrt den Installer still aus. Unterstuetzte Installer-Formate: - .msi : msiexec /i /quiet
▶ 2 Beispiele anzeigen
Install-sqmOdbcDriver -SourcePath '\\srv\Treiber\ODBC'
Install-sqmOdbcDriver -SourcePath '\\srv\Treiber\ODBC'
Install-sqmOdbcDriver -SourcePath 'C:\Setup\msodbcsql18.msi'
Install-sqmOdbcDriver -SourcePath 'C:\Setup\msodbcsql18.msi'
Install-sqmOlaMaintenanceSolution Sonstige
Downloads the latest version of the Maintenance Solution from GitHub (https://github.com/olahallengren/sql-server-maintenance-solution/archive/refs/heads/main.zip), extracts the required scr
▶ 2 Beispiele anzeigen
Install-sqmOlaMaintenanceSolution -SqlInstance "SQL01"
Install-sqmOlaMaintenanceSolution -SqlInstance "SQL01"
Install-sqmOlaMaintenanceSolution -SqlInstance "SQL01" -Force
Install-sqmOlaMaintenanceSolution -SqlInstance "SQL01" -Force
Install-sqmSsrsReportServer Sonstige
Executes the following steps in sequence: [1] Check prerequisites - Administrator rights on the target computer - Installer (.exe or .msi) found in the configured share (SsrsInsta
▶ 3 Beispiele anzeigen
Install-sqmSsrsReportServer
    Installs SSRS using the installer path stored in sqmConfig,
    Edition Developer, followed by full configuration with default values.
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')
Install-sqmSsrsReportServer -SkipConfiguration -WhatIf
    Shows what would be installed without making any changes.
Invoke-sqmMonitoringKey Sonstige
Reads or writes the registry key HKLM:\\dtcSoftware\sqmSQLTool on the specified computers. The key controls which monitoring components are active: SQL monitoring level (None/S
▶ 3 Beispiele anzeigen
Invoke-sqmMonitoringKey
Invoke-sqmMonitoringKey
Invoke-sqmMonitoringKey -Operation Set -SQL Standard -TSM 1 -AutoDetectSQLFreeSpaceVersion
Invoke-sqmMonitoringKey -Operation Set -SQL Standard -TSM 1 -AutoDetectSQLFreeSpaceVersion
"SQL01","SQL02" | Invoke-sqmMonitoringKey -Operation Set -SQL Full -TSM 1
#>
function Invoke-sqmMonitoringKey
{
	[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'None')]
	[OutputType([PSCustomObject])]
	param (
		[Parameter(Mandatory = $false, ValueFromPipeline = $true)]
		[Alias('Computer', 'Server')]
		[string[]]$ComputerName = @($env:COMPUTERNAME),
		[Parameter(Mandatory = $false)]
		[ValidateSet('Get', 'Set')]
		[string]$Operation = 'Get',
		[Parameter(Mandatory = $false)]
		[ValidateSet('None', 'Standard', 'Full')]
		[string]$SQL,
		[Parameter(Mandatory = $false)]
		[ValidateSet('Standard', 'Cluster')]
		[string]$SQLFreeSpaceVersion,
		[Parameter(Mandatory = $false)]
		[ValidateSet(0, 1)]
		[Nullable[int]]$TSM,
		[Parameter(Mandatory = $false)]
		[string]$RegistryBase = 'System',
		[Parameter(Mandatory = $false)]
		[switch]$AutoDetectSQLFreeSpaceVersion,
		[Parameter(Mandatory = $false)]
		[System.Management.Automation.PSCredential]$Credential,
		[Parameter(Mandatory = $false)]
		[switch]$ContinueOnError,
		[Parameter(Mandatory = $false)]
		[switch]$EnableException
	)
	
	begin
	{
		$functionName = $MyInvocation.MyCommand.Name
		$regSubKey = "$RegistryBase\dtcSoftware\sqmSQLTool"
		$regPath = "HKLM:\$regSubKey"
		
		$sqlToDword = @{ 'None' = 0; 'Standard' = 1; 'Full' = 2 }
		$sqlDesc = @{ 0 = 'NoMonitoring'; 1 = 'ServiceMonitoring'; 2 = 'FullMonitoring' }
		$tsmDesc = @{ 0 = 'Inactive'; 1 = 'Active' }
		
		$allResults = [System.Collections.Generic.List[PSCustomObject]]::new()
	}
	
	process
	{
		foreach ($computer in $ComputerName)
		{
			try
			{
				Invoke-sqmLogging -Message "[$computer] Operation: $Operation" -FunctionName $functionName -Level "INFO"
				
				$effectiveFreeSpaceVersion = $SQLFreeSpaceVersion
				
				# AutoDetect (nur bei Set)
				if ($Operation -eq 'Set' -and $AutoDetectSQLFreeSpaceVersion -and [string]::IsNullOrWhiteSpace($effectiveFreeSpaceVersion))
				{
					Invoke-sqmLogging -Message "[$computer] AutoDetect SQLFreeSpaceVersion ..." -FunctionName $functionName -Level "INFO"
					try
					{
						if (-not (Get-Module -ListAvailable -Name dbatools))
						{
							Invoke-sqmLogging -Message "dbatools nicht gefunden - AutoDetect uebersprungen, verwende 'Standard'." -FunctionName $functionName -Level "WARNING"
							$effectiveFreeSpaceVersion = 'Standard'
						}
						else
						{
							$agCheck = Get-DbaAvailabilityGroup -SqlInstance $computer -ErrorAction SilentlyContinue
							$effectiveFreeSpaceVersion = if ($agCheck) { 'Cluster' }
							else { 'Standard' }
							Invoke-sqmLogging -Message "[$computer] AutoDetect Ergebnis: $effectiveFreeSpaceVersion" -FunctionName $functionName -Level "INFO"
						}
					}
					catch
					{
						Invoke-sqmLogging -Message "[$computer] AutoDetect fehlgeschlagen: $($_.Exception.Message)" -FunctionName $functionName -Level "WARNING"
						$effectiveFreeSpaceVersion = 'Standard'
					}
				}
				
				# Schreibvorgang
				if ($Operation -eq 'Set')
				{
					if ([string]::IsNullOrWhiteSpace($SQL) -and [string]::IsNullOrWhiteSpace($effectiveFreeSpaceVersion) -and $null -eq $TSM)
					{
						Invoke-sqmLogging -Message "[$computer] Keine Werte zum Setzen angegeben." -FunctionName $functionName -Level "WARNING"
						continue
					}
					
					if ($PSCmdlet.ShouldProcess($computer, "Setze Monitoring-Registry-Werte in '$regPath'"))
					{
						# Stelle sicher, dass der Schluessel existiert (lokal/remote)
						$keyExists = $false
						try
						{
							if ($computer -eq $env:COMPUTERNAME -or $computer -eq 'localhost' -or $computer -eq '.')
							{
								$fullPath = "HKLM:\$regSubKey"
								if (-not (Test-Path $fullPath))
								{
									New-Item -Path $fullPath -Force -ErrorAction Stop | Out-Null
									Invoke-sqmLogging -Message "[$computer] Registry-Schluessel erstellt: $fullPath" -FunctionName $functionName -Level "INFO"
								}
								$keyExists = $true
							}
							else
							{
								# Remote: Pruefe/Erstelle ueber Invoke-Command
								$sb = {
									param ($sk)
									$fullPath = "HKLM:\$sk"
									if (-not (Test-Path $fullPath))
									{
										New-Item -Path $fullPath -Force -ErrorAction Stop | Out-Null
										Write-Output "CREATED"
									}
									else
									{
										Write-Output "EXISTS"
									}
								}
								$invokeParams = @{
									ComputerName = $computer
									ScriptBlock  = $sb
									ArgumentList = $regSubKey
									ErrorAction  = 'Stop'
								}
								if ($Credential) { $invokeParams['Credential'] = $Credential }
								$result = Invoke-Command @invokeParams
								if ($result -eq 'CREATED')
								{
									Invoke-sqmLogging -Message "[$computer] Registry-Schluessel remote erstellt: HKLM:\$regSubKey" -FunctionName $functionName -Level "INFO"
								}
								$keyExists = $true
							}
						}
						catch
						{
							Invoke-sqmLogging -Message "[$computer] Fehler bei Schluesselerstellung: $($_.Exception.Message)" -FunctionName $functionName -Level "ERROR"
							throw
						}
						
						# Nun Werte setzen
						$values = @{ }
						if (-not [string]::IsNullOrWhiteSpace($SQL)) { $values['SQL'] = $sqlToDword[$SQL] }
						if (-not [string]::IsNullOrWhiteSpace($effectiveFreeSpaceVersion)) { $values['SQLFreeSpaceVersion'] = $effectiveFreeSpaceVersion }
						if ($null -ne $TSM) { $values['TSM'] = [int]$TSM }
						
						if ($computer -eq $env:COMPUTERNAME -or $computer -eq 'localhost' -or $computer -eq '.')
						{
							$fullPath = "HKLM:\$regSubKey"
							foreach ($entry in $values.GetEnumerator())
							{
								$type = if ($entry.Value -is [int]) { 'DWord' }
								else { 'String' }
								Set-ItemProperty -Path $fullPath -Name $entry.Key -Value $entry.Value -Type $type -ErrorAction Stop
							}
						}
						else
						{
							$sb2 = {
								param ($sk,
									$vals)
								$fullPath = "HKLM:\$sk"
								foreach ($entry in $vals.GetEnumerator())
								{
									$type = if ($entry.Value -is [int]) { 'DWord' }
									else { 'String' }
									Set-ItemProperty -Path $fullPath -Name $entry.Key -Value $entry.Value -Type $type -ErrorAction Stop
								}
								return $true
							}
							$invokeParams2 = @{
								ComputerName = $computer
								ScriptBlock  = $sb2
								ArgumentList = $regSubKey, $values
								ErrorAction  = 'Stop'
							}
							if ($Credential) { $invokeParams2['Credential'] = $Credential }
							Invoke-Command @invokeParams2 | Out-Null
						}
						Invoke-sqmLogging -Message "[$computer] Werte erfolgreich gesetzt." -FunctionName $functionName -Level "INFO"
					}
					else
					{
						Invoke-sqmLogging -Message "[$computer] WhatIf: Schreibvorgang uebersprungen." -FunctionName $functionName -Level "VERBOSE"
					}
				}
				
				# Lesen (immer, auch nach Set)
				# Hier wird der Schluessel NICHT erstellt - nur lesen
				$current = $null
				try
				{
					if ($computer -eq $env:COMPUTERNAME -or $computer -eq 'localhost' -or $computer -eq '.')
					{
						$fullPath = "HKLM:\$regSubKey"
						if (Test-Path $fullPath)
						{
							$key = Get-ItemProperty -Path $fullPath -ErrorAction Stop
							$current = @{
								SQL = $key.SQL
								SQLFreeSpaceVersion = $key.SQLFreeSpaceVersion
								TSM = $key.TSM
								_KeyExists = $true
							}
						}
						else
						{
							$current = @{ _KeyExists = $false }
						}
					}
					else
					{
						$sbRead = {
							param ($sk)
							$fullPath = "HKLM:\$sk"
							if (Test-Path $fullPath)
							{
								$key = Get-ItemProperty -Path $fullPath -ErrorAction Stop
								return @{
									SQL = $key.SQL
									SQLFreeSpaceVersion = $key.SQLFreeSpaceVersion
									TSM = $key.TSM
									_KeyExists = $true
								}
							}
							else
							{
								return @{ _KeyExists = $false }
							}
						}
						$invokeRead = @{
							ComputerName = $computer
							ScriptBlock  = $sbRead
							ArgumentList = $regSubKey
							ErrorAction  = 'Stop'
						}
						if ($Credential) { $invokeRead['Credential'] = $Credential }
						$current = Invoke-Command @invokeRead
					}
				}
				catch
				{
					throw "Registry-Lesen fehlgeschlagen: $($_.Exception.Message)"
				}
				
				$status = if ($Operation -eq 'Set') { if ($current._KeyExists) { 'Updated' }
					else { 'Created' } }
				elseif ($current._KeyExists) { 'OK' }
				else { 'KeyNotFound' }
				
				$sqlVal = $current.SQL
				$tsmVal = $current.TSM
				$fsvVal = $current.SQLFreeSpaceVersion
				$sqlText = if ($null -ne $sqlVal -and $sqlDesc.ContainsKey([int]$sqlVal)) { $sqlDesc[[int]$sqlVal] }
				else { '(nicht gesetzt)' }
				$tsmText = if ($null -ne $tsmVal -and $tsmDesc.ContainsKey([int]$tsmVal)) { $tsmDesc[[int]$tsmVal] }
				else { '(nicht gesetzt)' }
				
				$msg = switch ($status)
				{
					'KeyNotFound' { "Registry-Schluessel '$regPath' nicht vorhanden." }
					'Created'     { "Schluessel neu erstellt und Werte gesetzt." }
					'Updated'     { "Werte aktualisiert." }
					default       { "Werte erfolgreich ausgelesen." }
				}
				
				$allResults.Add([PSCustomObject]@{
						ComputerName = $computer
						RegistryPath = "HKLM:\$regSubKey"
						SQL		     = $sqlVal
						SQL_Description = $sqlText
						SQLFreeSpaceVersion = $fsvVal
						TSM		     = $tsmVal
						TSM_Description = $tsmText
						Status	     = $status
						Message	     = $msg
					})
			}
			catch
			{
				$errMsg = $_.Exception.Message
				Invoke-sqmLogging -Message "[$computer] Fehler: $errMsg" -FunctionName $functionName -Level "ERROR"
				$allResults.Add([PSCustomObject]@{
						ComputerName = $computer
						RegistryPath = "HKLM:\$regSubKey"
						SQL		     = $null
						SQL_Description = '(Fehler)'
						SQLFreeSpaceVersion = $null
						TSM		     = $null
						TSM_Description = '(Fehler)'
						Status	     = 'Failed'
						Message	     = $errMsg
					})
				if ($EnableException) { throw }
				if (-not $ContinueOnError) { throw }
			}
		}
	}
	
	end
	{
		Invoke-sqmLogging -Message "$functionName abgeschlossen." -FunctionName $functionName -Level "INFO"
		return $allResults
	}
}
New-sqmOlaMaintenanceJobs Sonstige
Creates three fully configured SQL Agent jobs on the specified SQL Server instance that call Ola Hallengren's IndexOptimize and DatabaseIntegrityCheck procedures. Prerequisite: Ola Halleng
▶ 2 Beispiele anzeigen
New-sqmOlaMaintenanceJobs -SqlInstance "SQL01"
New-sqmOlaMaintenanceJobs -SqlInstance "SQL01"
New-sqmOlaMaintenanceJobs -SqlInstance "SQL01" -ScheduleTime "22:00" -ScheduleDay 64 -OperatorName "DBAs"
New-sqmOlaMaintenanceJobs -SqlInstance "SQL01" -ScheduleTime "22:00" -ScheduleDay 64 -OperatorName "DBAs"
New-sqmRandomSaPassword Sonstige
Erstellt ein kryptografisch sicheres Passwort das die SQL Server Passwort-Richtlinie erfuellt: - Mindestlaenge konfigurierbar (Standard: 20 Zeichen) - Mindestens 1 Grossbuchstabe (
▶ 3 Beispiele anzeigen
$pwd = New-sqmRandomSaPassword
    # Gibt SecureString zurueck
$pwd = New-sqmRandomSaPassword -Length 24 -ExportPath 'C:\Temp\sa.txt'
    # SecureString + DPAPI-Export nach C:\Temp\sa.txt
# Klartext anzeigen (nur fuer Debugging):
    $pwd = New-sqmRandomSaPassword
    $cred = New-Object PSCredential('sa', $pwd)
    $cred.GetNetworkCredential().Password
Repair-sqmAlwaysOnDatabases Sonstige
- Determines all databases in all Availability Groups. - Checks whether a database is problematic (synchronization status not 'HEALTHY' or 'SYNCHRONIZED'). - Ensures that Automatic Seeding is enable
▶ 2 Beispiele anzeigen
Automatically repairs all problematic AG databases.
Repair-sqmAlwaysOnDatabases
Forces repair of all AG databases (including healthy ones).
Repair-sqmAlwaysOnDatabases -Force
Set-sqmSqlPolicyState Sonstige
Uses dbatools (Get-DbaPbmPolicy) to check whether the specified policy exists on the target instance, and then toggles only that policy via its SMO object. Unlike older scripts, this does
▶ 2 Beispiele anzeigen
Set-sqmSqlPolicyState -SqlInstance "SQL01" -Policy "xp_cmdshell must be disabled" -State Disable
Set-sqmSqlPolicyState -SqlInstance "SQL01" -Policy "xp_cmdshell must be disabled" -State Disable
"SQL01","SQL02" | Set-sqmSqlPolicyState -Policy "Password Policy" -State Enable
"SQL01","SQL02" | Set-sqmSqlPolicyState -Policy "Password Policy" -State Enable
Test-sqmDriverInstalled Sonstige
Treiber-Erkennung je nach Typ: ODBC: - Get-OdbcDriver (Windows PowerShell / CIM) - Registry: HKLM:\SOFTWARE\ODBC\ODBCINST.INI\ JDBC: - Suche nach Microso
▶ 4 Beispiele anzeigen
Test-sqmDriverInstalled -DriverType ODBC
Test-sqmDriverInstalled -DriverType ODBC
Test-sqmDriverInstalled -DriverType ODBC -DriverName 'ODBC Driver 18 for SQL Server'
Test-sqmDriverInstalled -DriverType ODBC -DriverName 'ODBC Driver 18 for SQL Server'
Test-sqmDriverInstalled -DriverType JDBC
Test-sqmDriverInstalled -DriverType JDBC
Test-sqmDriverInstalled -DriverType DB2
Test-sqmDriverInstalled -DriverType DB2
Test-sqmMaxDop Sonstige
Liest den aktuellen MAXDOP-Wert aus sys.configurations und vergleicht ihn mit der Microsoft-Empfehlung: Empfehlung: min(8, Anzahl logischer CPUs) Sonderwert 0 bedeutet "kein Limit" =
▶ 2 Beispiele anzeigen
Test-sqmMaxDop -SqlInstance 'MSSQLSERVER'
Test-sqmMaxDop -SqlInstance 'MSSQLSERVER'
Test-sqmMaxDop -SqlInstance 'SQL01\INST01'
Test-sqmMaxDop -SqlInstance 'SQL01\INST01'
Test-sqmMaxMemory Sonstige
Liest den aktuellen "max server memory (MB)"-Wert und vergleicht ihn mit der Empfehlung (90% des physischen RAM). Sonderwert 2147483647 (= 2^31 - 1) bedeutet "nicht konfiguriert" (SQL-Standar
▶ 2 Beispiele anzeigen
Test-sqmMaxMemory -SqlInstance 'MSSQLSERVER'
Test-sqmMaxMemory -SqlInstance 'MSSQLSERVER'
Test-sqmMaxMemory -SqlInstance 'SQL01\INST01' | Where-Object { $_.Status -ne 'OK' }
Test-sqmMaxMemory -SqlInstance 'SQL01\INST01' | Where-Object { $_.Status -ne 'OK' }
Test-sqmSqlInstanceInstalled Sonstige
Kombiniert zwei Pruefmethoden: 1. Registry: HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL 2. Windows-Dienst: MSSQLSERVER (Default) oder MSSQL$ (Named)
▶ 3 Beispiele anzeigen
Test-sqmSqlInstanceInstalled
    # Prueft Default-Instanz MSSQLSERVER
Test-sqmSqlInstanceInstalled -InstanceName 'INST01'
Test-sqmSqlInstanceInstalled -InstanceName 'INST01'
if ((Test-sqmSqlInstanceInstalled).IsInstalled) { Write-Host "SQL installiert" }
if ((Test-sqmSqlInstanceInstalled).IsInstalled) { Write-Host "SQL installiert" }
Uninstall-sqmDb2Driver Sonstige
Sucht den installierten IBM DB2-Treiber in der Windows-Uninstall-Registry und fuehrt eine stille Deinstallation durch (msiexec /x fuer MSI-basierte Installationen, alternativ Setup.exe
▶ 1 Beispiel anzeigen
Uninstall-sqmDb2Driver
Uninstall-sqmDb2Driver
Uninstall-sqmJdbcDriver Sonstige
Entfernt vorhandene mssql-jdbc*.jar Dateien aus dem Standard-Installationsverzeichnis des Microsoft JDBC Driver for SQL Server. Da JDBC als JAR-Datei deployed wird (kein MSI), genuegt
▶ 2 Beispiele anzeigen
Uninstall-sqmJdbcDriver
Uninstall-sqmJdbcDriver
Uninstall-sqmJdbcDriver -RemoveClassPath
Uninstall-sqmJdbcDriver -RemoveClassPath
Uninstall-sqmOdbcDriver Sonstige
Sucht den installierten Microsoft ODBC Driver for SQL Server in der Windows-Uninstall-Registry und fuehrt eine stille Deinstallation via msiexec /x durch. Wird typischerweise vor einer
▶ 2 Beispiele anzeigen
Uninstall-sqmOdbcDriver
Uninstall-sqmOdbcDriver
Uninstall-sqmOdbcDriver -DriverName 'Microsoft ODBC Driver 17 for SQL Server'
Uninstall-sqmOdbcDriver -DriverName 'Microsoft ODBC Driver 17 for SQL Server'

🚀 Quick Start

sqmSQLTool ist ein modulares PowerShell-Toolset für die SQL Server Administration mit 122 Funktionen zur Verwaltung von AlwaysOn, Backup/Restore, Performance, Sicherheit und mehr.
1
Modul importieren
Import-Module sqmSQLTool
2
Konfiguration setzen
Set-sqmConfig -LogPath "C:\System\WinSrvLog\MSSQL" -OutputPath "C:\System\WinSrvLog\MSSQL"
3
Instanz prüfen
Get-sqmSQLInstanceCheck -SqlInstance "SQL01"
4
AlwaysOn Status
Get-sqmAlwaysOnHealthReport -SqlInstance "SQL01"
5
Setup Report
Invoke-sqmSetupReport -SqlInstance "SQL01"

⚙️ Konfiguration

Alle Einstellungen werden mit Set-sqmConfig gesetzt und mit Get-sqmConfig abgerufen.
ParameterBeschreibungBeispiel
-LogPathPfad für Log-DateienC:\System\WinSrvLog\MSSQL
-OutputPathPfad für Report-AusgabenC:\System\WinSrvLog\MSSQL
-CentralPathZentraler UNC-Pfad für Dateiverteilung\\server\share\sqmSQLTool
-AutoUpdateAutomatisches Update beim Import aktivieren$true
-UpdateRepositoryUpdate-Quelle (GitHub / PSGallery / UNC)GitHub
-LanguageSprache der Ausgabende-DE oder en-US
-DefaultPolicyStandard-Policy-Name für Policy-Checkssqm_Standard
-CheckProfilePrüfprofil für Instance-CheckAuto, FiTs, Generic
-CheckCostThresholdMinMindestwert für Cost Threshold Prüfung50
-CheckTempDbMaxFilesMax. TempDB-Dateien für Prüfung8
-CheckDiskBlockSizeErwartete Block-Größe in Bytes65536
-OlaJobNameFullName des Ola Full-Backup JobsDatabaseBackup - FULL
-OlaJobNameDiffName des Ola Diff-Backup JobsDatabaseBackup - DIFF
-OlaJobNameLogName des Ola Log-Backup JobsDatabaseBackup - LOG
-SsrsInstallerPathPfad zum SSRS Installer\\server\setup\SSRS.exe
-TsmManagementClassesTSM Management Classes (Array)@('FULL','DIFF','LOG')
Beispiel: Grundkonfiguration
Set-sqmConfig -LogPath "C:\System\WinSrvLog\MSSQL" ``
              -OutputPath "C:\System\WinSrvLog\MSSQL" ``
              -Language "de-DE" ``
              -AutoUpdate $false

📦 Installation

1
Voraussetzung: dbatools installieren

Falls dbatools noch nicht vorhanden — je nach Umgebung:

# Mit Internetzugang (PSGallery):
Install-Module dbatools -Scope AllUsers       # systemweit (als Admin)
Install-Module dbatools -Scope CurrentUser    # nur für aktuellen Benutzer

# Ohne Internetzugang (z.B. Bankenumgebung):
# dbatools als ZIP auf einen UNC-Share bereitstellen und manuell entpacken nach:
# C:\Program Files\WindowsPowerShell\Modules\dbatools\
2
sqmSQLTool herunterladen
# Von GitHub als ZIP:
# https://github.com/JankeUwe/sqmSQLTool
# → Code → Download ZIP → entpacken
3
Installation mit Install.cmd (empfohlen)

Install.cmd erkennt automatisch ob Admin-Rechte vorhanden sind, behandelt Execution Policy und installiert ins richtige PowerShell-Verzeichnis.

Install.cmd                  # Auto: AllUsers wenn Admin, sonst CurrentUser
Install.cmd AllUsers         # Systemweit (UAC-Abfrage wenn nötig)
Install.cmd CurrentUser      # Nur für aktuellen Benutzer, keine Elevation nötig
4
Modul laden und prüfen
Import-Module sqmSQLTool
Get-Command -Module sqmSQLTool | Measure-Object
5
Update prüfen
Test-sqmModuleUpdate

📊 Alle Funktionen (122)

FunktionBeschreibung
Add-sqmDatabaseToAGAdds one or more databases to an Always On availability group (AutoSeed).
Add-sqmDatabaseToDistributedAgAdds a database to a Distributed AlwaysOn Availability Group.
Compare-sqmServerConfigurationCompares important configuration settings between two SQL Server instances.
Complete-sqmListenerMigrationCompletes listener migration after cluster team recreates the listener resource.
Copy-sqmLoginsCopies logins from a source SQL Server instance to a target instance.
Copy-sqmNTFSPermissionsCopies NTFS permissions (ACLs) from a source path to a destination path.
Copy-sqmToCentralPathCopies one or more files to the configured CentralPath.
Export-sqmAlwaysOnConfigurationExports the complete AlwaysOn AG configuration for one or more SQL Server instances.
Export-sqmDatabaseDocumentationCreates structured HTML and CSV documentation for all databases on a SQL Server instance.
Export-sqmServerConfigurationExports all SQL Server configuration settings to a JSON snapshot file.
Find-sqmDatabaseObjectSearches all (or selected) databases on an instance for an object name.
Get-sqmADAccountStatusChecks the status of an Active Directory user account.
Get-sqmADGroupMembersLists all members of an Active Directory group.
Get-sqmAgentJobHistoryDisplays the execution history of SQL Agent jobs.
Get-sqmAlwaysOnHealthReportCreates a detailed health report for all Always On availability groups on an instance.
Get-sqmAutoGrowthReportCreates an AutoGrowth configuration report for all database files on a SQL Server instance.
Get-sqmBlockingReportRetrieves current blocking chains on a SQL Server instance.
Get-sqmCertificateReportCreates a comprehensive report on SQL Server certificates and their expiration dates.
Get-sqmClusterInfoRetrieves information about a Windows Failover Cluster: cluster name, nodes and roles including IP addresses.
Get-sqmConfigReturns the current module configuration.
Get-sqmConnectionStatsAnalyzes active SQL Server connections and connection statistics.
Get-sqmDatabaseHealthAggregated health report for all databases on an instance.
Get-sqmDeadlockReportReads and analyzes deadlock events from the System Health Extended Event session.
Get-sqmDiskBlockSizePrueft die NTFS-Blockgroesse (Cluster-Groesse) von Laufwerken auf 64KB.
Get-sqmDiskInfoByDriveLetterReturns disk information for a given drive letter.
Get-sqmDiskSpaceReportReports disk space usage on one or more Windows servers.
Get-sqmDistributedAgHealthCreates a detailed health report for Distributed AlwaysOn Availability Groups.
Get-sqmHpuAllowGroupSearches for the HPU allow group in Active Directory based on configurable domain/group mappings.
Get-sqmIndexFragmentationAnalyzes index fragmentation in one or more databases.
Get-sqmLinkedServerUsageAnalyzes which database objects (procedures, functions, views, triggers, SQL Agent jobs) access linked servers.
Get-sqmLongRunningQueriesIdentifies long-running queries on a SQL Server instance.
Get-sqmMissingIndexesRetrieves missing index recommendations from the SQL Server DMV cache.
Get-sqmOperationStatusDisplays progress and estimated remaining time for active backup, restore and AutoSeed operations.
Get-sqmOrphanedFilesFinds MDF/LDF/NDF database files that are not assigned to any database.
Get-sqmPerfCountersReads SQL Server performance counters from sys.dm_os_performance_counters.
Get-sqmServerHardwareReportErstellt einen HTML-Hardware-Konfigurationsbericht fuer einen oder mehrere Server.
Get-sqmServerSettingReads one or all server properties from a SQL Server instance.
Get-sqmSpnReportChecks the registered SPNs for SQL Server instances (default and named instances).
Get-sqmSQLInstanceCheckChecks a SQL Server instance against best practices.
Get-sqmSysadminAccountsRetrieves all logins with sysadmin rights on a SQL Server instance.
Get-sqmTempDbRecommendationAnalyzes the TempDB configuration and provides optimization recommendations.
Get-sqmTlsStatusAudits TLS/SSL configuration and certificate status for all SQL Server instances on one or more computers.
Get-sqmTsmConfigurationReads and displays the IBM Spectrum Protect (TSM) client configuration.
Get-sqmWaitStatisticsReads and analyzes SQL Server wait statistics from sys.dm_os_wait_stats.
Install-sqmAdModuleEnsures that the ActiveDirectory PowerShell module (RSAT) is installed.
Install-sqmCertificateImports a certificate file (.pfx or .cer) into the Windows certificate store.
Install-sqmCertificateToStoreImports a certificate into a specified Windows certificate store.
Install-sqmDb2DriverInstalliert den IBM DB2 ODBC/CLI-Treiber.
Install-sqmJdbcDriverInstalliert den Microsoft JDBC Driver for SQL Server.
Install-sqmOdbcDriverInstalliert den Microsoft ODBC Driver for SQL Server.
Install-sqmOlaMaintenanceSolutionInstalls or updates Ola Hallengren's Maintenance Solution on a SQL Server instance.
Install-sqmSsrsReportServerInstalls and configures SQL Server Reporting Services (SSRS).
Invoke-sqmCollationChangeAutomatically changes the server collation of a SQL Server instance.
Invoke-sqmConfigRollbackRestores SQL Server configuration from a previously exported snapshot.
Invoke-sqmDeployScriptsExecutes numbered SQL scripts from a directory sequentially against a SQL Server database.
Invoke-sqmDistributedFailoverInitiates failover of a Distributed AlwaysOn AG.
Invoke-sqmExtendedEventsManages Extended Events sessions for performance analysis on SQL Server.
Invoke-sqmFailoverPerforms a controlled AlwaysOn AG failover with pre- and post-checks.
Invoke-sqmFormatDrive64kFormats a drive with 64K allocation unit size for optimal SQL Server performance.
Invoke-sqmInstanceInventoryCreates a complete inventory of a SQL Server instance as a structured report (TXT + CSV).
Invoke-sqmLoginAuditComprehensive audit of all SQL Server logins on one or more instances.
Invoke-sqmLogShrinkShrinks the transaction log file (LDF) of one or more databases.
Invoke-sqmMonitoringKeyGets or sets monitoring registry values for the sqmSQLTool on one or more computers.
Invoke-sqmPatchAnalysisCompares the installed SQL Server version with known CU/SP builds.
Invoke-sqmPerfBaselineCreates, compares or lists performance baselines (wait stats + perf counters).
Invoke-sqmQueryStoreConfigures the Query Store, reads from it, detects issues and saves reports.
Invoke-sqmRestoreDatabaseRestores a database from a backup file, with support for single-server and AlwaysOn environments.
Invoke-sqmSaObfuscationObfuscates the SA account on a SQL Server instance by renaming it, disabling it, and setting a random password.
Invoke-sqmSetDatabaseRecoveryModeChanges the recovery mode of one or more user databases.
Invoke-sqmSetupReportProfessional SQL Server Setup Report with critical issues, security, and database overview.
Invoke-sqmSignModuleSigns all PowerShell script files in a module directory using Set-AuthenticodeSignature.
Invoke-sqmSqlAlwaysOnAutoseedingEnables Automatic Seeding on all replicas of an Always On Availability Group.
Invoke-sqmSsisConfigurationConfigures SQL Server Integration Services (SSIS) environment and catalog.
Invoke-sqmTsmConfigurationConfigures the IBM Spectrum Protect (TSM) client for SQL Server backup.
Invoke-sqmUpdateStatisticsUpdates statistics in one or more databases.
Invoke-sqmUserDatabaseBackupBacks up user databases on a SQL Server instance.
Move-sqmAlwaysOnListenerMigrates an AG Listener from one Availability Group to another.
New-sqmAgentProxyErstellt einen SQL Server Credential und einen SQL Agent Proxy und verbindet beide.
New-sqmAlwaysOnRepairJobCreates a SQL Server Agent job that regularly runs Repair-sqmAlwaysOnDatabases.
New-sqmAutoLoginSyncJobCreates a SQL Agent job to automatically synchronize logins in an AlwaysOn Availability Group.
New-sqmBackupMaintenanceJobCreates a SQL Agent job with two steps that implement the full dynamic backup maintenance workflow.
New-sqmCertificateRequestCreates a new certificate signing request (CSR) for SQL Server TLS.
New-sqmDistributedAvailabilityGroupCreates a new Distributed AlwaysOn Availability Group.
New-sqmOlaMaintenanceJobsCreates all standard Ola Hallengren maintenance jobs on a SQL Server instance.
New-sqmOlaSysDbBackupJobCreates a SQL Agent backup job for system databases using Ola Hallengren solution.
New-sqmOlaUsrDbBackupJobCreates SQL Agent backup jobs for user databases using Ola Hallengren solution.
New-sqmRandomSaPasswordGeneriert ein zufaelliges, richtlinienkonformes SA-Passwort.
New-sqmSqlCertificateCreates a new self-signed SQL Server certificate as a renewal of an existing one.
Remove-sqmDatabaseFromAGRemoves one or more databases from their Always On Availability Group.
Repair-sqmAlwaysOnDatabasesChecks all AlwaysOn databases for problems and repairs them (Remove -> Cleanup -> Add).
Set-sqmBackupExcludePermissionGrants SELECT, INSERT, and UPDATE permissions on master.dbo.sqm_BackupExclude to a login.
Set-sqmConfigSets one or more configuration values for the MSSQLTools module.
Set-sqmDatabaseOwnerSets the owner of one or more databases to a uniform login.
Set-sqmSqlPolicyStateEnables or disables a single Policy-Based Management policy on a SQL Server instance.
Set-sqmSqlTlsCertificateBinds a Windows certificate from the Machine store to SQL Server as the TLS certificate.
Set-sqmSsrsConfigurationConfigures SQL Server Reporting Services (SSRS) fully automatically.
Set-sqmSsrsHttpsCertificateBinds a Windows certificate to SSRS or Power BI Report Server for HTTPS access.
Set-sqmTcpPortKonfiguriert den TCP-Port einer SQL Server-Instanz ueber die Registry.
Sync-sqmAgNodeSynchronizes configuration and logins between AlwaysOn AG nodes.
Sync-sqmBackupExcludeTableCreates and synchronises the backup exclude table in the master database.
Sync-sqmLoginsToAlwaysOnSynchronizes logins from the primary replica to all secondary replicas in an AlwaysOn Availability Group.
Test-sqmBackupIntegrityVerifies one or more backup files using RESTORE VERIFYONLY.
Test-sqmCostThresholdPrueft ob CostThresholdForParallelism auf dem empfohlenen Wert liegt.
Test-sqmDistributedAgReadinessTests Distributed AlwaysOn AG readiness for failover.
Test-sqmDriverInstalledPrueft ob ein JDBC-, ODBC- oder DB2-Treiber auf dem System installiert ist.
Test-sqmMaxDopPrueft ob MAXDOP (Max Degree of Parallelism) korrekt konfiguriert ist.
Test-sqmMaxMemoryPrueft ob SQL Server Max Server Memory korrekt konfiguriert ist.
Test-sqmModuleUpdateChecks all configured update sources for a newer sqmSQLTool version.
Test-sqmOlaInstallationChecks whether Ola Hallengren's Maintenance Solution is installed on a SQL Server instance.
Test-sqmSQLFirewallTests whether the firewall and network allow a TCP connection to SQL Server.
Test-sqmSqlInstanceInstalledPrueft ob eine SQL Server-Instanz auf dem lokalen System installiert ist.
Test-sqmSsasDirectoryPermissionsChecks and corrects NTFS permissions for SSAS directories (Data, Log, Temp, Backup).
Test-sqmSSISPackageCompatibilityValidates SSIS package compatibility for SQL Server upgrades (2016 - 2025).
Test-sqmTempDbFileCountPrueft ob die Anzahl der TempDB-Datendateien der empfohlenen CPU-Anzahl entspricht.
Test-sqmTsmConnectionTests the connection to an IBM Spectrum Protect (TSM) server using dsmadmc.
Test-sqmUpdateViaGitHubChecks if a newer version of sqmSQLTool is available on GitHub.
Test-sqmUpdateViaPSGalleryChecks if a newer version of sqmSQLTool is available on PowerShell Gallery.
Test-sqmUpdateViaUNCChecks if a newer version of sqmSQLTool is available on a UNC share.
Uninstall-sqmDb2DriverDeinstalliert den IBM DB2 ODBC/CLI-Treiber.
Uninstall-sqmJdbcDriverDeinstalliert den Microsoft JDBC Driver for SQL Server.
Uninstall-sqmOdbcDriverDeinstalliert den Microsoft ODBC Driver for SQL Server.
Update-sqmModuleUpdates the sqmSQLTool module from GitHub, PSGallery or a UNC share.