diff --git a/src/svsmsp.install.ps1 b/src/svsmsp.install.ps1 index fce1ea0..e73cc7b 100644 --- a/src/svsmsp.install.ps1 +++ b/src/svsmsp.install.ps1 @@ -1,3 +1,315 @@ + +function Install-SVSMSP { + [CmdletBinding()] + param ( + [switch] $Cleanup, + [switch] $InstallToolkit, + + [Parameter(Mandatory = $false)] + [array] $AllModules = @(@{ ModuleName = "SVS_Toolkit" }, @{ ModuleName = "SVSMSP" }), + + [Parameter(Mandatory = $false)] + [array] $AllRepositories = @(@{ RepoName = "SVS_Repo" }, @{ RepoName = "SVS_Toolkit" }), + + [Parameter(Mandatory = $false)] + [string] $NewModuleName = "SVSMSP", + + [Parameter(Mandatory = $false)] + [string] $NewRepositoryName = "SVS_Repo", + + # Legacy PSGet v2 URL (works with Find-Package/Install-Package; PSGet v2 repo registration may fail on some machines) + [Parameter(Mandatory = $false)] + [string] $NewRepositoryURL = "https://proget.svstools.ca/nuget/SVS_Repo/", + + # PSResourceGet V3 service index URL (this is what made your install work) + [Parameter(Mandatory = $false)] + [string] $NewRepositoryV3Url = "https://proget.svstools.ca/nuget/SVS_Repo/v3/index.json" + ) + + function Ensure-Tls12 { + try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch { } + } + + function Ensure-NuGetProvider { + Ensure-Tls12 + try { + if (-not (Get-PackageProvider -ListAvailable -Name NuGet -ErrorAction SilentlyContinue)) { + Install-PackageProvider -Name NuGet -Force -Scope AllUsers | Out-Null + } + } catch { + Write-LogHybrid "Failed to ensure NuGet provider: $($_.Exception.Message)" "Warning" "SVSModule" -LogToEvent + } + } + + function Ensure-PSResourceGet { + Ensure-NuGetProvider + try { + if (-not (Get-Module Microsoft.PowerShell.PSResourceGet -ListAvailable -ErrorAction SilentlyContinue)) { + Install-Module Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force -AllowClobber -ErrorAction Stop + } + Import-Module Microsoft.PowerShell.PSResourceGet -Force -ErrorAction Stop + return $true + } catch { + Write-LogHybrid "PSResourceGet not available: $($_.Exception.Message)" "Warning" "SVSModule" -LogToEvent + return $false + } + } + + function Get-InstallStrategy { + # 1) PSResourceGet if present/usable + if (Ensure-PSResourceGet) { + if (Get-Command Register-PSResourceRepository -ErrorAction SilentlyContinue) { return "PSResourceGet" } + } + + # 2) PowerShellGet v2 cmdlets if present + if (Get-Command Register-PSRepository -ErrorAction SilentlyContinue) { return "PowerShellGetV2" } + + # 3) NuGet provider fallback + return "NuGetProvider" + } + + function Register-Repo_PSResourceGet { + Write-LogHybrid "Registering PSResourceGet repo $NewRepositoryName…" "Info" "SVSModule" -LogToEvent + if (-not (Get-PSResourceRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) { + Register-PSResourceRepository -Name $NewRepositoryName -Uri $NewRepositoryV3Url -Trusted -ErrorAction Stop + } + } + + function Install-Module_PSResourceGet { + Write-LogHybrid "Installing module $NewModuleName via PSResourceGet…" "Info" "SVSModule" -LogToEvent + Install-PSResource -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Reinstall -ErrorAction Stop + Import-Module $NewModuleName -Force -ErrorAction SilentlyContinue + } + + function Register-Repo_PowerShellGetV2 { + Write-LogHybrid "Registering PSRepository $NewRepositoryName…" "Info" "SVSModule" -LogToEvent + if (-not (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue)) { + Register-PSRepository -Name $NewRepositoryName -SourceLocation $NewRepositoryURL -InstallationPolicy Trusted -ErrorAction Stop + } + } + + function Install-Module_PowerShellGetV2 { + Write-LogHybrid "Installing module $NewModuleName via PowerShellGet…" "Info" "SVSModule" -LogToEvent + Install-Module -Name $NewModuleName -Repository $NewRepositoryName -Scope AllUsers -Force -ErrorAction Stop + Import-Module $NewModuleName -Force -ErrorAction SilentlyContinue + } + + function Register-Repo_NuGetProvider { + Ensure-NuGetProvider + Write-LogHybrid "Registering PackageSource $NewRepositoryName…" "Info" "SVSModule" -LogToEvent + try { + Register-PackageSource -Name $NewRepositoryName -ProviderName NuGet -Location $NewRepositoryURL -Trusted -Force -ErrorAction Stop | Out-Null + } catch { + Write-LogHybrid "Failed to register PackageSource '$NewRepositoryName': $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + throw + } + } + + function Install-Module_NuGetProvider { + Write-LogHybrid "Installing package $NewModuleName via NuGet provider…" "Info" "SVSModule" -LogToEvent + try { + Install-Package -Name $NewModuleName -Source $NewRepositoryName -Force -ErrorAction Stop | Out-Null + } catch { + Write-LogHybrid "Failed Install-Package '$NewModuleName': $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + throw + } + + # Optional: promote .nupkg to Modules path so Import-Module works like a normal module + try { + $pkg = Get-Package -Name $NewModuleName -ProviderName NuGet -ErrorAction Stop | Select-Object -First 1 + $nupkg = $pkg.Source + if (-not (Test-Path $nupkg)) { return } + + $stage = Join-Path $env:TEMP ("{0}_{1}" -f $NewModuleName, $pkg.Version) + Remove-Item -Recurse -Force $stage -ErrorAction SilentlyContinue + Expand-Archive -Path $nupkg -DestinationPath $stage -Force + + $psd1 = Get-ChildItem -Path $stage -Recurse -Filter ($NewModuleName + ".psd1") -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $psd1) { return } + + $moduleRoot = Split-Path $psd1.FullName -Parent + $dest = Join-Path $env:ProgramFiles ("WindowsPowerShell\Modules\{0}\{1}" -f $NewModuleName, $pkg.Version) + New-Item -ItemType Directory -Path $dest -Force | Out-Null + Copy-Item -Path (Join-Path $moduleRoot '*') -Destination $dest -Recurse -Force + + Import-Module $NewModuleName -Force -ErrorAction SilentlyContinue + } catch { + Write-LogHybrid "NuGet promotion step skipped/failed: $($_.Exception.Message)" "Warning" "SVSModule" -LogToEvent + } + } + + function Start-Cleanup { + Write-LogHybrid "Cleanup mode enabled. Starting cleanup..." "Info" "SVSModule" + + # Uninstall module using whichever tooling exists + try { + if (Get-Command Uninstall-PSResource -ErrorAction SilentlyContinue) { + Uninstall-PSResource -Name $NewModuleName -Scope AllUsers -ErrorAction SilentlyContinue + } + } catch { } + + try { + Uninstall-Module -Name $NewModuleName -AllVersions -Force -ErrorAction SilentlyContinue + } catch { } + + try { + Uninstall-Package -Name $NewModuleName -ProviderName NuGet -AllVersions -Force -ErrorAction SilentlyContinue | Out-Null + } catch { } + + if (Get-PSRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue) { + try { + Unregister-PSRepository -Name $NewRepositoryName -ErrorAction Stop + Write-LogHybrid "$NewRepositoryName repository unregistered (PSGet v2)." "Success" "SVSModule" -LogToEvent + } catch { + Write-LogHybrid "Failed to unregister PSRepository $NewRepositoryName: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + } + } + + if (Get-Command Get-PSResourceRepository -ErrorAction SilentlyContinue) { + if (Get-PSResourceRepository -Name $NewRepositoryName -ErrorAction SilentlyContinue) { + try { + Unregister-PSResourceRepository -Name $NewRepositoryName -ErrorAction Stop + Write-LogHybrid "$NewRepositoryName repository unregistered (PSResourceGet)." "Success" "SVSModule" -LogToEvent + } catch { + Write-LogHybrid "Failed to unregister PSResource repo $NewRepositoryName: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + } + } + } + + if (Get-PackageSource -Name $NewRepositoryName -ErrorAction SilentlyContinue) { + try { + Unregister-PackageSource -Name $NewRepositoryName -ErrorAction SilentlyContinue | Out-Null + Write-LogHybrid "$NewRepositoryName package source unregistered (NuGet provider)." "Success" "SVSModule" -LogToEvent + } catch { } + } + + if (Get-Module -Name $NewModuleName) { + try { + Remove-Module $NewModuleName -Force -ErrorAction Stop + Write-LogHybrid "$NewModuleName module removed from current session." "Success" "SVSModule" -LogToEvent + } catch { + Write-LogHybrid "Failed to remove $NewModuleName from session: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + } + } + + $cscePath = 'C:\CSCE' + if (Test-Path $cscePath) { + try { + Remove-Item -Path $cscePath -Recurse -Force + Write-LogHybrid "Deleted '$cscePath' contents." "Success" "SVSModule" -LogToEvent + } catch { + Write-LogHybrid "Failed to delete '$cscePath': $($_.Exception.Message)" "Warning" "SVSModule" -LogToEvent + } + } + } + + function Remove-SVSDeploymentRegKey { + $regKey = 'HKLM:\Software\SVS' + try { + if (Test-Path $regKey) { + Remove-Item -Path $regKey -Recurse -Force + Write-LogHybrid "Registry key '$regKey' deleted successfully." "Success" "SVSModule" -LogToEvent + } else { + Write-LogHybrid "Registry key '$regKey' not found; nothing to delete." "Info" "SVSModule" -LogToEvent + } + } catch { + Write-LogHybrid "Failed to delete registry key '$regKey': $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + } + } + + function Repair-SVSMspEventLogBinding { + param( + [string]$EventSource = "SVSMSP_Module", + [string]$TargetLog = "SVSMSP Events" + ) + + Write-LogHybrid "Checking Event Log binding for source '$EventSource'..." Info SVSModule -LogToEvent + + try { + if (-not [System.Diagnostics.EventLog]::SourceExists($EventSource)) { + Write-LogHybrid "Event source '$EventSource' not found. Nothing to repair." Info SVSModule -LogToEvent + return + } + $currentLog = [System.Diagnostics.EventLog]::LogNameFromSourceName($EventSource, '.') + } catch { + Write-LogHybrid "Failed to query Event Log binding for '$EventSource': $($_.Exception.Message)" Warning SVSModule -LogToEvent + return + } + + if (-not $currentLog) { + Write-LogHybrid "Could not determine current log for event source '$EventSource'. Skipping repair." Warning SVSModule -LogToEvent + return + } + + if ($currentLog -eq $TargetLog) { + Write-LogHybrid "Event source '$EventSource' already bound to '$TargetLog'." Info SVSModule -LogToEvent + return + } + + Write-LogHybrid "Rebinding event source '$EventSource' from '$currentLog' to '$TargetLog'..." Warning SVSModule -LogToEvent + + try { + [System.Diagnostics.EventLog]::DeleteEventSource($EventSource) + New-EventLog -LogName $TargetLog -Source $EventSource -ErrorAction Stop + Write-LogHybrid "Event source '$EventSource' rebound to '$TargetLog'." Success SVSModule -LogToEvent + } catch { + Write-LogHybrid "Failed to rebind event source '$EventSource' to log '$TargetLog': $($_.Exception.Message)" Error SVSModule -LogToEvent + } + } + + function Start-ToolkitInstallation { + Start-Cleanup + + $strategy = Get-InstallStrategy + Write-LogHybrid "Selected install strategy: $strategy" "Info" "SVSModule" -LogToEvent + + try { + switch ($strategy) { + "PSResourceGet" { + Register-Repo_PSResourceGet + Install-Module_PSResourceGet + } + "PowerShellGetV2" { + Ensure-NuGetProvider + Register-Repo_PowerShellGetV2 + Install-Module_PowerShellGetV2 + } + default { + Register-Repo_NuGetProvider + Install-Module_NuGetProvider + } + } + } catch { + Write-LogHybrid "Installation failed using $strategy: $($_.Exception.Message)" "Error" "SVSModule" -LogToEvent + throw + } + + Repair-SVSMspEventLogBinding -EventSource "SVSMSP_Module" -TargetLog "SVSMSP Events" + Write-LogHybrid "Toolkit installation completed." "Success" "SVSModule" -LogToEvent + } + + Write-LogHybrid "Install-SVSMSP called" "Info" "SVSModule" -LogToEvent + + if ($Cleanup) { + Start-Cleanup + Remove-SVSDeploymentRegKey + return + } + + if ($InstallToolkit) { Start-ToolkitInstallation; return } + + Start-ToolkitInstallation +} + + + + +<# Function as is before we attempted to have it attempt to use + +Prefer PSResourceGet when it exists (and your ProGet v3 index works). +Fallback to PowerShellGet v2 (Register-PSRepository / Install-Module) if PSResourceGet isn’t available. +Last-resort fallback to your proven NuGet provider path (Register-PackageSource / Install-Package + optional “promote”) for the cursed endpoints where PSGet v2 explodes. + function Install-SVSMSP { param ( [switch] $Cleanup, @@ -144,3 +456,4 @@ function Install-SVSMSP { Start-ToolkitInstallation } +#> \ No newline at end of file