sqmSQLTool.psm1
|
<#
=========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.183 Created on: 21.04.2026 15:37 Created by: Janke Organization: dtcSoftware Filename: sqmSQLTool.psm1 ------------------------------------------------------------------------- Module Name: sqmSQLTool =========================================================================== #> # ============================================================================= # SCHRITT 1: Modulkonfiguration als ERSTES initialisieren # (muss vor dem Laden der Funktionen und vor Get-sqmConfig-Aufrufen stehen) # Neutrale Standardwerte fuer PSGallery-Nutzer. # FI-TS-spezifische Werte werden in Schritt 1b gesetzt wenn erkannt. # ============================================================================= $script:sqmModuleConfig = @{ LogPath = "C:\System\WinSrvLog\MSSQL" OutputPath = "C:\System\WinSrvLog\MSSQL" CentralPath = $null OlaJobNameFull = "OlaHH-UserDatabases-FULL" OlaJobNameDiff = "OlaHH-UserDatabases-DIFF" OlaJobNameLog = "OlaHH-UserDatabases-LOG" OlaJobNameIndexOpt = "OlaHH IndexOptimize - USER_DATABASES" OlaJobNameIntUserDb = "OlaHH IntegrityCheck - USER_DATABASES" OlaJobNameIntSysDb = "OlaHH IntegrityCheck - SYSTEM_DATABASES" OlaJobNameSysDbBackup = "OlaHH-SystemDatabases-FULL" OlaJobNameOutputCleanup = "DatabaseMaintenance-Output File Cleanup" OlaJobNamePurgeJobHistory = "DatabaseMaintenance-sp_purge_jobhistory" OlaJobNameDeleteBackupHistory = "DatabaseMaintenance-sp_delete_backuphistory" BackupDirectory = $null HpuDomainGroupMap = @() SsrsInstallerPath = $null AutoUpdate = $false UpdateRepository = '' # Auto-Update-Quelle (zuletzt verwendete Installationsquelle - von Install.ps1 gesetzt # bzw. zur Laufzeit erkannt). Type: 'PSGallery'|'UNC'|'GitHub'|'LocalDir'|''(leer=auto). InstallSourceType = '' InstallSourcePath = '' # Throttle fuer den On-Import-Update-Check (Stunden zwischen Netz-Pruefungen). UpdateCheckIntervalHours = 24 ModuleVersion = '1.0.0' Language = 'en-US' # Check-Profil: 'Auto' = FI-TS wenn erkannt, 'FiTs' = immer, 'Generic' = nie FI-TS-Checks CheckProfile = 'Auto' # Grenzwerte fuer Setup-Checks (neutrale Defaults, FI-TS-Block setzt gleiche Werte) CheckCostThresholdMin = 50 CheckTempDbMaxFiles = 8 CheckDiskBlockSize = 65536 # Monitoring-Zugang (Enable-sqmMonitoringAccess) DefaultPolicy = $null # Policy die vor Setup deaktiviert wird, $null = kein Policy-Handling DefaultMonitoringUser = $null # Windows-Login des Monitoring-Accounts, $null = Pflicht per Parameter # Verbindungssicherheit: TrustServerCertificate fuer alle dbatools-Verbindungen. # SQL Server 2022+ / neuere Microsoft.Data.SqlClient erzwingen Encrypt=True und pruefen # das Serverzertifikat. Bei self-signed Zertifikaten schlaegt die Verbindung sonst mit # "The certificate chain was issued by an authority that is not trusted" fehl. TrustServerCertificate = $true } # Aktuelle Version aus der Manifestdatei lesen $manifestPath = Join-Path $PSScriptRoot 'sqmSQLTool.psd1' if (Test-Path $manifestPath) { try { $manifestData = Import-PowerShellDataFile -Path $manifestPath -ErrorAction Stop $script:sqmModuleConfig['ModuleVersion'] = $manifestData.ModuleVersion } catch { } } # ============================================================================= # SCHRITT 1b: FI-TS-Umgebungserkennung # Kriterium 1: Modul liegt auf W:\ (FI-TS Netzlaufwerk) # Kriterium 2: Angemeldeter Benutzer ist in Domaene OFFICELAN.IZB / OFFICELAN # Wenn erkannt: FI-TS-Standardwerte setzen (config.json ueberschreibt weiterhin). # ============================================================================= $script:sqmIsFitsEnvironment = $false if ($PSScriptRoot -like 'W:\*' -or $PSScriptRoot -like '\\tsclient\W\*') { $script:sqmIsFitsEnvironment = $true Write-Verbose "sqmSQLTool: FI-TS-Umgebung erkannt (Modulpfad: $PSScriptRoot)." } if (-not $script:sqmIsFitsEnvironment) { $_dnsDomain = $env:USERDNSDOMAIN $_userDomain = $env:USERDOMAIN if (($_dnsDomain -and $_dnsDomain -eq 'OFFICELAN.IZB') -or ($_userDomain -and $_userDomain -eq 'OFFICELAN')) { $script:sqmIsFitsEnvironment = $true Write-Verbose "sqmSQLTool: FI-TS-Umgebung erkannt (Domaene: $_dnsDomain / $_userDomain)." } } if ($script:sqmIsFitsEnvironment) { $script:sqmModuleConfig['LogPath'] = 'C:\System\WinSrvLog\MSSQL' $script:sqmModuleConfig['OutputPath'] = 'C:\System\WinSrvLog\MSSQL' $script:sqmModuleConfig['AutoUpdate'] = $true $script:sqmModuleConfig['UpdateRepository'] = 'W:\75084-Datenbanken\MSSQL\CPM\sqmSQLTool' $script:sqmModuleConfig['TsmManagementClasses'] = @('MC_B_NL.NL_35.35.NA') $script:sqmModuleConfig['DefaultPolicy'] = 'New Login_Enforce Passwort Policy' $script:sqmModuleConfig['DefaultMonitoringUser'] = "$env:USERDOMAIN\izt0504" $script:sqmModuleConfig['SsrsInstallerPath'] = 'W:\75084-Datenbanken\MSSQL\SQLSources\Reporting' $script:sqmModuleConfig['OlaJobNameFull'] = 'FITS Backup - USER_DATABASES - FULL' $script:sqmModuleConfig['OlaJobNameDiff'] = 'FITS Backup - USER_DATABASES - DIFF' $script:sqmModuleConfig['OlaJobNameLog'] = 'FITS Backup - USER_DATABASES - LOG' $script:sqmModuleConfig['OlaJobNameIndexOpt'] = 'FITS IndexOptimize - USER_DATABASES' $script:sqmModuleConfig['OlaJobNameIntUserDb'] = 'FITS IntegrityCheck - USER_DATABASES' $script:sqmModuleConfig['OlaJobNameIntSysDb'] = 'FITS IntegrityCheck - SYSTEM_DATABASES' $script:sqmModuleConfig['OlaJobNameSysDbBackup'] = 'FITS Backup - SYSTEM_DATABASES - FULL' $script:sqmModuleConfig['OlaJobNameOutputCleanup'] = 'FITS Output File Cleanup' $script:sqmModuleConfig['OlaJobNamePurgeJobHistory'] = 'FITS sp_purge_jobhistory' $script:sqmModuleConfig['OlaJobNameDeleteBackupHistory'] = 'FITS sp_delete_backuphistory' # FI-TS Check-Profil und Grenzwerte (identisch mit Defaults, explizit gesetzt fuer Ueberschreibbarkeit) $script:sqmModuleConfig['CheckProfile'] = 'FiTs' $script:sqmModuleConfig['CheckCostThresholdMin'] = 50 $script:sqmModuleConfig['CheckTempDbMaxFiles'] = 8 $script:sqmModuleConfig['CheckDiskBlockSize'] = 65536 } # ============================================================================= # SCHRITT 1c: Persistierte Konfiguration laden (ueberschreibt alle Standardwerte) # ============================================================================= $configFile = Join-Path $env:APPDATA "MSSQLTools\config.json" if (Test-Path $configFile) { try { $userConfig = Get-Content $configFile -Raw | ConvertFrom-Json foreach ($key in $userConfig.PSObject.Properties) { $script:sqmModuleConfig[$key.Name] = $key.Value } } catch { Write-Warning "Konfiguration konnte nicht geladen werden: $($_.Exception.Message)" } } # String-Cache invalidieren (wird durch Get-sqmString bei erstem Zugriff neu befuellt) $script:_strings = $null # ============================================================================= # SCHRITT 2: dbatools-Verfuegbarkeit pruefen und einmalig laden # Robuste Pruefung: zuerst bereits geladen, dann expliziter Import-Versuch # ============================================================================= $script:dbatoolsAvailable = $false if (Get-Module -Name dbatools) { # dbatools bereits in der Session geladen (z.B. via RequiredModules) $script:dbatoolsAvailable = $true } else { try { Import-Module dbatools -ErrorAction Stop $script:dbatoolsAvailable = $true } catch { # dbatools nicht ladbar - nur warnen, Modul laedt trotzdem $script:dbatoolsAvailable = $false } } if (-not $script:dbatoolsAvailable) { Write-Warning "dbatools-Modul nicht gefunden. Funktionen die dbatools benoetigen sind nicht verfuegbar. Installation: Install-Module dbatools" } else { # TrustServerCertificate fuer ALLE dbatools-Verbindungen aktivieren (self-signed Zertifikate). # Behebt "The certificate chain was issued by an authority that is not trusted" auf SQL 2022+. # Per Set-sqmConfig -TrustServerCertificate $false abschaltbar (vor dem Import gesetzt). if ($script:sqmModuleConfig['TrustServerCertificate']) { try { # Hinweis: Set-DbatoolsConfig hat KEINEN -Scope-Parameter (dbatools 2.8.x) - die # Einstellung gilt ohnehin sessionweit. Fruehere Variante mit "-Scope Session" warf # eine vom catch verschluckte Exception, sodass trustcert nie gesetzt wurde. Set-DbatoolsConfig -FullName 'sql.connection.trustcert' -Value $true -ErrorAction SilentlyContinue } catch { Write-Verbose "Konnte dbatools trustcert nicht setzen: $($_.Exception.Message)" } } } # ============================================================================= # SCHRITT 3: Private und Public Funktionen laden # ============================================================================= $PublicPath = Join-Path $PSScriptRoot 'Public' $PrivatePath = Join-Path $PSScriptRoot 'Private' Get-ChildItem -Path $PrivatePath -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue | ForEach-Object { . $_.FullName } Get-ChildItem -Path $PublicPath -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue | ForEach-Object { . $_.FullName } # ============================================================================= # SCHRITT 4: Logging-Bereitschaft pruefen (NACH Funktionsladung und Config-Init) # ============================================================================= $script:sqmLoggingReady = Test-sqmLoggingPath -Path (Get-sqmConfig -Key "LogPath") # ============================================================================= # Update-Mechanismus mit Fallback-Chain # ============================================================================= # Priorität: # 1. PowerShell Gallery (PSGallery) # 2. GitHub Releases (fallback) # 3. UNC-Pfad (fallback) # 4. Warnung ausgeben wenn alle fehlschlagen <# .SYNOPSIS Prueft ob eine neuere Version des Moduls in PowerShell Gallery verfuegbar ist. .PARAMETER ModuleName Name des Moduls (Standard: sqmSQLTool). #> function Test-InternetConnectivity { <# .SYNOPSIS Prüft ob eine Internetverbindung zu PowerShell Gallery vorhanden ist. .DESCRIPTION Schneller, non-blocking Check ohne NuGet-Installation zu erzwingen. Versucht DNS-Auflösung (schnell) und optional HTTP-Verbindung (mit Timeout). #> param( [int]$TimeoutMs = 3000 ) try { # Schneller DNS-Check (funktioniert meist offline auch nicht) $dnsTest = @{ Server = 'www.powershellgallery.com' ErrorAction = 'Stop' } $null = [System.Net.Dns]::GetHostEntry($dnsTest.Server) return $true } catch { Write-Verbose "Keine Internetverbindung erkannt (DNS-Auflösung fehlgeschlagen)" return $false } } function Test-sqmUpdateViaPSGallery { [CmdletBinding()] param ([string]$ModuleName = 'sqmSQLTool') # === FLEXIBLE LÖSUNG: Prüfe zuerst Internetverbindung === # Wenn kein Internet -> kein NuGet-Hang, direkt Fallback if (-not (Test-InternetConnectivity)) { Write-Verbose "Keine Internetverbindung: PSGallery-Check übersprungen" return $null } try { $galleryModule = Find-Module -Name $ModuleName -Repository PSGallery -ErrorAction Stop $currentVersion = [version]$script:sqmModuleConfig['ModuleVersion'] $galleryVersion = [version]$galleryModule.Version if ($galleryVersion -gt $currentVersion) { Write-Verbose "PSGallery: Neuere Version verfuegbar ($($galleryModule.Version))" return @{ Source = 'PSGallery' Version = $galleryVersion UpdateCommand = "Update-Module -Name $ModuleName -Repository PSGallery -Force" } } return $null } catch { Write-Verbose "PSGallery-Check fehlgeschlagen: $($_.Exception.Message)" return $null } } <# .SYNOPSIS Prueft ob eine neuere Version auf GitHub Releases verfuegbar ist. .PARAMETER GitHubRepo GitHub Repository (Format: owner/repo, z.B. JankeUwe/sqmSQLTool). #> function Test-sqmUpdateViaGitHub { [CmdletBinding()] param ([string]$GitHubRepo = 'JankeUwe/sqmSQLTool') try { $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/$GitHubRepo/releases/latest" ` -Headers @{'Accept' = 'application/vnd.github+json'} ` -ErrorAction Stop # Version aus Tag extrahieren (v1.4.0.0 -> 1.4.0.0) $tagVersion = $latestRelease.tag_name -replace '^v', '' $currentVersion = [version]$script:sqmModuleConfig['ModuleVersion'] $releaseVersion = [version]$tagVersion if ($releaseVersion -gt $currentVersion) { Write-Verbose "GitHub: Neuere Version verfuegbar ($tagVersion)" return @{ Source = 'GitHub' Version = $releaseVersion URL = $latestRelease.html_url UpdateCommand = "# ZIP von $($latestRelease.html_url) herunterladen und manuell entpacken" } } return $null } catch { Write-Verbose "GitHub-Check fehlgeschlagen: $($_.Exception.Message)" return $null } } <# .SYNOPSIS Prueft ob eine neuere Version im UNC-Pfad verfuegbar ist. .PARAMETER RepositoryPath UNC-Pfad zum Repository. #> function Test-sqmUpdateViaUNC { [CmdletBinding()] param ([string]$RepositoryPath = $script:sqmModuleConfig['UpdateRepository']) try { if (-not $RepositoryPath) { Write-Verbose "Kein UNC-Repository konfiguriert." return $null } if (-not (Test-Path -Path $RepositoryPath -ErrorAction SilentlyContinue)) { Write-Verbose "UNC-Repository nicht erreichbar: $RepositoryPath" return $null } $remoteVersionFile = Join-Path $RepositoryPath 'ModuleVersion.txt' if (Test-Path -Path $remoteVersionFile -ErrorAction SilentlyContinue) { $remoteVersion = (Get-Content -Path $remoteVersionFile -ErrorAction Stop).Trim() } else { $remoteManifest = Join-Path $RepositoryPath 'sqmSQLTool.psd1' if (Test-Path -Path $remoteManifest -ErrorAction SilentlyContinue) { $remoteData = Import-PowerShellDataFile -Path $remoteManifest -ErrorAction Stop $remoteVersion = $remoteData.ModuleVersion } else { Write-Verbose "Keine Versionsinformation im UNC-Repository gefunden." return $null } } $currentVersion = [version]$script:sqmModuleConfig['ModuleVersion'] $newVersion = [version]$remoteVersion if ($newVersion -gt $currentVersion) { Write-Verbose "UNC: Neuere Version verfuegbar ($newVersion)" return @{ Source = 'UNC' Version = $newVersion Path = $RepositoryPath UpdateCommand = "Update-sqmModule -RepositoryPath '$RepositoryPath'" } } return $null } catch { Write-Verbose "UNC-Check fehlgeschlagen: $($_.Exception.Message)" return $null } } <# .SYNOPSIS Ermittelt die effektive Update-Quelle (zuletzt verwendete Installationsquelle). .DESCRIPTION Primaer aus der Config (InstallSourceType/InstallSourcePath, von Install.ps1 gesetzt). Ist nichts gesetzt: Auto-Erkennung - via PowerShellGet installiert -> PSGallery, sonst konfiguriertes UpdateRepository -> UNC, sonst leer. Rueckgabe: Hashtable @{ Type='PSGallery'|'UNC'|'GitHub'|'LocalDir'|''; Path='...' }. #> function Get-sqmInstallSource { [CmdletBinding()] param () $type = $script:sqmModuleConfig['InstallSourceType'] $path = $script:sqmModuleConfig['InstallSourcePath'] if ($type) { return @{ Type = "$type"; Path = "$path" } } # Auto-Erkennung: ueber PowerShellGet (Install-Module) installiert -> PSGallery try { $inst = Get-InstalledModule -Name sqmSQLTool -ErrorAction Stop | Select-Object -First 1 if ($inst -and $inst.Repository) { return @{ Type = 'PSGallery'; Path = "$($inst.Repository)" } } } catch { } # sonst: konfiguriertes UNC-Repository if ($script:sqmModuleConfig['UpdateRepository']) { return @{ Type = 'UNC'; Path = "$($script:sqmModuleConfig['UpdateRepository'])" } } return @{ Type = ''; Path = '' } } <# .SYNOPSIS Prueft ob eine neuere Version verfuegbar ist - QUELLENBEWUSST. .DESCRIPTION Prueft zuerst die zuletzt verwendete Installationsquelle (Get-sqmInstallSource). Ist diese erreichbar, ist sie massgeblich (kein Fallback). Ist die letzte Quelle unbekannt oder nicht erreichbar, greift die Fallback-Kette PSGallery -> GitHub -> UNC. .PARAMETER Credential Credentials fuer UNC-Freigaben. #> function Test-sqmModuleUpdate { [CmdletBinding()] param ( [System.Management.Automation.PSCredential]$Credential ) $src = Get-sqmInstallSource # Erreichbarkeit der letzten Quelle bestimmen $reachable = switch ($src.Type) { 'PSGallery' { Test-InternetConnectivity } 'GitHub' { Test-InternetConnectivity } 'UNC' { [bool]$src.Path -and (Test-Path -Path $src.Path -ErrorAction SilentlyContinue) } 'LocalDir' { [bool]$src.Path -and (Test-Path -Path $src.Path -ErrorAction SilentlyContinue) } default { $false } } if ($src.Type -and $reachable) { # Letzte Quelle ist massgeblich -> KEIN Fallback Write-Verbose "Update-Check gegen letzte Quelle: $($src.Type) ($($src.Path))" switch ($src.Type) { 'PSGallery' { return Test-sqmUpdateViaPSGallery -ModuleName 'sqmSQLTool' } 'GitHub' { return Test-sqmUpdateViaGitHub -GitHubRepo $(if ($src.Path) { $src.Path } else { 'JankeUwe/sqmSQLTool' }) } 'UNC' { return Test-sqmUpdateViaUNC -RepositoryPath $src.Path } 'LocalDir' { return Test-sqmUpdateViaUNC -RepositoryPath $src.Path } } } # Quelle unbekannt oder nicht erreichbar -> Fallback-Kette PSGallery -> GitHub -> UNC Write-Verbose "Letzte Quelle unbekannt/nicht erreichbar -> Fallback-Kette" $updateResult = Test-sqmUpdateViaPSGallery -ModuleName 'sqmSQLTool' if ($updateResult) { return $updateResult } $updateResult = Test-sqmUpdateViaGitHub -GitHubRepo 'JankeUwe/sqmSQLTool' if ($updateResult) { return $updateResult } $updateResult = Test-sqmUpdateViaUNC -RepositoryPath $script:sqmModuleConfig['UpdateRepository'] if ($updateResult) { return $updateResult } return $null } <# .SYNOPSIS Kopiert die Moduldateien aus einem Quellordner in den Modulordner (mit optionalem Backup). Gemeinsame Hilfe fuer UNC-, LocalDir- und GitHub-Updates. #> function Copy-sqmModuleFiles { [CmdletBinding()] param ( [Parameter(Mandatory)][string]$SourcePath, [Parameter(Mandatory)][string]$ModulePath, [switch]$Backup = $true ) if ($Backup) { $backupDir = Join-Path $env:TEMP "sqmSQLTool_Backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" Copy-Item -Path $ModulePath -Destination $backupDir -Recurse -Force -ErrorAction Stop Write-Host "Backup erstellt: $backupDir" -ForegroundColor Gray } Get-ChildItem -Path $SourcePath -Recurse -File | ForEach-Object { $relativePath = $_.FullName.Substring($SourcePath.Length).TrimStart('\') $targetFile = Join-Path $ModulePath $relativePath $targetDir = Split-Path $targetFile -Parent if (-not (Test-Path $targetDir)) { New-Item -ItemType Directory -Path $targetDir -Force | Out-Null } Copy-Item -Path $_.FullName -Destination $targetFile -Force -ErrorAction Stop Unblock-File -Path $targetFile -ErrorAction SilentlyContinue } } <# .SYNOPSIS Aktualisiert das Modul aus einem GitHub-Release (laedt das ZIP-Asset, entpackt, kopiert). .PARAMETER Version Release-Version (z.B. 1.8.0.0). Ohne Angabe wird das latest-Release verwendet. #> function Update-sqmFromGitHub { [CmdletBinding()] param ( [string]$Version, [Parameter(Mandatory)][string]$ModulePath, [switch]$Backup = $true, [string]$GitHubRepo = 'JankeUwe/sqmSQLTool' ) $tmp = Join-Path $env:TEMP "sqmSQLTool_gh_$(Get-Date -Format 'yyyyMMddHHmmss')" New-Item -ItemType Directory -Path $tmp -Force | Out-Null try { if (-not $Version) { $latest = Invoke-RestMethod -Uri "https://api.github.com/repos/$GitHubRepo/releases/latest" ` -Headers @{ 'Accept' = 'application/vnd.github+json' } -ErrorAction Stop $Version = $latest.tag_name -replace '^v', '' } $zipUrl = "https://github.com/$GitHubRepo/releases/download/v$Version/sqmSQLTool-v$Version.zip" $zipFile = Join-Path $tmp "sqmSQLTool-v$Version.zip" [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri $zipUrl -OutFile $zipFile -UseBasicParsing -ErrorAction Stop Expand-Archive -Path $zipFile -DestinationPath $tmp -Force -ErrorAction Stop # Quelle = Ordner, der die sqmSQLTool.psd1 enthaelt (ZIP kann einen Wurzelordner haben) $psd1 = Get-ChildItem -Path $tmp -Recurse -Filter 'sqmSQLTool.psd1' -ErrorAction Stop | Select-Object -First 1 if (-not $psd1) { throw "sqmSQLTool.psd1 im heruntergeladenen ZIP nicht gefunden." } Copy-sqmModuleFiles -SourcePath $psd1.Directory.FullName -ModulePath $ModulePath -Backup:$Backup Write-Host "Modul aus GitHub-Release v$Version aktualisiert." -ForegroundColor Green Write-Warning "Bitte Session neu starten oder 'Remove-Module sqmSQLTool; Import-Module sqmSQLTool'." } finally { Remove-Item -Path $tmp -Recurse -Force -ErrorAction SilentlyContinue } } <# .SYNOPSIS Aktualisiert sqmSQLTool QUELLENBEWUSST von der zuletzt verwendeten Installationsquelle. .DESCRIPTION Dispatcht nach Quelle: PSGallery (Install-Module), GitHub (Release-ZIP), UNC/LocalDir (Datei-Copy). Ohne -UpdateInfo wird Test-sqmModuleUpdate selbst aufgerufen. .PARAMETER UpdateInfo Optionales Ergebnis von Test-sqmModuleUpdate (Source/Version/Path). .PARAMETER Backup Sicherung vor Datei-Update (Standard: $true). .PARAMETER Force Update auch ohne erkannte neuere Version erzwingen. #> function Update-sqmModule { [CmdletBinding(SupportsShouldProcess = $true)] param ( [hashtable]$UpdateInfo, [System.Management.Automation.PSCredential]$Credential, [switch]$Backup = $true, [switch]$Force ) $currentModulePath = $PSScriptRoot if (-not $UpdateInfo) { $UpdateInfo = Test-sqmModuleUpdate -Credential $Credential } if (-not $UpdateInfo -and -not $Force) { Write-Host "Keine neuere Version verfuegbar." -ForegroundColor Green return } $source = if ($UpdateInfo -and $UpdateInfo.Source) { $UpdateInfo.Source } else { (Get-sqmInstallSource).Type } $verTxt = if ($UpdateInfo -and $UpdateInfo.Version) { " auf $($UpdateInfo.Version)" } else { '' } try { switch ($source) { 'PSGallery' { $scope = if ($currentModulePath -like "$env:ProgramFiles*") { 'AllUsers' } else { 'CurrentUser' } if ($PSCmdlet.ShouldProcess("sqmSQLTool$verTxt via PSGallery (Scope $scope)", "Install-Module")) { try { Install-Module -Name sqmSQLTool -Repository PSGallery -Force -AllowClobber -Scope $scope -ErrorAction Stop Write-Host "sqmSQLTool via PSGallery aktualisiert (Scope $scope)." -ForegroundColor Green Write-Warning "Bitte Session neu starten oder 'Remove-Module sqmSQLTool; Import-Module sqmSQLTool'." } catch { Write-Warning "PSGallery-Update fehlgeschlagen (Adminrechte fuer AllUsers noetig?): $($_.Exception.Message)" } } } 'GitHub' { if ($PSCmdlet.ShouldProcess("sqmSQLTool$verTxt via GitHub-Release", "Download & Update")) { $v = if ($UpdateInfo) { "$($UpdateInfo.Version)" } else { $null } Update-sqmFromGitHub -Version $v -ModulePath $currentModulePath -Backup:$Backup } } default { # UNC / LocalDir -> Datei-Copy $repo = if ($UpdateInfo -and $UpdateInfo.Path) { $UpdateInfo.Path } elseif ($script:sqmModuleConfig['InstallSourcePath']) { $script:sqmModuleConfig['InstallSourcePath'] } else { $script:sqmModuleConfig['UpdateRepository'] } if (-not $repo) { Write-Warning "Keine Update-Quelle ermittelbar (weder Install-Source noch UpdateRepository gesetzt)." return } if (-not (Test-Path -Path $repo -ErrorAction SilentlyContinue)) { Write-Warning "Quelle '$repo' nicht erreichbar." return } if ($PSCmdlet.ShouldProcess("sqmSQLTool$verTxt aus '$repo'", "Datei-Update")) { Copy-sqmModuleFiles -SourcePath $repo -ModulePath $currentModulePath -Backup:$Backup Write-Host "Modul wurde aktualisiert." -ForegroundColor Green Write-Warning "Bitte Session neu starten oder 'Remove-Module sqmSQLTool; Import-Module sqmSQLTool'." } } } } catch { Write-Error "Update fehlgeschlagen: $($_.Exception.Message)" } } # Auto-update on module import (only when AutoUpdate = $true) # === FLEXIBLE: Vollständige Fallback-Chain (PSGallery wird automat. übersprungen wenn offline) === if ($script:sqmModuleConfig['AutoUpdate']) { $noUpdate = $env:SQMSQLTOOL_SKIP_AUTO_UPDATE -eq '1' if (-not $noUpdate) { try { # Vollständige Fallback-Chain: PSGallery (wenn online) -> GitHub -> UNC # PSGallery wird automatisch übersprungen wenn kein Internet erkannt # Throttle: nur pruefen wenn der letzte Check aelter als UpdateCheckIntervalHours ist $intervalH = [int]($script:sqmModuleConfig['UpdateCheckIntervalHours']) if ($intervalH -le 0) { $intervalH = 24 } $markerDir = Join-Path $env:LOCALAPPDATA 'sqmSQLTool' $markerFile = Join-Path $markerDir 'lastUpdateCheck' $dueCheck = $true if (Test-Path $markerFile) { try { $last = [datetime]::Parse((Get-Content $markerFile -Raw -ErrorAction Stop).Trim()) if ((Get-Date) -lt $last.AddHours($intervalH)) { $dueCheck = $false } } catch { } } if ($dueCheck) { # Marker sofort schreiben (verhindert Doppel-Checks bei mehreren Importen) if (-not (Test-Path $markerDir)) { New-Item -ItemType Directory -Path $markerDir -Force | Out-Null } (Get-Date).ToString('o') | Set-Content -Path $markerFile -Force -ErrorAction SilentlyContinue # Quellenbewusst: letzte Installationsquelle zuerst, sonst Fallback-Kette $updateInfo = Test-sqmModuleUpdate if ($updateInfo) { Write-Host "`n[sqmSQLTool] Neuere Version verfuegbar: $($updateInfo.Version) (Quelle: $($updateInfo.Source))" -ForegroundColor Cyan Write-Host "[sqmSQLTool] Fuehre automatisches Update durch..." -ForegroundColor Cyan # Quellenbewusstes Update (PSGallery/GitHub/UNC/LocalDir). Import darf nie brechen. Update-sqmModule -UpdateInfo $updateInfo -Force -Backup -Confirm:$false } } } catch { Write-Verbose "Auto-update check failed: $($_.Exception.Message)" } } } # Export-ModuleMember wird NICHT aufgerufen! # Export wird ausschliesslich durch FunctionsToExport in sqmSQLTool.psd1 gesteuert. # Das verhindert die PowerShell WARNING ueber "restricted characters" (Bindestriche in Verb-Noun Namen), # weil der Check nur beim expliziten Export-ModuleMember Aufruf ausgeloest wird. # Private Funktionen (Get-sqmString, Invoke-sqmLogging etc.) bleiben privat da sie nicht # in der FunctionsToExport Liste der .psd1 stehen. |