Install.ps1
|
<#
.SYNOPSIS Installs the sqmSQLTool module into the PowerShell module path. .DESCRIPTION Copies the module to either the system-wide module path (requires Admin) or the current user's personal module path (no Admin rights needed). The default scope is determined automatically: - Running as Administrator -> AllUsers ($env:ProgramFiles\WindowsPowerShell\Modules) - Running as normal user -> CurrentUser ($HOME\Documents\WindowsPowerShell\Modules) Pass -Scope explicitly to override this behaviour. The required dependency 'dbatools' is ensured automatically in the SAME scope before the import test (installed from the PSGallery if missing) - so a fresh server without dbatools installs cleanly and AllUsers installs get dbatools system-wide too. .PARAMETER Scope Installation scope: CurrentUser — installs to $HOME\Documents\WindowsPowerShell\Modules AllUsers — installs to $env:ProgramFiles\WindowsPowerShell\Modules (requires Admin) Default: AllUsers when running as Administrator, CurrentUser otherwise. .PARAMETER Source Source directory of the module. Defaults to the script's own directory. .PARAMETER Destination Explicit destination path. Overrides -Scope when specified. .EXAMPLE .\Install.ps1 Installs for the current user — no Admin rights required. .EXAMPLE .\Install.cmd Recommended when running from a cross-domain share (handles execution policy). .EXAMPLE .\Install.ps1 -Scope AllUsers Installs system-wide — requires Admin rights. .NOTES Uses robocopy /COPY:DAT to copy the module data. Note: /COPY:DAT does NOT strip the Zone.Identifier ADS (Mark-of-the-Web) - the subsequent Unblock-File pass on all destination files is what removes it. #> param( [ValidateSet('CurrentUser', 'AllUsers')] [string]$Scope = '', # auto-detected below [string]$Source = $PSScriptRoot, [string]$Destination = '' ) # --------------------------------------------------------------------------- # 0. Scope auto-detect: Admin -> AllUsers, sonst CurrentUser # --------------------------------------------------------------------------- $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole]'Administrator') if ($Scope -eq '') { $Scope = if ($isAdmin) { 'AllUsers' } else { 'CurrentUser' } Write-Host "Auto-detected Scope: $Scope" -ForegroundColor Cyan } # --------------------------------------------------------------------------- # 1. Zielpfad bestimmen # --------------------------------------------------------------------------- if (-not $Destination) { if ($Scope -eq 'AllUsers') { $Destination = "$env:ProgramFiles\WindowsPowerShell\Modules\sqmSQLTool" } else { $docsPath = [Environment]::GetFolderPath('MyDocuments') $Destination = Join-Path $docsPath "WindowsPowerShell\Modules\sqmSQLTool" } } # --------------------------------------------------------------------------- # 2. Doppel-Installation erkennen und warnen # --------------------------------------------------------------------------- $docsPath_ = [Environment]::GetFolderPath('MyDocuments') $pathUser = Join-Path $docsPath_ "WindowsPowerShell\Modules\sqmSQLTool" $pathAllUsers = "$env:ProgramFiles\WindowsPowerShell\Modules\sqmSQLTool" $existsUser = Test-Path $pathUser $existsAll = Test-Path $pathAllUsers if ($existsUser -and $existsAll -and $Scope -eq 'AllUsers') { # Running as Admin installing AllUsers — remove the CurrentUser copy automatically Write-Host "Both installations detected. Removing CurrentUser copy..." -ForegroundColor Yellow Write-Host " $pathUser" -ForegroundColor Gray Remove-Item $pathUser -Recurse -Force Write-Host "CurrentUser installation removed." -ForegroundColor Green Write-Host "" $existsUser = $false } elseif ($existsUser -and $existsAll) { # CurrentUser install, both exist — warn, cannot auto-remove AllUsers without Admin Write-Warning "sqmSQLTool is installed in BOTH locations:" Write-Warning " CurrentUser : $pathUser" Write-Warning " AllUsers : $pathAllUsers" Write-Warning "PowerShell loads the CurrentUser version — the AllUsers copy is ignored." Write-Warning "To remove the AllUsers copy (requires Admin):" Write-Warning " Remove-Item '$pathAllUsers' -Recurse -Force" Write-Host "" } elseif ($Scope -eq 'CurrentUser' -and $existsAll) { Write-Warning "An AllUsers installation already exists at: $pathAllUsers" Write-Warning "After this install, PowerShell will load the CurrentUser version and ignore AllUsers." Write-Host "" } elseif ($Scope -eq 'AllUsers' -and $existsUser) { # Running as Admin — remove the CurrentUser copy automatically Write-Host "CurrentUser installation detected. Removing to avoid conflicts..." -ForegroundColor Yellow Write-Host " $pathUser" -ForegroundColor Gray Remove-Item $pathUser -Recurse -Force Write-Host "CurrentUser installation removed." -ForegroundColor Green Write-Host "" $existsUser = $false } # --------------------------------------------------------------------------- # 3. Scope-Hinweis und Admin-Check # --------------------------------------------------------------------------- if ($Scope -eq 'AllUsers') { if (-not $isAdmin) { Write-Warning "Scope 'AllUsers' requires Administrator rights." Write-Warning "Run Install.cmd as Administrator, or use: .\Install.ps1 (installs for current user only)" exit 1 } } else { # CurrentUser — Hinweis auf systemweite Installation Write-Host "" if ($isAdmin) { Write-Host "INFO: You are running as Administrator." -ForegroundColor Cyan Write-Host " Installing for the current user only ($env:USERNAME)." -ForegroundColor Cyan Write-Host " To install system-wide for ALL users, run:" -ForegroundColor Cyan Write-Host " Install.cmd AllUsers" -ForegroundColor White } else { Write-Host "INFO: Installing for the current user only ($env:USERNAME)." -ForegroundColor Cyan Write-Host " To install system-wide for ALL users, re-run as Administrator:" -ForegroundColor Cyan Write-Host " Right-click Install.cmd > 'Run as administrator'" -ForegroundColor White Write-Host " or: Install.cmd AllUsers (in an elevated PowerShell)" -ForegroundColor White } Write-Host "" } # --------------------------------------------------------------------------- # 4. Modul kopieren # /COPY:DAT -> Data, Attributes, Timestamps (KEIN Zone.Identifier-Strip! # das erledigt der Unblock-File-Schritt 5) # /XD .git -> exclude git directory # /XF -> exclude meta files # --------------------------------------------------------------------------- Write-Host "Installing sqmSQLTool to: $Destination" -ForegroundColor Cyan robocopy $Source $Destination /E /PURGE /NJH /NJS /NDL /COPY:DAT ` /XD .git tests bin ` /XF .gitignore README.md LICENSE ` Install.cmd Install.ps1 ` "*.TempPoint.*" "*.RestorePoint.*" "*.psproj" "*.psproj.psbuild" "*.psprojs" ` "desktop.ini" "Tester.ps1" "Test-Module*.ps1" ` "coverage.xml" "testresults.xml" # --------------------------------------------------------------------------- # 5. Zone.Identifier auf dem Ziel entfernen # --------------------------------------------------------------------------- Write-Host "Unblocking files..." -ForegroundColor Cyan Get-ChildItem -Path $Destination -Recurse -File | ForEach-Object { Unblock-File -Path $_.FullName -ErrorAction SilentlyContinue } # --------------------------------------------------------------------------- # 5b. dbatools-Abhaengigkeit im PASSENDEN Scope sicherstellen # sqmSQLTool.psd1 hat RequiredModules = @('dbatools') -> ohne dbatools # schlaegt der Import-Test (Schritt 6) fehl. Auf einem frischen Server ist # dbatools nicht vorhanden. Installation im GLEICHEN Scope wie sqmSQLTool, # sonst Scope-Mismatch: AllUsers-Modul wuerde ein nur in CurrentUser # liegendes dbatools in fremden/Admin-Sessions nicht finden. # --------------------------------------------------------------------------- $auDbatools = Join-Path $env:ProgramFiles 'WindowsPowerShell\Modules\dbatools' $cuDbatools = Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'WindowsPowerShell\Modules\dbatools' if ($Scope -eq 'AllUsers') { $dbatoolsInScope = Test-Path $auDbatools # AllUsers braucht dbatools systemweit } else { $dbatoolsInScope = (Test-Path $cuDbatools) -or (Test-Path $auDbatools) # CurrentUser: beides ok } Write-Host "Pruefe Abhaengigkeit 'dbatools' (Scope $Scope)..." -ForegroundColor Cyan if ($dbatoolsInScope) { Write-Host " dbatools im passenden Scope vorhanden." -ForegroundColor Gray } else { Write-Host " dbatools fehlt im Scope '$Scope' - installiere von der PSGallery..." -ForegroundColor Yellow try { [Net.ServicePointManager]::SecurityProtocol = ` [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope $Scope -Force -ErrorAction Stop | Out-Null } catch {} Install-Module dbatools -Scope $Scope -Force -AllowClobber -ErrorAction Stop Write-Host " dbatools installiert (-Scope $Scope)." -ForegroundColor Green } catch { Write-Warning " dbatools-Installation fehlgeschlagen: $_" Write-Warning " Bitte manuell nachholen: Install-Module dbatools -Scope $Scope -Force -AllowClobber" } } # --------------------------------------------------------------------------- # 6. Import testen # --------------------------------------------------------------------------- Write-Host "Testing module import..." -ForegroundColor Cyan $importOk = $false try { # Expliziter Pfad zur .psd1 verhindert dass eine alte Version aus PSModulePath geladen wird $psd1Path = Join-Path $Destination "sqmSQLTool.psd1" Import-Module $psd1Path -Force -WarningAction SilentlyContinue -ErrorAction Stop $version = (Get-Module sqmSQLTool).Version Write-Host "sqmSQLTool v$version successfully loaded." -ForegroundColor Green Write-Host "Scope: $Scope | Path: $Destination" -ForegroundColor Gray $importOk = $true } catch { Write-Warning "Import failed: $_" } # --------------------------------------------------------------------------- # 6a. Installationsquelle merken (fuer quellenbewusstes Auto-Update) # Install.ps1 installiert aus $Source -> Typ aus dem Pfad ableiten: # UNC-Pfad (\\...) -> 'UNC' (zusaetzlich UpdateRepository setzen), sonst 'LocalDir'. # (PSGallery-Installs laufen ueber Install-Module, nicht hier; die werden zur # Laufzeit automatisch erkannt.) # --------------------------------------------------------------------------- if ($importOk) { try { $srcType = if ($Source -like '\\*') { 'UNC' } else { 'LocalDir' } if ($srcType -eq 'UNC') { Set-sqmConfig -InstallSourceType $srcType -InstallSourcePath $Source -UpdateRepository $Source -ErrorAction Stop } else { Set-sqmConfig -InstallSourceType $srcType -InstallSourcePath $Source -ErrorAction Stop } Write-Host "Installationsquelle gemerkt: $srcType ($Source)" -ForegroundColor Gray } catch { Write-Warning "Installationsquelle konnte nicht gespeichert werden: $_" } } # --------------------------------------------------------------------------- # 6b. Windows Event Log Source registrieren (fuer Splunk-Integration) # Die Agent-Jobs (Sync/Compare) schreiben bei Fehler/Drift in das Application # Log unter der Source 'sqmSQLTool'. Das Anlegen der Source erfordert Adminrechte # und ist nur einmalig noetig. Schlaegt es fehl (CurrentUser-Install ohne Admin), # wird es ignoriert - die Jobs registrieren die Source sonst beim ersten Lauf. # --------------------------------------------------------------------------- Write-Host "Registriere Event Log Source 'sqmSQLTool'..." -ForegroundColor Cyan try { if (-not [System.Diagnostics.EventLog]::SourceExists('sqmSQLTool')) { New-EventLog -LogName Application -Source 'sqmSQLTool' -ErrorAction Stop Write-Host " Event Log Source 'sqmSQLTool' registriert." -ForegroundColor Green } else { Write-Host " Event Log Source 'sqmSQLTool' bereits vorhanden." -ForegroundColor Gray } } catch { Write-Host " Hinweis: Event Log Source konnte nicht registriert werden (keine Adminrechte?) - wird beim ersten Job-Lauf nachgeholt." -ForegroundColor Yellow } # --------------------------------------------------------------------------- # 7. FI-TS-Konfiguration automatisch setzen # Kriterium: Installation wurde von W:\ oder \\tsclient\W\ gestartet. # Setzt alle FI-TS-Standardwerte via Set-sqmConfig (persistiert in config.json). # Laeuft nur wenn der Import erfolgreich war. # --------------------------------------------------------------------------- $isFitsInstall = ($Source -like 'W:\*') -or ($Source -like '\\tsclient\W\*') if ($importOk -and $isFitsInstall) { Write-Host "" Write-Host "FI-TS-Umgebung erkannt (Quelle: $Source)" -ForegroundColor Cyan Write-Host "Setze FI-TS-Standardkonfiguration..." -ForegroundColor Cyan try { Set-sqmConfig ` -OutputPath 'C:\System\WinSrvLog\MSSQL' ` -OlaJobNameFull 'FITS-UserDatabases-FULL' ` -OlaJobNameDiff 'FITS-UserDatabases-DIFF' ` -OlaJobNameLog 'FITS-UserDatabases-LOG' ` -OlaJobNameIndexOpt 'FITS IndexOptimize - USER_DATABASES' ` -OlaJobNameIntUserDb 'FITS IntegrityCheck - USER_DATABASES' ` -OlaJobNameIntSysDb 'FITS IntegrityCheck - SYSTEM_DATABASES' ` -OlaJobNameSysDbBackup 'FITS-SystemDatabases-FULL' ` -DefaultPolicy 'New Login_Enforce Passwort Policy' ` -CheckProfile 'FiTs' ` -ErrorAction Stop Write-Host "FI-TS-Konfiguration erfolgreich gesetzt." -ForegroundColor Green Write-Host " OutputPath : C:\System\WinSrvLog\MSSQL" -ForegroundColor Gray Write-Host " OlaJobs : FITS-*" -ForegroundColor Gray Write-Host " DefaultPolicy: New Login_Enforce Passwort Policy" -ForegroundColor Gray } catch { Write-Warning "FI-TS-Konfiguration konnte nicht gesetzt werden: $_" Write-Warning "Manuell nachholen mit: Set-sqmConfig -DefaultPolicy 'New Login_Enforce Passwort Policy' ..." } } elseif ($importOk -and -not $isFitsInstall) { Write-Host "" Write-Host "Hinweis: Keine FI-TS-Umgebung erkannt." -ForegroundColor Yellow Write-Host " Job-Namen und Policy manuell setzen: Set-sqmConfig -OlaJobNameFull '...' -DefaultPolicy '...'" -ForegroundColor Gray } |