🛢 mssSQLTool
PowerShell SQL Admin Toolset · dtcSoftware · Janke
🔄 AlwaysOn Availability Groups
-All sequentielle Verarbeitung zur Lastvermeidung.Invoke-mssAddDatabaseToAvailabilityGroup -AvailabilityGroup "AG_Prod" -Database "SalesDB"
Invoke-mssAddDatabaseToAvailabilityGroup -AvailabilityGroup "AG_Prod" -All
Invoke-mssAddDatabaseToAvailabilityGroup -SqlInstance "SQL01" ` -AvailabilityGroup "AG_Prod" ` -Database "SalesDB","InventoryDB","HRApp"
Invoke-mssRemoveDatabaseFromAvailabilityGroup -Database "SalesDB"
Invoke-mssRemoveDatabaseFromAvailabilityGroup -All
Invoke-mssRemoveDatabaseFromAvailabilityGroup -SqlInstance "SQL01" -Database "OldApp"
Invoke-mssSqlAlwaysOnAutoseeding
Invoke-mssSqlAlwaysOnAutoseeding -SqlInstance "SQL01" -All
Invoke-mssSqlAlwaysOnAutoseeding -SqlInstance "SQL01\MSSQLSERVER"
Get-mssAgHealthReport
Get-mssAgHealthReport -SqlInstance "SQL01" -MaxRedoQueueMB 200 -OutputPath "D:\Reports"
Get-mssAgHealthReport -SqlInstance "SQL01" | Where-Object OverallStatus -eq 'Critical' | Format-Table AgName, ReplicaName, Database, DbSyncState, RedoQueueMB -AutoSize
Get-mssAgHealthReport -SqlInstance "SQL01" | Where-Object Role -eq 'SECONDARY' | Sort-Object RedoQueueMB -Descending | Select-Object AgName, Database, ReplicaName, RedoQueueMB, SendQueueMB | Format-Table -AutoSize
while ($true) {
Clear-Host
Get-mssAgHealthReport -SqlInstance "SQL01" |
Where-Object Role -eq 'SEEDING' |
Select-Object Database, DbSyncState, PercentComplete |
Format-Table -AutoSize
Start-Sleep 30
}Sync-mssAgNode
Sync-mssAgNode -SqlInstance "SQL01" -ExcludeType Jobs,LinkedServers,Operators,Alerts
Sync-mssAgNode -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod"
Sync-mssAgNode -SqlInstance "SQL01" -ObjectName "AppServiceAccount"
$r = Sync-mssAgNode -SqlInstance "SQL01"
$r | Group-Object ObjectType | ForEach-Object {
"$($_.Name): $(@($_.Group | Where Status -eq 'Success').Count) OK, " +
"$(@($_.Group | Where Status -eq 'Failed').Count) Fehler"
}Repair-mssAlwaysOnDatabases
Repair-mssAlwaysOnDatabases -Force
Repair-mssAlwaysOnDatabases -SqlInstance "SQL01" -ContinueOnError
Repair-mssAlwaysOnDatabases periodisch ausführt (PowerShell-Subsystem). Konfigurierbar mit Zeitplan und Operator-Benachrichtigung.New-mssAlwaysOnRepairJob
New-mssAlwaysOnRepairJob -Schedule "FREQ=DAILY;INTERVAL=1" -StartTime "02:00:00"
"SQL01","SQL02","SQL03" | ForEach-Object {
New-mssAlwaysOnRepairJob -SqlInstance $_ -Schedule "FREQ=HOURLY;INTERVAL=2"
}ALTER AVAILABILITY GROUP ... FAILOVER wird auf dem Ziel-Sekundaer ausgefuehrt.
Post-Check: Bestaetigt neue Primary-Rolle nach konfigurierbarer Wartezeit.
Unterstuetzt -WhatIf, automatische Replikat-Auswahl (kleinste Redo-Queue, SYNCHRONOUS_COMMIT bevorzugt) und -ContinueOnError.Invoke-mssFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" -WhatIf
Invoke-mssFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" ` -TargetReplica "SQL02" -MaxRedoQueueMB 10
Invoke-mssFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod"
Invoke-mssFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod" ` -WaitAfterFailoverSeconds 60 -EnableException
$result = Invoke-mssFailover -SqlInstance "SQL01" -AvailabilityGroup "AG_Prod"
if ($result.Status -eq 'Success') {
Write-Host "Failover OK: $($result.OldPrimary) -> $($result.NewPrimary) in $($result.FailoverDurationSec)s"
}💾 Backup & Restore
Invoke-mssUserDatabaseBackup -All
Invoke-mssUserDatabaseBackup -SqlInstance "SQL01" -Database "SalesDB","InventoryDB"
Invoke-mssUserDatabaseBackup -All -BackupPath "D:\Backup\User-Db"
Invoke-mssUserDatabaseBackup -All -WhatIf
Invoke-mssRestoreDatabase -SqlInstance "SQL01" ` -BackupFile "D:\Backup\AdventureWorks.bak" ` -DatabaseName "AdventureWorks"
$backupSequence = @( "D:\Backup\AW_Full.bak", "D:\Backup\AW_Diff.bak", "D:\Backup\AW_Log1.trn", "D:\Backup\AW_Log2.trn" ) Invoke-mssRestoreDatabase -SqlInstance "SQL01" ` -BackupFiles $backupSequence ` -DatabaseName "AdventureWorks"
Invoke-mssRestoreDatabase -SqlInstance "SQL01" ` -BackupFile "D:\Backup\OldDB.bak" ` -DatabaseName "OldDB" ` -NewDatabaseName "NewDB"
Invoke-mssRestoreDatabase -SqlInstance "SQL01" ` -BackupFile "D:\Backup\SalesDB.bak" ` -DatabaseName "SalesDB" ` -CreatePreRestoreBackup
Invoke-mssRestoreDatabase -SqlInstance "SQL01" ` -BackupFile "D:\Backup\SalesDB.bak" ` -DatabaseName "SalesDB" ` -ForceSingleUser
"D:\Bak\DB1.bak","D:\Bak\DB2.bak" |
Invoke-mssRestoreDatabase -SqlInstance "SQL01" -DatabaseName { [IO.Path]::GetFileNameWithoutExtension($_) }$true bei Erfolg.Test-mssBackupIntegrity -SqlInstance "SQL01" -BackupPath "D:\Backup\AdventureWorks.bak"
Get-ChildItem "D:\Backup\*.bak" | ForEach-Object {
$ok = Test-mssBackupIntegrity -SqlInstance "SQL01" -BackupPath $_.FullName
[PSCustomObject]@{ File = $_.Name; Valid = $ok }
} | Format-Table -AutoSizeif (-not (Test-mssBackupIntegrity -SqlInstance "SQL01" -BackupPath "D:\Backup\SalesDB.bak")) {
throw "Backup-Prüfung fehlgeschlagen!"
}Invoke-mssLogShrink -Database "MyDB" -ShrinkTargetPercent 20
Invoke-mssLogShrink -SqlInstance "SQL01" -All -WhatIf
Invoke-mssLogShrink -Database "HugeDB" -ShrinkTargetPercent 10 -MinTargetMB 512
# 1. Log-Backup Backup-DbaDatabase -SqlInstance "SQL01" -Database "SalesDB" -Type Log -BackupDirectory "D:\Backup" # 2. Dann shrink Invoke-mssLogShrink -SqlInstance "SQL01" -Database "SalesDB" -ShrinkTargetPercent 15
🔒 Sicherheit
$r = Invoke-mssSaObfuscation -SqlInstance "SQL01" Write-Host "Neuer Name : $($r.NewLoginName)" Write-Host "Kennwort : $($r.GeneratedPassword)" # SOFORT sicher verwahren!
Invoke-mssSaObfuscation -SqlInstance "SQL01" -NewName "dbsvc_sys" -PasswordLength 32
$r = Invoke-mssSaObfuscation -SqlInstance "SQL01"
if ($r.Status -eq 'Success') {
$r.GeneratedPassword | Out-File "C:\Secure\sa_pw_$(Get-Date -f 'yyyyMMdd').txt" -Encoding UTF8
}$results = "SQL01","SQL02","SQL03" | ForEach-Object {
Invoke-mssSaObfuscation -SqlInstance $_ -ContinueOnError
}
$results | Select-Object SqlInstance, NewLoginName, SysadminCheck, Status | Format-Table -AutoSizeInvoke-mssRenameSaAccount
Invoke-mssRenameSaAccount -NewName "MyHiddenSA" -Disable
Invoke-mssRenameSaAccount -NewName "sa" -Enable
"SQL01","SQL02","SQL03" | ForEach-Object {
Invoke-mssRenameSaAccount -SqlInstance $_ -NewName "mssa" -Disable
}-ExcludeLogin (Wildcard) als "Excluded" markieren. BUILTIN\Administrators erhält eigenen Status. Schreibt TXT + CSV ins OutputPath.Get-mssSysadminAccounts -SqlInstance "SQL01"
Get-mssSysadminAccounts -SqlInstance "SQL01" -ExcludeSysAccounts
Get-mssSysadminAccounts -SqlInstance "SQL01" ` -ExcludeLogin "NT SERVICE\*","NT AUTHORITY\*","CONTOSO\SQLAdmins","msssa" ` -ExcludeSysAccounts
Get-mssSysadminAccounts -SqlInstance "SQL01" -ExcludeSysAccounts | Where-Object Status -in 'Unexpected','BuiltinAdmins' | Format-Table SqlInstance, LoginName, LoginType, IsEnabled -AutoSize
$all = Get-mssSysadminAccounts -SqlInstance "SQL01","SQL02","SQL03" `
-ExcludeLogin "NT SERVICE\*","msssa" -ContinueOnError
$all | Group-Object SqlInstance | ForEach-Object {
$u = @($_.Group | Where-Object Status -eq 'Unexpected').Count
"$($_.Name): $($_.Count) gesamt, $u unerwartet$(if($u -gt 0){' ← PRÜFEN'})"
}Invoke-mssLoginAudit -SqlInstance "SQL01"
Invoke-mssLoginAudit -SqlInstance "SQL01" ` -InactivityThresholdDays 60 ` -MaxPasswordAgeDays 90 ` -ExcludeLogin "NT SERVICE\*","SA"
Invoke-mssLoginAudit -SqlInstance "SQL01" -CheckAdOrphans -IncludeSystemLogins
$r = Invoke-mssLoginAudit -SqlInstance "SQL01" -ExcludeLogin "NT SERVICE\*" $r | Where-Object Category -eq 'Policy' | Format-Table LoginName, Issue -AutoSize
"SQL01","SQL02","SQL03" | Invoke-mssLoginAudit -ContinueOnError
finally-Block (idempotent).Copy-mssLogins -SourceInstance "SQL01" -TargetInstance "SQL02"
Copy-mssLogins -SourceInstance "SQL01" -TargetInstance "SQL02" ` -AdjustAuthMode -RestartServiceIfRequired
Copy-mssLogins -SourceInstance "SQL01" -TargetInstance "SQL02" ` -ExcludeLogin "OldApp*","TestUser"
"SQL02","SQL03","SQL04" | ForEach-Object {
Copy-mssLogins -SourceInstance "SQL01" -TargetInstance $_ -ContinueOnError
}Get-mssADAccountStatus -SamAccountName "svc-sqlserver"
sa setzen. Systemdatenbanken übersprungen. Unterstützt -WhatIf.Set-mssDatabaseOwner -SqlInstance "SQL01" -All
🩺 Diagnose & Health
Get-mssDatabaseHealth
Get-mssDatabaseHealth -SqlInstance "SQL01" -IncludeSystemDatabases -OutputPath "D:\Reports"
Get-mssDatabaseHealth -SqlInstance "SQL01" |
Where-Object { $_.LastFullBackup -lt (Get-Date).AddDays(-2) } |
Select-Object DatabaseName, LastFullBackup, RecoveryModelGet-mssDatabaseHealth -SqlInstance "SQL01" | Where-Object VlfCount -gt 1000 | Sort-Object VlfCount -Descending | Format-Table DatabaseName, VlfCount, LogSizeMB -AutoSize
Get-mssSQLInstanceCheck
Get-mssSQLInstanceCheck -SqlInstance "SQL01\INSTANCE" -Detailed
Get-mssSQLInstanceCheck -SqlInstance "SQL01" | Where-Object Status -in 'Warning','Critical' | Format-Table Check, CurrentValue, RecommendedValue, Status -AutoSize
"SQL01","SQL02","SQL03","SQL04" | ForEach-Object {
Get-mssSQLInstanceCheck -SqlInstance $_ -ContinueOnError
} | Where-Object Status -eq 'Warning' | Format-Table SqlInstance, Check, CurrentValueGet-mssTempDbRecommendation -SqlInstance "SQL01"
Get-mssTempDbRecommendation -SqlInstance "SQL01" | Where-Object Status -ne 'OK' | Select-Object Status, Messages, Recommendations
Get-mssTempDbRecommendation -SqlInstance "SQL01" -OutputPath "D:\Reports"
sys.dm_os_volume_stats, AutoGrowth-Volumen (Default Trace), geschätzte Tage bis Erschöpfung, Warnung unter WarnThresholdPct.Get-mssDiskSpaceReport
Get-mssDiskSpaceReport -SqlInstance "SQL01" -WarnThresholdPct 15 -OutputPath "D:\Reports"
Get-mssDiskSpaceReport -SqlInstance "SQL01" | Where-Object Status -eq 'Warning' | Sort-Object DaysUntilFull | Format-Table VolumeName, FreeGB, DaysUntilFull, Status -AutoSize
"SQL01","SQL02","SQL03" | ForEach-Object {
Get-mssDiskSpaceReport -SqlInstance $_ -WarnThresholdPct 10 -ContinueOnError
} | Where-Object Status -eq 'Warning' | Export-Csv "D:\Reports\DiskWarnings.csv" -NoTypeInformationsys.dm_exec_requests, sys.dm_hadr_physical_seeding_stats).Get-mssOperationStatus
Get-mssOperationStatus -SqlInstance "SQL01" -OperationType AutoSeed
Get-mssOperationStatus -Continuous -RefreshSeconds 10
while ($true) {
$ops = Get-mssOperationStatus -SqlInstance "SQL01" -OperationType Restore
if (-not $ops) { Write-Host "Restore abgeschlossen."; break }
$ops | Format-Table Database, PercentComplete, EstimatedTimeRemaining -AutoSize
Start-Sleep 15
}setspn.exe-Kommandos für fehlende SPNs. Schreibt TXT + CSV ins OutputPath.Get-mssSpnReport
Get-mssSpnReport -ComputerName "SQL01" -OutputPath "D:\Reports"
Get-mssSpnReport -ComputerName "SQL01" -InstanceFilter "MSSQLSERVER"
"SQL01","SQL02","SQL03" | ForEach-Object {
Get-mssSpnReport -ComputerName $_ -ContinueOnError
} | Where-Object Status -eq 'Missing' |
Select-Object ComputerName, InstanceName, SpnValue, SetSpnCommand |
Format-Table -AutoSizesys.dm_exec_sessions, sys.dm_exec_requests und sys.dm_exec_connections.
Gruppiert nach Application, Login, Host oder Database. Zeigt Verbindungsauslastung (% von max connections), aktive Requests, CPU-Nutzung, blockierte Sessions und aelteste Verbindungen.
Optionaler CSV-Export. System-Verbindungen optional einschliessbar.Get-mssConnectionStats -SqlInstance "SQL01"
Get-mssConnectionStats -SqlInstance "SQL01" -GroupBy Login -TopN 10
Get-mssConnectionStats -SqlInstance "SQL01" -GroupBy Database -IncludeSystemConnections
$stats = Get-mssConnectionStats -SqlInstance "SQL01" $stats.Summary $stats.ActiveRequests | Where-Object BlockedBy -gt 0 | Format-Table
Get-mssConnectionStats -SqlInstance "SQL01" -GroupBy Host -OutputPath "D:\Reports"
sys.master_files und vergleicht diese mit den tatsaechlich vorhandenen Dateien im Dateisystem.
Suchverzeichnisse werden automatisch aus sys.master_files und den SQL-Registry-Standardpfaden ermittelt oder explizit angegeben.
Hinweis bei Remote-Instanzen: Dateisystemzugriff erfolgt vom lokalen Computer; UNC-Pfade empfohlen.Get-mssOrphanedFiles -SqlInstance "SQL01"
Get-mssOrphanedFiles -SqlInstance "SQL01" -SearchPath "D:\SQLData","E:\SQLLog" -Recurse
Get-mssOrphanedFiles -SqlInstance "SQL01" ` -SearchPath "\\SQL01\D$\SQLData","\\SQL01\E$\SQLLog"
$orphans = Get-mssOrphanedFiles -SqlInstance "SQL01" Write-Host "$($orphans.OrphanedFiles) verwaiste Dateien, $($orphans.TotalOrphanedMB) MB gesamt" $orphans.Files | Sort-Object SizeMB -Descending | Format-Table FileName, SizeMB, LastModified
UpToDate, MinorUpdate (1–2 Builds), MajorUpdate (3–4), Critical (5+ Builds zurueck).
Pipeline-faehig: mehrere Instanzen in einem Aufruf. Optionaler CSV-Export.Invoke-mssPatchAnalysis
"SQL01","SQL02","SQL03" | Invoke-mssPatchAnalysis
"SQL01","SQL02","SQL03" | Invoke-mssPatchAnalysis |
Where-Object PatchStatus -in @('Critical','MajorUpdate') |
Select-Object SqlInstance, ProductVersion, LatestKnownLabel, BuildsBehind, PatchStatusInvoke-mssPatchAnalysis -SqlInstance "SQL01" -OutputPath "D:\Reports"
Get-Content "C:\Scripts\sql-instances.txt" | Invoke-mssPatchAnalysis -OutputPath "D:\Reports"
⚡ Performance
sys.dm_db_missing_index_details): Impact-Score, Tabelle, empfohlene Spalten.Get-mssMissingIndexes -SqlInstance "SQL01" -TopN 20
Get-mssBlockingReport -SqlInstance "SQL01"
Get-mssDeadlockReport -SqlInstance "SQL01"
sys.dm_exec_requests: Session-ID, Laufzeit, CPU, Reads, Wait-Type, SQL-Text.Get-mssLongRunningQueries -SqlInstance "SQL01" -MinDurationSeconds 30
Get-mssIndexFragmentation -Database "AdventureWorks" -MinFragmentationPercent 10
Get-mssIndexFragmentation -SqlInstance "SQL01" -Database "SalesDB" | Where-Object Recommendation -eq 'REBUILD' | Sort-Object FragmentationPercent -Descending | Select-Object TableName, IndexName, FragmentationPercent, Recommendation | Format-Table -AutoSize
Get-mssIndexFragmentation -SqlInstance "SQL01" -All -MinFragmentationPercent 30
Get-mssIndexFragmentation -SqlInstance "SQL01" -Database "Sales" -TableName "OrderDetails"
Invoke-mssUpdateStatistics -Database "SalesDB" -SamplePercent 10
Invoke-mssUpdateStatistics -SqlInstance "SQL01" -All -OnlyModified
Invoke-mssUpdateStatistics -SqlInstance "SQL01" -Database "Sales" ` -TableName "OrderDetails" -FullScan
Get-mssAutoGrowthReport -SqlInstance "SQL01" -HistoryDays 7
Get-mssAutoGrowthReport -SqlInstance "SQL01" | Group-Object DatabaseName | Sort-Object Count -Descending | Select-Object Name, Count | Format-Table -AutoSize
Get-mssAutoGrowthReport -SqlInstance "SQL01" |
Group-Object DatabaseName |
ForEach-Object { [PSCustomObject]@{
DB = $_.Name
GrowthMB = ($_.Group | Measure-Object GrowthMB -Sum).Sum
}} | Sort-Object GrowthMB -DescendingOutputPath\QueryStore.Invoke-mssQueryStore -SqlInstance "SQL01" -All
Invoke-mssQueryStore -SqlInstance "SQL01" ` -Database "SalesDB","CRM" ` -Configure -Query -Diagnose ` -MaxStorageSizeMB 2000 -QueryCaptureMode AUTO
Invoke-mssQueryStore -SqlInstance "SQL01" ` -Database "SalesDB" -Query ` -TopN 50 -OrderBy CPU -LookbackHours 48
Invoke-mssQueryStore -SqlInstance "SQL01" -All ` -Diagnose -StorageWarningPct 70 -OutputPath "D:\Reports\QS"
Invoke-mssQueryStore -SqlInstance "SQL01" ` -Database "OldDB" -Configure -OperationMode OFF
OutputPath\XEvents.Invoke-mssExtendedEvents -SqlInstance "SQL01" -Create -Start
Invoke-mssExtendedEvents -SqlInstance "SQL01" ` -Template SlowQueries ` -SlowQueryThresholdMs 2000 ` -TargetType File -Create -Start
Invoke-mssExtendedEvents -SqlInstance "SQL01" ` -Read -Diagnose -LookbackMinutes 60 -TopN 25
Invoke-mssExtendedEvents -SqlInstance "SQL01" ` -SessionName "DeadlockCapture" ` -Template Deadlocks -TargetType File -Create -Start
Invoke-mssExtendedEvents -SqlInstance "SQL01" -Stop -Drop
sys.dm_os_wait_stats. Filtert automatisch 30+ Idle-Wait-Typen heraus.
Kategorisiert 25+ bekannte Wait Types (CPU, IO, Locking, Memory, Network, TempDB, Log, Parallelism ...) und liefert Handlungsempfehlungen.
Delta-Modus: Mit -SnapshotBefore und -SaveSnapshot lassen sich Intervall-Deltas berechnen - ideal zur Lastanalyse waehrend eines Fensters.
Optionaler CSV-Export.Get-mssWaitStatistics -SqlInstance "SQL01"
Get-mssWaitStatistics -SqlInstance "SQL01" -IncludeIdle -TopN 50
# Snapshot vorher $snap = Get-mssWaitStatistics -SqlInstance "SQL01" -SaveSnapshot Start-Sleep 300 # Delta messen Get-mssWaitStatistics -SqlInstance "SQL01" -SnapshotBefore $snap.Snapshot
Get-mssWaitStatistics -SqlInstance "SQL01" |
Select-Object -ExpandProperty WaitStats |
Where-Object Category -in @('Locking','IO') |
Sort-Object WaitTimeSec -Descending | Format-TableGet-mssWaitStatistics -SqlInstance "SQL01" -OutputPath "D:\Reports"
sys.dm_os_performance_counters:
Buffer Cache Hit Ratio, Page Life Expectancy, Batch Requests/sec, Kompilierungen, Lock Waits, Deadlocks, Speicher, Verbindungen, Scans und mehr.
Interpretiert Werte automatisch und kennzeichnet auffaellige Werte mit CRITICAL/WARNING-Markierungen.
Gibt ein Summary-Objekt mit den wichtigsten KPIs (PLE, BHR, User Connections, Anzahl Warnungen) zurueck.Get-mssPerfCounters -SqlInstance "SQL01"
Get-mssPerfCounters -SqlInstance "SQL01" -Category "Buffer","Memory"
$perf = Get-mssPerfCounters -SqlInstance "SQL01" $perf.Summary $perf.Counters | Where-Object Interpretation -ne '' | Format-Table CounterName, Value, Interpretation
while ($true) {
$s = (Get-mssPerfCounters -SqlInstance "SQL01").Summary
Write-Host "$(Get-Date -f HH:mm:ss) PLE=$($s.PageLifeExpectancy) BHR=$($s.BufferCacheHitRatioPct)% Conn=$($s.UserConnections)"
Start-Sleep 60
}Get-mssPerfCounters -SqlInstance "SQL01" -OutputPath "D:\Reports"
Invoke-mssPerfBaseline -SqlInstance "SQL01" -Action Capture ` -BaselineName "BeforePatch" -OutputPath "D:\Baselines"
Invoke-mssPerfBaseline -SqlInstance "SQL01" -Action Capture ` -BaselineName "AfterPatch" -OutputPath "D:\Baselines"
Invoke-mssPerfBaseline -Action Compare ` -BaselineA "D:\Baselines\PerfBaseline_SQL01_..._BeforePatch.json" ` -BaselineB "D:\Baselines\PerfBaseline_SQL01_..._AfterPatch.json"
Invoke-mssPerfBaseline -Action List -OutputPath "D:\Baselines"
$cmp = Invoke-mssPerfBaseline -Action Compare -BaselineA $fileA -BaselineB $fileB $cmp.WaitDeltas | Select-Object -First 10 | Format-Table WaitType, DeltaWaitSec, Category, Recommendation
🔧 Ola Hallengren Wartung
Install-mssOlaMaintenanceSolution -SqlInstance "SQL01"
Install-mssOlaMaintenanceSolution -SqlInstance "SQL01" -Force
# 1. Ola installieren Install-mssOlaMaintenanceSolution -SqlInstance "SQL01" # 2. Prüfen ob Installation ok Test-mssOlaInstallation -SqlInstance "SQL01" # 3. Maintenance-Jobs anlegen New-mssOlaMaintenanceJobs -SqlInstance "SQL01" -ScheduleTime "23:00" # 4. System-DB-Backup-Job anlegen New-mssOlaSysDbBackupJob -SqlInstance "SQL01" -ScheduleTime "20:00"
New-mssOlaMaintenanceJobs -SqlInstance "SQL01"
New-mssOlaMaintenanceJobs -SqlInstance "SQL01" ` -ScheduleTime "22:00" -ScheduleDay 64 -OperatorName "DBAs"
New-mssOlaMaintenanceJobs -SqlInstance "SQL01" ` -FragmentationLevel1 10 -FragmentationLevel2 40 ` -FillFactor 85 -MaxDOP 4
New-mssOlaMaintenanceJobs -SqlInstance "SQL01" -Update
New-mssOlaSysDbBackupJob -SqlInstance "SQL01"
New-mssOlaSysDbBackupJob -SqlInstance "SQL01" -ScheduleTime "20:00" -OperatorName "DBAs"
-FullScheduleDays, -DiffScheduleDays, -LogScheduleDays) und Startzeit. Backup-Ziel: <BackupDirectory>\Usr-db. Job-Namen aus Modulkonfiguration (OlaJobNameFull / OlaJobNameDiff / OlaJobNameLog). Wochentage als Array; Kurzformen Weekdays, Weekend, EveryDay werden aufgelöst.New-mssOlaUsrDbBackupJob -SqlInstance "SQL01" -Full `
-FullScheduleDays @('Sunday') -FullScheduleTime "21:00"New-mssOlaUsrDbBackupJob -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" `
-OperatorName "DBAs"New-mssOlaUsrDbBackupJob -SqlInstance "SQL01" -Log `
-Databases "SalesDB,HRDB" `
-LogScheduleDays @('EveryDay') -LogScheduleTime "00:30"New-mssOlaUsrDbBackupJob -SqlInstance "SQL01" -Full -Diff -Log -Update
Invoke-mssFormatDrive64k -DriveLetter D
Invoke-mssFormatDrive64k -DriveLetter E -BackupPath "C:\Backup\DriveTemp" -Force
Invoke-mssFormatDrive64k -DriveLetter D -WhatIf
TcpReachable, DynamicPort, Status (OK / Failed / Error) und Detailmeldung zurück. Pipeline-fähig für mehrere Server.Test-mssSQLFirewall -Server "SQL01"
Test-mssSQLFirewall -Server "SQL01" -Instance "SAGE"
"SQL01","SQL02","SQL03" | Test-mssSQLFirewall -Instance "PROD" -TimeoutSeconds 3 | Format-Table Server, Port, TcpReachable, Status -AutoSize
Test-mssOlaInstallation -SqlInstance "SQL01"
if (-not (Test-mssOlaInstallation -SqlInstance "SQL01")) {
Install-mssOlaMaintenanceSolution -SqlInstance "SQL01"
}⚙️ Konfiguration
-Key: einzelner Wert.Get-mssConfig
Get-mssConfig -Key 'OutputPath' Get-mssConfig -Key 'LogPath'
$outPath = Get-mssConfig -Key 'OutputPath' $report = Get-mssDatabaseHealth -SqlInstance "SQL01" -OutputPath $outPath
%APPDATA%\MSSQLTools\config.json). Pfade werden geprüft und erstellt.Set-mssConfig -LogPath "D:\Logs\SQL" -OutputPath "D:\Reports\SQL" -CentralPath "\\Fileserver\SQL"
Set-mssConfig -OlaJobNameFull "PROD-FULL" -OlaJobNameIndexOpt "PROD-IndexOpt"
Set-mssConfig -TsmManagementClasses @('MC_10','MC_30','MC_100')Set-mssConfig -AutoUpdate $false
Compare-mssServerConfiguration -SourceInstance "SQL01" -TargetInstance "SQL02"
Compare-mssServerConfiguration -SourceInstance "SQL01" -TargetInstance "SQL02" |
Where-Object { $_.SourceValue -ne $_.TargetValue } |
Format-Table Setting, SourceValue, TargetValue -AutoSize$targets = "SQL02","SQL03","SQL04"
$targets | ForEach-Object {
$diffs = Compare-mssServerConfiguration -SourceInstance "SQL01" -TargetInstance $_ |
Where-Object { $_.SourceValue -ne $_.TargetValue }
if ($diffs) { Write-Host "$_ hat $($diffs.Count) Abweichungen"; $diffs | Format-Table }
}sqlservr.exe -m -T4022 -T3659 -q. Nur für lokale Standalone-Instanzen. 9-Schritt-Prozess inkl. Pre-Flight, optionales Backup, Stopp/Start-Dienst, Verifikation.Invoke-mssCollationChange -NewCollation "Latin1_General_CI_AS"
Invoke-mssCollationChange -SqlInstance "SQL01\INST2" ` -NewCollation "German_CI_AS" ` -IncludeUserDatabases ` -BackupBeforeChange
Invoke-mssSetDatabaseRecoveryMode -All -RecoveryMode Full
Invoke-mssSetDatabaseRecoveryMode -Database "SalesDB" -RecoveryMode Simple -Confirm
"DB1","DB2","DB3" | ForEach-Object {
Invoke-mssSetDatabaseRecoveryMode -SqlInstance "SQL01" -Database $_ -RecoveryMode Full
}-Name einzelne Eigenschaft, mit -All alle Eigenschaften.$backupPath = Get-mssServerSetting -Name "BackupDirectory"
Get-mssServerSetting -All
$cred = Get-Credential Get-mssServerSetting -SqlInstance "SQL01" -SqlCredential $cred -All
📋 Inventar & Suche
Invoke-mssInstanceInventory
Invoke-mssInstanceInventory -SqlInstance "SQL01","SQL02","SQL03" -ContinueOnError
# Alle SQL-Instanzen in der Umgebung inventarisieren $instances = Get-Content "C:\Admin\sql_instances.txt" Invoke-mssInstanceInventory -SqlInstance $instances -ContinueOnError # Ergebnis liegt in $OutputPath\InstanceInventory_*.txt
Export-mssDatabaseDocumentation -SqlInstance "SQL01" -OutputPath "D:\Reports"
Find-mssDatabaseObject -SqlInstance "SQL01" -ObjectName "sp_GetOrders"
Find-mssDatabaseObject -SqlInstance "SQL01" -ObjectName "*log*" ` -ObjectType "TABLE","VIEW" -Database "Sales*"
Find-mssDatabaseObject -SqlInstance "SQL01" -ObjectName "*" ` -SearchInDefinition -SearchText "OPENQUERY" | Format-Table Database, Schema, ObjectType, ObjectName -AutoSize
Find-mssDatabaseObject -SqlInstance "SQL01" -ObjectName "*" -ObjectType "TRIGGER" | Group-Object Database | Select-Object Name, Count
Get-mssLinkedServerUsage -SqlInstance "SQL01" -LinkedServer "PROD_SRV"
Get-mssLinkedServerUsage -SqlInstance "SQL01" | Group-Object LinkedServer | Select-Object Name, Count | Sort-Object Count -Descending
$usage = Get-mssLinkedServerUsage -SqlInstance "SQL01" -LinkedServer "OLD_SRV"
if ($usage) {
Write-Warning "Linked Server wird noch verwendet!"
$usage | Format-Table Database, Schema, ObjectType, ObjectName -AutoSize
} else {
Write-Host "Linked Server kann sicher entfernt werden."
}Get-mssAgentJobHistory
Get-mssAgentJobHistory -JobName '*Backup*' -Status Failure ` -Since (Get-Date).AddDays(-1) | Format-Table JobName, RunDate, RunDuration, Message -AutoSize
Get-mssAgentJobHistory -SqlInstance "SQL01" -Since (Get-Date).AddDays(-30) |
Group-Object JobName | ForEach-Object {
$ok = @($_.Group | Where RunStatus -eq 'Success').Count
$fail = @($_.Group | Where RunStatus -eq 'Failure').Count
[PSCustomObject]@{ Job = $_.Name; Erfolg = $ok; Fehler = $fail }
} | Sort-Object Fehler -DescendingGet-mssAgentJobHistory -SqlInstance "SQL01" -JobName "FITS-SystemDatabases-FULL" | Select-Object -First 10 | Format-Table -AutoSize
🖥️ Cluster & Dienste
$info = Get-mssClusterInfo -ClusterName "MEINCLUSTER" $info.Nodes | Format-Table $info.Roles | Where-Object OwnerNode -eq "SQL01" | Select-Object Name, IPAddresses
Get-mssClusterInfo -IncludeCoreGroup
$info = Get-mssClusterInfo -ClusterName "MEINCLUSTER"
if (-not $info.Success) { Write-Error $info.ErrorMessage; return }Set-mssConfig -SsrsInstallerPath voreinstellbar.Set-mssConfig -SsrsInstallerPath '\\srv-share\Software\SSRS2022\SQLServerReportingServices.exe' Install-mssSsrsReportServer
Set-mssSsrsConfiguration
Set-mssSsrsConfiguration -ComputerName "SSRS01" -DatabaseServer "AG_Listener"
Set-mssSsrsConfiguration -ComputerName "SSRS01" -WhatIf
$pwd = Read-Host "SSISDB-Kennwort" -AsSecureString Invoke-mssSsisConfiguration -SqlInstance "SQL01" -CatalogPassword $pwd
$pwd = Read-Host "SSISDB-Kennwort" -AsSecureString Invoke-mssSsisConfiguration -SqlInstance "SQL01" -AgName "AG_SSIS" -CatalogPassword $pwd
Test-mssSsasDirectoryPermissions
Test-mssSsasDirectoryPermissions -InstanceName "SSAS2019" -WhatIf
🔐 Zertifikate
Get-mssCertificateReport -SqlInstance "SQL01"
Install-mssCertificate -SqlInstance "SQL01" -CertificatePath "C:\Certs\SQL01.pfx" -CertPassword $cred
New-mssCertificateRequest -SqlInstance "SQL01" -OutputPath "C:\Certs"
New-mssSqlCertificate -SqlInstance "SQL01" -ValidityYears 5
📼 TSM / IBM Spectrum Protect
Invoke-mssTsmConfiguration -ManagementClass MC_B_NL.NL_42.42.NA
Invoke-mssTsmConfiguration -ComputerName "SQL01" -UseDiff
Invoke-mssTsmConfiguration -ComputerName "SQL01" -AdditionalIncludePaths "E:\Archive","F:\ExtraBackup"
Get-mssTsmConfiguration
Get-mssTsmConfiguration -ComputerName "SQL01"
Test-mssTsmConnection
Test-mssTsmConnection -ComputerName "SQL01" -ContinueOnError
🔹 Sonstige
Set-mssSqlPolicyState -SqlInstance "SQL01" -Policy "xp_cmdshell must be disabled" -State Disable
"SQL01","SQL02" | Set-mssSqlPolicyState -Policy "Password Policy" -State Enable
Set-mssSqlPolicyState -SqlInstance "SQL01" -Policy "DefaultPolicy" -State Disable Invoke-mssRestoreDatabase -SqlInstance "SQL01" -BackupFile "D:\Backup\DB.bak" -DatabaseName "DB" Set-mssSqlPolicyState -SqlInstance "SQL01" -Policy "DefaultPolicy" -State Enable
Invoke-mssMonitoringKey -SqlInstance "SQL01"
"SQL01","SQL02","SQL03" | ForEach-Object {
Invoke-mssMonitoringKey -SqlInstance $_ -ContinueOnError
}Copy-mssToCentralPath
Copy-mssToCentralPath -SourcePath "D:\Reports" -CentralPath "\\Fileserver\SQL\Reports"
Add-WindowsCapability, (2) Install-WindowsFeature, (3) dism.exe, (4) PSGallery. Erfordert lokale Administratorrechte. Wird automatisch von Copy-mssLogins und Invoke-mssLoginAudit aufgerufen wenn das AD-Modul fehlt.Install-mssAdModule
Install-mssAdModule -SkipIfPresent $false
if (-not (Install-mssAdModule -ContinueOnError)) {
Write-Warning "AD-Modul nicht verfügbar – Windows-Login-Prüfung wird übersprungen"
}Set-mssConfig -HpuDomainGroupMap). Intern von Audit- und Login-Funktionen genutzt.Get-mssHpuAllowGroup -ServerFqdn "SQL01.bayernlb.sfinance.net"
🚀 Quick Start
# Empfohlener Zielpfad (systemweit, alle Benutzer): C:\Program Files\WindowsPowerShell\Modules\mssSQLTool\ # Alternativ: nur fuer den aktuellen Benutzer $env:USERPROFILE\Documents\WindowsPowerShell\Modules\mssSQLTool\ # Alle konfigurierten Modulpfade anzeigen $env:PSModulePath -split ';' # Modul-Verzeichnis anlegen und Dateien kopieren $target = "C:\Program Files\WindowsPowerShell\Modules\mssSQLTool" Copy-Item -Path "C:\CCM\mssSQLTool" -Destination $target -Recurse -Force # Nach korrekter Ablage genuegt ein einfaches: Import-Module mssSQLTool
Import-Module mssSQLTool automatisch gefunden.
PowerShell Studio und ISE erkennen es zudem per Auto-Completion ohne weiteres Zutun.
# dbatools installieren (falls noch nicht vorhanden) Install-Module dbatools -Scope CurrentUser -Force # mssSQLTool-Modul laden Import-Module "C:\Pfad\zum\mssSQLTool\mssSQLTool.psd1"
Set-mssConfig ` -LogPath "C:\System\WinSrvLog\MSSQL" ` -OutputPath "C:\System\WinSrvLog\MSSQL" ` -CentralPath "\\Fileserver\SQL\Reports" # Konfiguration prüfen Get-mssConfig
$instance = "SQL01" # Anpassen! Write-Host "=== Instance Check ===" -ForegroundColor Cyan Get-mssSQLInstanceCheck -SqlInstance $instance | Where-Object Status -ne 'OK' | Format-Table Check, CurrentValue, Status Write-Host "=== Database Health ===" -ForegroundColor Cyan Get-mssDatabaseHealth -SqlInstance $instance | Select-Object DatabaseName, Status, RecoveryModel, LastFullBackup, VlfCount | Format-Table -AutoSize Write-Host "=== Disk Space ===" -ForegroundColor Cyan Get-mssDiskSpaceReport -SqlInstance $instance | Format-Table VolumeName, FreeGB, DaysUntilFull, Status -AutoSize
$instance = "SQL01"
# Schritt 1: Ola installieren
Install-mssOlaMaintenanceSolution -SqlInstance $instance
# Schritt 2: Installation prüfen
Test-mssOlaInstallation -SqlInstance $instance
# Schritt 3: Index + Integrity Jobs anlegen
New-mssOlaMaintenanceJobs -SqlInstance $instance -ScheduleTime "23:00" -OperatorName "DBAs"
# Schritt 4: System-DB-Backup-Job
New-mssOlaSysDbBackupJob -SqlInstance $instance -ScheduleTime "20:00" -OperatorName "DBAs"
# Schritt 5: User-DB-Backup-Jobs (FULL/DIFF/LOG)
New-mssOlaUsrDbBackupJob -SqlInstance $instance -Full -Diff -Log `
-FullScheduleDays @('Sunday') -FullScheduleTime "21:00" `
-DiffScheduleDays @('Monday','Tuesday','Wednesday','Thursday','Friday','Saturday') `
-DiffScheduleTime "21:00" `
-LogScheduleDays @('EveryDay') -LogScheduleTime "00:00" `
-OperatorName "DBAs"$instance = "SQL01" # SA-Konto verschleiern $r = Invoke-mssSaObfuscation -SqlInstance $instance Write-Host "Neuer SA-Name: $($r.NewLoginName)" $r.GeneratedPassword | Out-File "C:\Secure\sa_pw_$(Get-Date -f 'yyyyMMdd').txt" # Sysadmin-Audit Get-mssSysadminAccounts -SqlInstance $instance -ExcludeSysAccounts | Where-Object Status -eq 'Unexpected' | Format-Table LoginName, LoginType
$instance = "SQL01" $ag = "AG_Prod" # Datenbank hinzufügen Invoke-mssAddDatabaseToAvailabilityGroup -SqlInstance $instance ` -AvailabilityGroup $ag -Database "NeueDB" # AG-Nodes synchronisieren (Logins, Jobs, Linked Server) Sync-mssAgNode -SqlInstance $instance -AvailabilityGroup $ag # Health-Report prüfen Get-mssAgHealthReport -SqlInstance $instance | Where-Object OverallStatus -ne 'Healthy' | Format-Table -AutoSize
⚙️ Modul-Konfiguration
%APPDATA%\MSSQLTools\config.json) und beim Modulimport automatisch geladen. Änderungen greifen sofort — kein Neuimport nötig.
Konfigurationsschlüssel
| Schlüssel | Standard | Beschreibung |
|---|---|---|
LogPath | C:\System\WinSrvLog\MSSQL | Pfad für Log-Dateien |
OutputPath | C:\System\WinSrvLog\MSSQL | Pfad für Report-Ausgaben (TXT/CSV) |
CentralPath | C:\System\WinSrvLog\MSSQL | Zentraler Pfad (z. B. Fileserver) |
OlaJobNameFull | FITS-UserDatabases-FULL | Job-Name für Ola Full-Backup |
OlaJobNameDiff | FITS-UserDatabases-DIFF | Job-Name für Ola Diff-Backup |
OlaJobNameLog | FITS-UserDatabases-LOG | Job-Name für Ola Log-Backup |
OlaJobNameIndexOpt | FITS-UserDatabases-IndexOptimize | Job-Name für Ola IndexOptimize |
OlaJobNameIntUserDb | FITS-UserDatabases-IntegrityCheck | Job-Name für Ola IntegrityCheck User |
OlaJobNameIntSysDb | FITS-SystemDatabases-IntegrityCheck | Job-Name für Ola IntegrityCheck System |
OlaJobNameSysDbBackup | FITS-SystemDatabases-FULL | Job-Name für System-DB-Backup |
TsmManagementClasses | [] | TSM Management-Klassen-Liste |
HpuDomainGroupMap | [] | Domain→Gruppen-Mapping für Get-mssHpuAllowGroup |
SsrsInstallerPath | "" | Pfad zur SSRS-Installationsdatei für Install-mssSsrsReportServer. |
AutoUpdate | $false | Automatisches Modul-Update beim Import |
UpdateRepository | "" | PSRepository-Name für Auto-Update |
DefaultPolicy | "" | PBM-Policy die bei Restore temp. deaktiviert wird |
Language | de-DE | Ausgabe-Sprache. de-DE (Standard) · en-US. |
Beispiel-Konfiguration
# Komplette Initialkonfiguration für Produktivumgebung
Set-mssConfig `
-LogPath "D:\Logs\SQL" `
-OutputPath "D:\Reports\SQL" `
-CentralPath "\\Fileserver01\SQL\Reports" `
-OlaJobNameFull "PROD-UserDB-FULL" `
-OlaJobNameIndexOpt "PROD-UserDB-IndexOpt" `
-OlaJobNameSysDbBackup "PROD-SysDB-FULL" `
-TsmManagementClasses @('MC_B_NL.NL_42.42.NA') `
-SsrsInstallerPath '\\srv-share\Software\SSRS2022\SQLServerReportingServices.exe' `
-DefaultPolicy "DBA-StandardPolicy" `
-Language de-DE `
-AutoUpdate $false
Spracheinstellungen
de-DE (Standard) · en-US. Sprachdateien: Private\Strings\{lang}.psd1.Set-mssConfig -Language en-US Set-mssConfig -Language de-DE