refactor(packaging/windows): installer script execution (#4675)
This commit is contained in:
parent
bf574afdfd
commit
e2652fa52b
4 changed files with 705 additions and 21 deletions
|
|
@ -28,6 +28,9 @@ install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio)
|
||||||
install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT application)
|
install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT application)
|
||||||
|
|
||||||
# Mandatory scripts
|
# Mandatory scripts
|
||||||
|
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/sunshine-setup.ps1"
|
||||||
|
DESTINATION "scripts"
|
||||||
|
COMPONENT assets)
|
||||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/"
|
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/"
|
||||||
DESTINATION "scripts"
|
DESTINATION "scripts"
|
||||||
COMPONENT assets)
|
COMPONENT assets)
|
||||||
|
|
|
||||||
|
|
@ -4,35 +4,36 @@
|
||||||
set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}")
|
set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}")
|
||||||
|
|
||||||
# Extra install commands
|
# Extra install commands
|
||||||
# Restores permissions on the install directory
|
# Runs the main setup script which handles all installation tasks
|
||||||
# Migrates config files from the root into the new config folder
|
|
||||||
# Install service
|
|
||||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
|
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
|
||||||
"${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
|
"${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
|
||||||
IfSilent +2 0
|
; Enable detailed logging
|
||||||
ExecShell 'open' 'https://docs.lizardbyte.dev/projects/sunshine'
|
LogSet on
|
||||||
nsExec::ExecToLog 'icacls \\\"$INSTDIR\\\" /reset'
|
IfSilent +3 0
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" add'
|
nsExec::ExecToLog \
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"'
|
'powershell -ExecutionPolicy Bypass \
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"'
|
-File \\\"$INSTDIR\\\\scripts\\\\sunshine-setup.ps1\\\" -Action install'
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"'
|
Goto +2
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\autostart-service.bat\\\"'
|
nsExec::ExecToLog \
|
||||||
NoController:
|
'powershell -ExecutionPolicy Bypass \
|
||||||
|
-File \\\"$INSTDIR\\\\scripts\\\\sunshine-setup.ps1\\\" -Action install -Silent'
|
||||||
|
install_done:
|
||||||
")
|
")
|
||||||
|
|
||||||
# Extra uninstall commands
|
# Extra uninstall commands
|
||||||
# Uninstall service
|
# Runs the main setup script which handles all uninstallation tasks
|
||||||
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
|
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
|
||||||
"${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
|
"${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\delete-firewall-rule.bat\\\"'
|
; Enable detailed logging
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-service.bat\\\"'
|
LogSet on
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe\\\" --restore-nvprefs-undo'
|
nsExec::ExecToLog \
|
||||||
|
'powershell -ExecutionPolicy Bypass \
|
||||||
|
-File \\\"$INSTDIR\\\\scripts\\\\sunshine-setup.ps1\\\" -Action uninstall'
|
||||||
MessageBox MB_YESNO|MB_ICONQUESTION \
|
MessageBox MB_YESNO|MB_ICONQUESTION \
|
||||||
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \
|
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \
|
||||||
/SD IDNO IDNO NoDelete
|
/SD IDNO IDNO no_delete
|
||||||
RMDir /r \\\"$INSTDIR\\\"; skipped if no
|
RMDir /r \\\"$INSTDIR\\\"; skipped if no
|
||||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" remove'
|
no_delete:
|
||||||
NoDelete:
|
|
||||||
")
|
")
|
||||||
|
|
||||||
# Adding an option for the start menu
|
# Adding an option for the start menu
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,12 @@ brew uninstall sunshine
|
||||||
1. Download and install
|
1. Download and install
|
||||||
[Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe)
|
[Sunshine-Windows-AMD64-installer.exe](https://github.com/LizardByte/Sunshine/releases/latest/download/Sunshine-Windows-AMD64-installer.exe)
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Installer logs can be found in the following locations.<br>
|
||||||
|
> | File | log paths |
|
||||||
|
> | ---- | --------- |
|
||||||
|
> | .exe | `%%PROGRAMFILES%/Sunshine/install.log`<br>`%%TEMP%/Sunshine/logs/install/` |
|
||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> You should carefully select or unselect the options you want to install. Do not blindly install or
|
> You should carefully select or unselect the options you want to install. Do not blindly install or
|
||||||
> enable features.
|
> enable features.
|
||||||
|
|
|
||||||
674
src_assets/windows/misc/sunshine-setup.ps1
Normal file
674
src_assets/windows/misc/sunshine-setup.ps1
Normal file
|
|
@ -0,0 +1,674 @@
|
||||||
|
# Sunshine Setup Script
|
||||||
|
# This script orchestrates the installation and uninstallation of Sunshine
|
||||||
|
# Usage: sunshine-setup.ps1 -Action [install|uninstall] [-Silent]
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet(
|
||||||
|
"install",
|
||||||
|
"uninstall"
|
||||||
|
)]
|
||||||
|
[string]$Action,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]$Silent
|
||||||
|
)
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
$DocsUrl = "https://docs.lizardbyte.dev/projects/sunshine"
|
||||||
|
|
||||||
|
# Set preference variables for output streams
|
||||||
|
$InformationPreference = 'Continue'
|
||||||
|
|
||||||
|
# Function to write output to both console (with color/stream) and log file (without color)
|
||||||
|
function Write-LogMessage {
|
||||||
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '',
|
||||||
|
Justification='Write-Host is required for colored output')]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[AllowEmptyString()]
|
||||||
|
[string]$Message,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet(
|
||||||
|
'Debug',
|
||||||
|
'Error',
|
||||||
|
'Information',
|
||||||
|
'Step',
|
||||||
|
'Success',
|
||||||
|
'Verbose',
|
||||||
|
'Warning'
|
||||||
|
)]
|
||||||
|
[string]$Level = 'Information',
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet(
|
||||||
|
'Black',
|
||||||
|
'Blue',
|
||||||
|
'Cyan',
|
||||||
|
'DarkGray',
|
||||||
|
'Gray',
|
||||||
|
'Green',
|
||||||
|
'Magenta',
|
||||||
|
'Red',
|
||||||
|
'White',
|
||||||
|
'Yellow'
|
||||||
|
)]
|
||||||
|
[string]$Color = $null,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]$NoTimestamp,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]$NoLogFile
|
||||||
|
)
|
||||||
|
|
||||||
|
# Map levels to colors and output streams
|
||||||
|
$levelConfig = @{
|
||||||
|
'Debug' = @{ DefaultColor = 'DarkGray'; Stream = 'Debug'; Emoji = ''; LogLevel = 'DEBUG' }
|
||||||
|
'Error' = @{ DefaultColor = 'Red'; Stream = 'Error'; Emoji = '✗'; LogLevel = 'ERROR' }
|
||||||
|
'Information' = @{ DefaultColor = $null; Stream = 'Host'; Emoji = ''; LogLevel = 'INFO' }
|
||||||
|
'Step' = @{ DefaultColor = 'Cyan'; Stream = 'Host'; Emoji = '==>'; LogLevel = 'INFO' }
|
||||||
|
'Success' = @{ DefaultColor = 'Green'; Stream = 'Host'; Emoji = '✓'; LogLevel = 'INFO' }
|
||||||
|
'Verbose' = @{ DefaultColor = 'DarkGray'; Stream = 'Verbose'; Emoji = ''; LogLevel = 'VERBOSE' }
|
||||||
|
'Warning' = @{ DefaultColor = 'Yellow'; Stream = 'Warning'; Emoji = '⚠'; LogLevel = 'WARN' }
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = $levelConfig[$Level]
|
||||||
|
|
||||||
|
# Use custom color if specified, otherwise use default color for the level
|
||||||
|
$displayColor = if ($Color) { $Color } else { $config.DefaultColor }
|
||||||
|
|
||||||
|
# Write to appropriate output stream with color
|
||||||
|
switch ($config.Stream) {
|
||||||
|
'Debug' {
|
||||||
|
Write-Debug $Message
|
||||||
|
}
|
||||||
|
'Error' {
|
||||||
|
Write-Error $Message
|
||||||
|
}
|
||||||
|
'Host' {
|
||||||
|
if ($null -ne $displayColor) {
|
||||||
|
Write-Host "$($config.Emoji) $Message" -ForegroundColor $displayColor
|
||||||
|
} else {
|
||||||
|
Write-Host "$($config.Emoji) $Message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'Information' {
|
||||||
|
Write-Information $Message
|
||||||
|
}
|
||||||
|
'Verbose' {
|
||||||
|
Write-Verbose $Message
|
||||||
|
}
|
||||||
|
'Warning' {
|
||||||
|
Write-Warning $Message
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Write-Information $Message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write to log file without color codes (only if LogPath exists and not disabled)
|
||||||
|
if ($script:LogPath -and -not $NoLogFile) {
|
||||||
|
try {
|
||||||
|
# Format log entry with timestamp and level
|
||||||
|
if ($NoTimestamp) {
|
||||||
|
$logEntry = $Message
|
||||||
|
} else {
|
||||||
|
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
|
||||||
|
$logEntry = "[$timestamp] [$($config.LogLevel)] $Message"
|
||||||
|
}
|
||||||
|
|
||||||
|
$logEntry | Out-File `
|
||||||
|
-FilePath $script:LogPath `
|
||||||
|
-Append `
|
||||||
|
-Encoding UTF8
|
||||||
|
} catch {
|
||||||
|
# Avoid infinite recursion - use Write-Verbose directly
|
||||||
|
Write-Verbose "Could not write to log file: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print a separator bar
|
||||||
|
function Write-Bar {
|
||||||
|
param(
|
||||||
|
[string]$Level = 'Information',
|
||||||
|
[int]$Length = 63,
|
||||||
|
[string]$Color = $null,
|
||||||
|
[switch]$NoTimestamp
|
||||||
|
)
|
||||||
|
$bar = "=" * $Length
|
||||||
|
if ($Color) {
|
||||||
|
Write-LogMessage -Message $bar -Level $Level -Color $Color -NoTimestamp:$NoTimestamp
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message $bar -Level $Level -NoTimestamp:$NoTimestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print text framed by bars
|
||||||
|
function Write-FramedText {
|
||||||
|
param(
|
||||||
|
[string]$Message,
|
||||||
|
[string]$Level = 'Information',
|
||||||
|
[int]$BarLength = 63,
|
||||||
|
[string]$Color = $null,
|
||||||
|
[switch]$NoTimestamp,
|
||||||
|
[switch]$NoCenter
|
||||||
|
)
|
||||||
|
|
||||||
|
# Center the message if NoCenter is not specified
|
||||||
|
$displayMessage = $Message
|
||||||
|
if (-not $NoCenter) {
|
||||||
|
$messageLength = $Message.Trim().Length
|
||||||
|
|
||||||
|
if ($messageLength -lt $BarLength) {
|
||||||
|
$totalPadding = $BarLength - $messageLength
|
||||||
|
$leftPadding = [Math]::Floor($totalPadding / 2)
|
||||||
|
$displayMessage = (' ' * $leftPadding) + $Message.Trim()
|
||||||
|
} else {
|
||||||
|
$displayMessage = $Message.Trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Color) {
|
||||||
|
Write-Bar -Level $Level -Length $BarLength -Color $Color -NoTimestamp:$NoTimestamp
|
||||||
|
Write-LogMessage -Message $displayMessage -Level $Level -Color $Color -NoTimestamp:$NoTimestamp
|
||||||
|
Write-Bar -Level $Level -Length $BarLength -Color $Color -NoTimestamp:$NoTimestamp
|
||||||
|
} else {
|
||||||
|
Write-Bar -Level $Level -Length $BarLength -NoTimestamp:$NoTimestamp
|
||||||
|
Write-LogMessage -Message $displayMessage -Level $Level -NoTimestamp:$NoTimestamp
|
||||||
|
Write-Bar -Level $Level -Length $BarLength -NoTimestamp:$NoTimestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to write to log file (helper function)
|
||||||
|
function Write-LogFile {
|
||||||
|
param(
|
||||||
|
[string[]]$Lines
|
||||||
|
)
|
||||||
|
if ($script:LogPath) {
|
||||||
|
try {
|
||||||
|
foreach ($line in $Lines) {
|
||||||
|
$line | Out-File `
|
||||||
|
-FilePath $script:LogPath `
|
||||||
|
-Append `
|
||||||
|
-Encoding UTF8
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Warning "Failed to write to log file: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# If Action is not provided, prompt the user
|
||||||
|
if (-not $Action) {
|
||||||
|
Write-Information ""
|
||||||
|
Write-FramedText -Message "🔅 Sunshine Setup Script" -Level "Information" -Color "Cyan"
|
||||||
|
Write-Information ""
|
||||||
|
Write-LogMessage -Message "Please select an action:" -Level "Information" -Color "Yellow"
|
||||||
|
Write-LogMessage -Message " 1. Install Sunshine" -Level "Information" -Color "Green"
|
||||||
|
Write-LogMessage -Message " 2. Uninstall Sunshine" -Level "Information" -Color "Red"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
$validChoice = $false
|
||||||
|
while (-not $validChoice) {
|
||||||
|
$choice = Read-Host "Enter your choice (1 or 2)"
|
||||||
|
|
||||||
|
switch ($choice) {
|
||||||
|
"1" {
|
||||||
|
$Action = "install"
|
||||||
|
$validChoice = $true
|
||||||
|
}
|
||||||
|
"2" {
|
||||||
|
$Action = "uninstall"
|
||||||
|
$validChoice = $true
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Write-Warning "Invalid choice. Please select 1 or 2."
|
||||||
|
Write-Information ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write-Information ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if running as administrator, if not, relaunch with elevation
|
||||||
|
$currentPrincipal = New-Object `
|
||||||
|
Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||||
|
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
|
||||||
|
if (-not $isAdmin) {
|
||||||
|
Write-Warning "This script requires administrator privileges. Relaunching with elevation..."
|
||||||
|
|
||||||
|
# Build the argument list for the elevated process
|
||||||
|
$arguments = "-ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`" -Action $Action"
|
||||||
|
if ($Silent) {
|
||||||
|
$arguments += " -Silent"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Relaunch the script with elevation
|
||||||
|
Start-Process powershell.exe -Verb RunAs -ArgumentList $arguments -Wait
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to elevate privileges: $($_.Exception.Message)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the script directory and root directory
|
||||||
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$RootDir = Split-Path -Parent $ScriptDir
|
||||||
|
|
||||||
|
# Set up transcript logging
|
||||||
|
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
||||||
|
$logDir = Join-Path $env:TEMP "Sunshine\logs\$Action"
|
||||||
|
$LogPath = Join-Path $logDir "${timestamp}.log"
|
||||||
|
|
||||||
|
# Ensure the log directory exists
|
||||||
|
if (-not (Test-Path $logDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store LogPath in script scope for logging functions
|
||||||
|
$script:LogPath = $LogPath
|
||||||
|
|
||||||
|
# Function to execute a batch script if it exists
|
||||||
|
function Invoke-ScriptIfExist {
|
||||||
|
param(
|
||||||
|
[string]$ScriptPath,
|
||||||
|
[string]$Arguments = "",
|
||||||
|
[string]$Description = "",
|
||||||
|
[string]$Emoji = "🔧"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Description) {
|
||||||
|
Write-LogMessage -Message "$Emoji $Description" -Level "Step"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $ScriptPath) {
|
||||||
|
Write-LogMessage -Message "Executing: $ScriptPath $Arguments" -Level "Information"
|
||||||
|
|
||||||
|
# Capture output to suppress it from console but log it
|
||||||
|
$stdoutFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
$stderrFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($Arguments -ne "") {
|
||||||
|
$process = Start-Process `
|
||||||
|
-FilePath $ScriptPath `
|
||||||
|
-ArgumentList $Arguments `
|
||||||
|
-Wait `
|
||||||
|
-PassThru `
|
||||||
|
-NoNewWindow `
|
||||||
|
-RedirectStandardOutput $stdoutFile `
|
||||||
|
-RedirectStandardError $stderrFile
|
||||||
|
} else {
|
||||||
|
$process = Start-Process `
|
||||||
|
-FilePath $ScriptPath `
|
||||||
|
-Wait `
|
||||||
|
-PassThru `
|
||||||
|
-NoNewWindow `
|
||||||
|
-RedirectStandardOutput $stdoutFile `
|
||||||
|
-RedirectStandardError $stderrFile
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log and display the output
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
$output = Get-Content $stdoutFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($output) {
|
||||||
|
# Display output with indentation
|
||||||
|
$output -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Information" -Color "DarkGray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
$errors = Get-Content $stderrFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($errors) {
|
||||||
|
# Display errors with indentation
|
||||||
|
$errors -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($process.ExitCode -ne 0) {
|
||||||
|
Write-LogMessage -Message " ⚠ Script exited with code $($process.ExitCode): $ScriptPath" -Level "Warning"
|
||||||
|
return $process.ExitCode
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message " ✓ Done" -Level "Success"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
# Clean up temp files
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message " ⓘ Skipped (script not found)" -Level "Information" -Color "DarkGray"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to execute sunshine.exe with arguments if it exists
|
||||||
|
function Invoke-SunshineIfExist {
|
||||||
|
param(
|
||||||
|
[string]$Arguments,
|
||||||
|
[string]$Description = "",
|
||||||
|
[string]$Emoji = "🔧"
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Description) {
|
||||||
|
Write-LogMessage -Message "$Emoji $Description" -Level "Step"
|
||||||
|
}
|
||||||
|
|
||||||
|
$SunshinePath = Join-Path $RootDir "sunshine.exe"
|
||||||
|
|
||||||
|
if (Test-Path $SunshinePath) {
|
||||||
|
Write-LogMessage -Message "Executing: $SunshinePath $Arguments" -Level "Information"
|
||||||
|
|
||||||
|
# Capture output to suppress it from console but log it
|
||||||
|
$stdoutFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
$stderrFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
|
||||||
|
try {
|
||||||
|
$process = Start-Process `
|
||||||
|
-FilePath $SunshinePath `
|
||||||
|
-ArgumentList $Arguments `
|
||||||
|
-Wait `
|
||||||
|
-PassThru `
|
||||||
|
-NoNewWindow `
|
||||||
|
-RedirectStandardOutput $stdoutFile `
|
||||||
|
-RedirectStandardError $stderrFile
|
||||||
|
|
||||||
|
# Log and display the output
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
$output = Get-Content $stdoutFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($output) {
|
||||||
|
# Display output with indentation
|
||||||
|
$output -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Information" -Color "DarkGray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
$errors = Get-Content $stderrFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($errors) {
|
||||||
|
# Display errors with indentation
|
||||||
|
$errors -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($process.ExitCode -ne 0) {
|
||||||
|
Write-LogMessage -Message " ⚠ Sunshine exited with code $($process.ExitCode)" -Level "Warning"
|
||||||
|
return $process.ExitCode
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message " ✓ Done" -Level "Success"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
# Clean up temp files
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message " ⓘ Skipped (executable not found)" -Level "Information" -Color "DarkGray"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script logic
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
if ($Action -eq "install") {
|
||||||
|
Write-FramedText `
|
||||||
|
-Message "🔅 Sunshine Installation Script" `
|
||||||
|
-Level "Information" `
|
||||||
|
-Color "Yellow"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
$totalSteps = 6
|
||||||
|
$currentStep = 0
|
||||||
|
|
||||||
|
# Reset permissions on the install directory
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Resetting permissions on installation directory" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
Write-LogMessage -Message "🔐 Resetting permissions on installation directory" -Level "Step"
|
||||||
|
try {
|
||||||
|
Write-LogMessage -Message "Executing: icacls.exe `"$RootDir`" /reset" -Level "Information"
|
||||||
|
|
||||||
|
# Capture output to suppress it from console but log it
|
||||||
|
$stdoutFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
$stderrFile = [System.IO.Path]::GetTempFileName()
|
||||||
|
|
||||||
|
try {
|
||||||
|
$icaclsProcess = Start-Process `
|
||||||
|
-FilePath "icacls.exe" `
|
||||||
|
-ArgumentList "`"$RootDir`" /reset" `
|
||||||
|
-Wait `
|
||||||
|
-PassThru `
|
||||||
|
-NoNewWindow `
|
||||||
|
-RedirectStandardOutput $stdoutFile `
|
||||||
|
-RedirectStandardError $stderrFile
|
||||||
|
|
||||||
|
# Log and display the output
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
$output = Get-Content $stdoutFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($output) {
|
||||||
|
# Display output with indentation
|
||||||
|
$output -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Information" -Color "DarkGray"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
$errors = Get-Content $stderrFile -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ($errors) {
|
||||||
|
# Display errors with indentation
|
||||||
|
$errors -split "`r?`n" | ForEach-Object {
|
||||||
|
if ($_.Trim()) {
|
||||||
|
Write-LogMessage -Message " $_" -Level "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($icaclsProcess.ExitCode -eq 0) {
|
||||||
|
Write-LogMessage -Message " ✓ Done" -Level "Success"
|
||||||
|
} else {
|
||||||
|
Write-LogMessage -Message " ⚠ Exit code $($icaclsProcess.ExitCode)" -Level "Warning"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
# Clean up temp files
|
||||||
|
if (Test-Path $stdoutFile) {
|
||||||
|
Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
if (Test-Path $stderrFile) {
|
||||||
|
Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-LogMessage -Message " ⚠ Failed to reset permissions: $($_.Exception.Message)" -Level "Warning"
|
||||||
|
}
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 1. Update PATH (add)
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Updating system PATH" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$updatePathScript = Join-Path $RootDir "scripts\update-path.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $updatePathScript `
|
||||||
|
-Arguments "add" `
|
||||||
|
-Description "Adding Sunshine directories to PATH" `
|
||||||
|
-Emoji "📁"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 2. Migrate configuration
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Migrating configuration" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$migrateConfigScript = Join-Path $RootDir "scripts\migrate-config.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $migrateConfigScript `
|
||||||
|
-Description "Migrating configuration files" `
|
||||||
|
-Emoji "⚙️"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 3. Add firewall rules
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Configuring firewall" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$addFirewallScript = Join-Path $RootDir "scripts\add-firewall-rule.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $addFirewallScript `
|
||||||
|
-Description "Adding firewall rules" `
|
||||||
|
-Emoji "🛡️"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 4. Install service
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Installing service" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$installServiceScript = Join-Path $RootDir "scripts\install-service.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $installServiceScript `
|
||||||
|
-Description "Installing Windows Service" `
|
||||||
|
-Emoji "⚡"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 5. Configure autostart
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Installing Sunshine" `
|
||||||
|
-Status "Configuring autostart" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$autostartScript = Join-Path $RootDir "scripts\autostart-service.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $autostartScript `
|
||||||
|
-Description "Configuring autostart" `
|
||||||
|
-Emoji "🚀"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
Write-Progress -Activity "Installing Sunshine" -Completed
|
||||||
|
Write-FramedText -Message "✓ Sunshine installation completed successfully!" -Level "Success"
|
||||||
|
|
||||||
|
# Open documentation in browser (only if not running silently)
|
||||||
|
if (-not $Silent) {
|
||||||
|
Write-Information ""
|
||||||
|
Write-LogMessage `
|
||||||
|
-Message "📖 Opening documentation in your browser: $DocsUrl" `
|
||||||
|
-Level "Step"
|
||||||
|
try {
|
||||||
|
Start-Process $DocsUrl
|
||||||
|
Write-LogMessage -Message " ✓ Done" -Level "Success"
|
||||||
|
} catch {
|
||||||
|
Write-LogMessage `
|
||||||
|
-Message " ⓘ Could not open browser automatically: $($_.Exception.Message)" `
|
||||||
|
-Level "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($Action -eq "uninstall") {
|
||||||
|
Write-FramedText `
|
||||||
|
-Message "🗑️ Sunshine Uninstallation Script" `
|
||||||
|
-Level "Information" `
|
||||||
|
-Color "Yellow"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
$totalSteps = 4
|
||||||
|
$currentStep = 0
|
||||||
|
|
||||||
|
# 1. Delete firewall rules
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Uninstalling Sunshine" `
|
||||||
|
-Status "Removing firewall rules" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$deleteFirewallScript = Join-Path $RootDir "scripts\delete-firewall-rule.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $deleteFirewallScript `
|
||||||
|
-Description "Removing firewall rules" `
|
||||||
|
-Emoji "🛡️"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 2. Uninstall service
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Uninstalling Sunshine" `
|
||||||
|
-Status "Uninstalling service" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$uninstallServiceScript = Join-Path $RootDir "scripts\uninstall-service.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $uninstallServiceScript `
|
||||||
|
-Description "Removing Windows Service" `
|
||||||
|
-Emoji "⚡"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 3. Restore NVIDIA preferences
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Uninstalling Sunshine" `
|
||||||
|
-Status "Restoring NVIDIA settings" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
Invoke-SunshineIfExist `
|
||||||
|
-Arguments "--restore-nvprefs-undo" `
|
||||||
|
-Description "Restoring NVIDIA preferences" `
|
||||||
|
-Emoji "🎮"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
# 4. Update PATH (remove)
|
||||||
|
$currentStep++
|
||||||
|
Write-Progress `
|
||||||
|
-Activity "Uninstalling Sunshine" `
|
||||||
|
-Status "Cleaning up system PATH" `
|
||||||
|
-PercentComplete (($currentStep / $totalSteps) * 100)
|
||||||
|
$updatePathScript = Join-Path $RootDir "scripts\update-path.bat"
|
||||||
|
Invoke-ScriptIfExist `
|
||||||
|
-ScriptPath $updatePathScript `
|
||||||
|
-Arguments "remove" `
|
||||||
|
-Description "Removing from PATH" `
|
||||||
|
-Emoji "📁"
|
||||||
|
Write-Information ""
|
||||||
|
|
||||||
|
Write-Progress -Activity "Uninstalling Sunshine" -Completed
|
||||||
|
Write-FramedText `
|
||||||
|
-Message "✓ Sunshine uninstallation completed successfully!" `
|
||||||
|
-Level "Success"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Information ""
|
||||||
|
exit 0
|
||||||
Loading…
Add table
Add a link
Reference in a new issue