Private/Initialize/Initialize-CWAA.ps1
|
function Get-CWAARedactedValue { <# .SYNOPSIS Returns a SHA256-hashed redacted representation of a sensitive string. .DESCRIPTION Private helper that returns '[SHA256:a1b2c3d4]' for non-empty strings and '[EMPTY]' for null/empty strings. Used to log that a credential value is present without exposing the actual content. .NOTES Version: 0.1.5.0 Author: Chris Taylor Private function - not exported. #> [CmdletBinding()] Param( [AllowNull()] [AllowEmptyString()] [string]$InputString ) if ([string]::IsNullOrEmpty($InputString)) { return '[EMPTY]' } $sha256 = [System.Security.Cryptography.SHA256]::Create() $hashBytes = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($InputString)) $hashHex = -join ($hashBytes | ForEach-Object { $_.ToString('x2') }) $sha256.Dispose() return "[SHA256:$($hashHex.Substring(0, 8))]" } function Initialize-CWAA { # Guard: PowerShell 1.0 lacks $PSVersionTable entirely if (-not ($PSVersionTable)) { Write-Warning 'PS1 Detected. PowerShell Version 2.0 or higher is required.' return } if ($PSVersionTable.PSVersion.Major -lt 3) { Write-Verbose 'PS2 Detected. PowerShell Version 3.0 or higher may be required for full functionality.' } # WOW64 relaunch: When running as 32-bit PowerShell on a 64-bit OS, many registry # and file system operations target the wrong hive/path. Re-launch under native # 64-bit PowerShell to ensure consistent behavior with the Automate agent services. # Note: This relaunch works correctly in single-file mode (ConnectWiseAutomateAgent.ps1). # In module mode (Import-Module), the .psm1 emits a warning instead since relaunch # cannot re-invoke Import-Module from within a function. if ($env:PROCESSOR_ARCHITEW6432 -match '64' -and [IntPtr]::Size -ne 8) { Write-Warning '32-bit PowerShell session detected on 64-bit OS. Attempting to launch 64-Bit session to process commands.' $pshell = "${env:WINDIR}\sysnative\windowspowershell\v1.0\powershell.exe" if (!(Test-Path -Path $pshell)) { # sysnative virtual folder is unavailable (e.g. older OS or non-interactive context). # Fall back to the real System32 path after disabling WOW64 file system redirection # so the 64-bit powershell.exe is accessible instead of the 32-bit redirected copy. Write-Warning 'SYSNATIVE PATH REDIRECTION IS NOT AVAILABLE. Attempting to access 64-bit PowerShell directly.' $pshell = "${env:WINDIR}\System32\WindowsPowershell\v1.0\powershell.exe" $FSRedirection = $True Add-Type -Debug:$False -Name Wow64 -Namespace 'Kernel32' -MemberDefinition @' [DllImport("kernel32.dll", SetLastError=true)] public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr); [DllImport("kernel32.dll", SetLastError=true)] public static extern bool Wow64RevertWow64FsRedirection(ref IntPtr ptr); '@ [ref]$ptr = New-Object System.IntPtr $Null = [Kernel32.Wow64]::Wow64DisableWow64FsRedirection($ptr) } # Re-invoke the original command/script under the 64-bit host if ($myInvocation.Line) { &"$pshell" -NonInteractive -NoProfile $myInvocation.Line } elseif ($myInvocation.InvocationName) { &"$pshell" -NonInteractive -NoProfile -File "$($myInvocation.InvocationName)" $args } else { &"$pshell" -NonInteractive -NoProfile $myInvocation.MyCommand } $ExitResult = $LASTEXITCODE # Restore file system redirection if it was disabled if ($FSRedirection -eq $True) { [ref]$defaultptr = New-Object System.IntPtr $Null = [Kernel32.Wow64]::Wow64RevertWow64FsRedirection($defaultptr) } Write-Warning 'Exiting 64-bit session. Module will only remain loaded in native 64-bit PowerShell environment.' Exit $ExitResult } # Module-level constants — centralized to avoid duplication across functions. # These are cheap to create with no side effects, so they run at module load. $Script:CWAARegistryRoot = 'HKLM:\SOFTWARE\LabTech\Service' $Script:CWAARegistrySettings = 'HKLM:\SOFTWARE\LabTech\Service\Settings' $Script:CWAAInstallPath = "${env:windir}\LTSVC" $Script:CWAAInstallerTempPath = "${env:windir}\Temp\LabTech" $Script:CWAAServiceNames = @('LTService', 'LTSvcMon') # Server URL validation regex breakdown: # ^(https?://)? — optional http:// or https:// scheme # (([12]?[0-9]{1,2}\.){3}[12]?[0-9]{1,2} — IPv4 address (0.0.0.0 - 299.299.299.299) # | — OR # [a-z0-9][a-z0-9_-]*(\.[a-z0-9][a-z0-9_-]*)*) — hostname with optional subdomains # $ — end of string, no trailing path/query $Script:CWAAServerValidationRegex = '^(https?://)?(([12]?[0-9]{1,2}\.){3}[12]?[0-9]{1,2}|[a-z0-9][a-z0-9_-]*(\.[a-z0-9][a-z0-9_-]*)*)$' # Registry paths for Add/Remove Programs operations (shared by Hide, Show, Rename functions) $Script:CWAAInstallerProductKeys = @( 'HKLM:\SOFTWARE\Classes\Installer\Products\C4D064F3712D4B64086B5BDE05DBC75F', 'HKLM:\SOFTWARE\Classes\Installer\Products\D1003A85576B76D45A1AF09A0FC87FAC' ) $Script:CWAAUninstallKeys = @( 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{58A3001D-B675-4D67-A5A1-0FA9F08CF7CA}', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{58A3001D-B675-4D67-A5A1-0FA9F08CF7CA}', 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{3F460D4C-D217-46B4-80B6-B5ED50BD7CF5}', 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{3F460D4C-D217-46B4-80B6-B5ED50BD7CF5}' ) $Script:CWAARegistryBackup = 'HKLM:\SOFTWARE\LabTechBackup\Service' # Installer artifact paths for cleanup (used by Clear-CWAAInstallerArtifacts) $Script:CWAAInstallerArtifactPaths = @( "${env:windir}\Temp\_LTUpdate", "${env:windir}\Temp\Agent_Uninstall.exe", "${env:windir}\Temp\RemoteAgent.msi", "${env:windir}\Temp\Uninstall.exe", "${env:windir}\Temp\Uninstall.exe.config" ) # Installer process names for cleanup (used by Clear-CWAAInstallerArtifacts) $Script:CWAAInstallerProcessNames = @('Agent_Uninstall', 'Uninstall', 'LTUpdate') # Windows Event Log settings (used by Write-CWAAEventLog) $Script:CWAAEventLogSource = 'ConnectWiseAutomateAgent' $Script:CWAAEventLogName = 'Application' # Service credential storage â€" populated on-demand by Get-CWAAProxy $Script:LTServiceKeys = [PSCustomObject]@{ ServerPasswordString = '' PasswordString = '' } # Proxy configuration — populated on-demand by Initialize-CWAANetworking $Script:LTProxy = [PSCustomObject]@{ ProxyServerURL = '' ProxyUsername = '' ProxyPassword = '' Enabled = $False } # Networking subsystem deferred flags. Initialize-CWAANetworking sets these to $True # after registration/initialization. This keeps module import fast and avoids # irreversible global session side effects until networking is actually needed. $Script:CWAANetworkInitialized = $False $Script:CWAACertCallbackRegistered = $False } |