mirror of
https://github.com/Andre-Bzk/SunshineDisplaySwitch.git
synced 2026-11-15 09:33:11 +01:00
Coarse DisplaySwitch projection modes cannot reliably target the virtual display once multiple physical monitors are connected. The setup needs to persist Sunshine's device-specific configuration and document the recovery path so stream startup and abnormal shutdown handling remain predictable.
624 lines
19 KiB
Batchfile
624 lines
19 KiB
Batchfile
@echo off
|
|
setlocal
|
|
set "SDS_SELF=%~f0"
|
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -Sta -Command "$path=$env:SDS_SELF; $raw=Get-Content -LiteralPath $path -Raw; $marker='### POWERSHELL ###'; $index=$raw.LastIndexOf($marker); if($index -lt 0){throw 'PowerShell block not found.'}; $code=$raw.Substring($index + $marker.Length); Invoke-Expression $code"
|
|
exit /b %ERRORLEVEL%
|
|
|
|
### POWERSHELL ###
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$SunshineDir = if ([string]::IsNullOrWhiteSpace($env:SDS_SUNSHINE_DIR)) { Join-Path $env:ProgramFiles 'Sunshine' } else { $env:SDS_SUNSHINE_DIR }
|
|
$DeviceId = $env:SDS_DEVICE_ID
|
|
$ListOnly = $env:SDS_LIST_ONLY -eq '1'
|
|
$NoRestart = $env:SDS_NO_RESTART -eq '1'
|
|
$Silent = $env:SDS_SILENT -eq '1'
|
|
$Action = $env:SDS_ACTION
|
|
$BatchPath = $env:SDS_SELF
|
|
|
|
function Test-IsAdministrator {
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
function Test-CanWriteFile {
|
|
param([string]$Path)
|
|
|
|
try {
|
|
$stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::Read)
|
|
$stream.Close()
|
|
return $true
|
|
}
|
|
catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Get-JsonArrayAfterMarker {
|
|
param(
|
|
[string]$Text,
|
|
[string]$Marker
|
|
)
|
|
|
|
$markerIndex = $Text.LastIndexOf($Marker, [StringComparison]::OrdinalIgnoreCase)
|
|
if ($markerIndex -lt 0) {
|
|
return $null
|
|
}
|
|
|
|
$start = $Text.IndexOf('[', $markerIndex + $Marker.Length)
|
|
if ($start -lt 0) {
|
|
return $null
|
|
}
|
|
|
|
$depth = 0
|
|
$inString = $false
|
|
$escaped = $false
|
|
|
|
for ($i = $start; $i -lt $Text.Length; $i++) {
|
|
$char = $Text[$i]
|
|
|
|
if ($inString) {
|
|
if ($escaped) {
|
|
$escaped = $false
|
|
continue
|
|
}
|
|
|
|
if ($char -eq '\') {
|
|
$escaped = $true
|
|
continue
|
|
}
|
|
|
|
if ($char -eq '"') {
|
|
$inString = $false
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
if ($char -eq '"') {
|
|
$inString = $true
|
|
continue
|
|
}
|
|
|
|
if ($char -eq '[') {
|
|
$depth++
|
|
continue
|
|
}
|
|
|
|
if ($char -eq ']') {
|
|
$depth--
|
|
if ($depth -eq 0) {
|
|
return $Text.Substring($start, $i - $start + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Format-Rational {
|
|
param($Rational)
|
|
|
|
$rationalValue = Get-ObjectProperty -Object $Rational -Name 'value'
|
|
if ($null -eq $rationalValue) {
|
|
return ''
|
|
}
|
|
|
|
$denominator = [double](Get-ObjectProperty -Object $rationalValue -Name 'denominator')
|
|
if ($denominator -eq 0) {
|
|
return ''
|
|
}
|
|
|
|
$value = [double](Get-ObjectProperty -Object $rationalValue -Name 'numerator') / $denominator
|
|
$formatted = ('{0:N2}' -f $value).TrimEnd('0').TrimEnd((Get-Culture).NumberFormat.NumberDecimalSeparator)
|
|
return "$formatted Hz"
|
|
}
|
|
|
|
function Get-ObjectProperty {
|
|
param(
|
|
$Object,
|
|
[string]$Name
|
|
)
|
|
|
|
if ($null -eq $Object) {
|
|
return $null
|
|
}
|
|
|
|
$property = $Object.PSObject.Properties[$Name]
|
|
if ($null -eq $property) {
|
|
return $null
|
|
}
|
|
|
|
return $property.Value
|
|
}
|
|
|
|
function ConvertTo-DisplayRows {
|
|
param([object[]]$Devices)
|
|
|
|
if ($Devices.Count -eq 1 -and $Devices[0] -is [Array]) {
|
|
$Devices = $Devices[0]
|
|
}
|
|
|
|
$rows = @()
|
|
foreach ($device in $Devices) {
|
|
$resolution = ''
|
|
$refreshRate = ''
|
|
$primary = $false
|
|
$active = $false
|
|
|
|
$info = Get-ObjectProperty -Object $device -Name 'info'
|
|
if ($null -ne $info) {
|
|
$active = $true
|
|
$resolutionInfo = Get-ObjectProperty -Object $info -Name 'resolution'
|
|
if ($null -ne $resolutionInfo) {
|
|
$resolution = '{0}x{1}' -f (Get-ObjectProperty -Object $resolutionInfo -Name 'width'), (Get-ObjectProperty -Object $resolutionInfo -Name 'height')
|
|
}
|
|
$refreshRate = Format-Rational -Rational (Get-ObjectProperty -Object $info -Name 'refresh_rate')
|
|
$primaryInfo = Get-ObjectProperty -Object $info -Name 'primary'
|
|
if ($null -ne $primaryInfo) {
|
|
$primary = [bool]$primaryInfo
|
|
}
|
|
}
|
|
|
|
$edid = ''
|
|
$deviceEdid = Get-ObjectProperty -Object $device -Name 'edid'
|
|
if ($null -ne $deviceEdid) {
|
|
$edidParts = @()
|
|
$manufacturerId = Get-ObjectProperty -Object $deviceEdid -Name 'manufacturer_id'
|
|
$productCode = Get-ObjectProperty -Object $deviceEdid -Name 'product_code'
|
|
$serialNumber = Get-ObjectProperty -Object $deviceEdid -Name 'serial_number'
|
|
if ($manufacturerId) { $edidParts += $manufacturerId }
|
|
if ($productCode) { $edidParts += $productCode }
|
|
if ($null -ne $serialNumber) { $edidParts += "SN:$serialNumber" }
|
|
$edid = $edidParts -join ' '
|
|
}
|
|
|
|
$rows += [pscustomobject]@{
|
|
Name = [string](Get-ObjectProperty -Object $device -Name 'friendly_name')
|
|
DeviceId = [string](Get-ObjectProperty -Object $device -Name 'device_id')
|
|
DisplayName = [string](Get-ObjectProperty -Object $device -Name 'display_name')
|
|
Active = $active
|
|
Primary = $primary
|
|
Resolution = $resolution
|
|
RefreshRate = $refreshRate
|
|
Edid = $edid
|
|
}
|
|
}
|
|
|
|
return $rows
|
|
}
|
|
|
|
function Get-SunshineDisplayDevicesDirect {
|
|
param([string]$InstallDir)
|
|
|
|
$sunshineExe = Join-Path $InstallDir 'sunshine.exe'
|
|
if (-not (Test-Path -LiteralPath $sunshineExe)) {
|
|
throw "Sunshine executable not found: $sunshineExe"
|
|
}
|
|
|
|
$stdoutPath = Join-Path $env:TEMP ('sunshine-display-probe-{0}.out' -f ([guid]::NewGuid()))
|
|
$stderrPath = Join-Path $env:TEMP ('sunshine-display-probe-{0}.err' -f ([guid]::NewGuid()))
|
|
$probeLogPath = Join-Path $env:TEMP ('sunshine-display-probe-{0}.log' -f ([guid]::NewGuid()))
|
|
$process = $null
|
|
|
|
function Stop-ProbeProcess {
|
|
param($Process)
|
|
|
|
if ($null -eq $Process -or $Process.HasExited) {
|
|
return
|
|
}
|
|
|
|
Stop-Process -Id $Process.Id -Force -ErrorAction SilentlyContinue
|
|
try {
|
|
$Process.WaitForExit(2000) | Out-Null
|
|
}
|
|
catch {
|
|
}
|
|
}
|
|
|
|
try {
|
|
$arguments = @('-1', "log_path=$probeLogPath")
|
|
$process = Start-Process -FilePath $sunshineExe -ArgumentList $arguments -WorkingDirectory $InstallDir -WindowStyle Hidden -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -PassThru
|
|
|
|
$deadline = (Get-Date).AddSeconds(10)
|
|
$json = $null
|
|
|
|
while ((Get-Date) -lt $deadline) {
|
|
Start-Sleep -Milliseconds 200
|
|
|
|
if (Test-Path -LiteralPath $stdoutPath) {
|
|
$text = Get-Content -LiteralPath $stdoutPath -Raw
|
|
$json = Get-JsonArrayAfterMarker -Text $text -Marker 'Currently available display devices:'
|
|
if (-not [string]::IsNullOrWhiteSpace($json)) {
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($process.HasExited) {
|
|
break
|
|
}
|
|
}
|
|
|
|
Stop-ProbeProcess -Process $process
|
|
|
|
if ([string]::IsNullOrWhiteSpace($json)) {
|
|
$stdout = if (Test-Path -LiteralPath $stdoutPath) { Get-Content -LiteralPath $stdoutPath -Raw } else { '' }
|
|
$stderr = if (Test-Path -LiteralPath $stderrPath) { Get-Content -LiteralPath $stderrPath -Raw } else { '' }
|
|
throw "Sunshine did not return a display-device list.`n`nstdout:`n$stdout`n`nstderr:`n$stderr"
|
|
}
|
|
|
|
return ConvertTo-DisplayRows -Devices @($json | ConvertFrom-Json)
|
|
}
|
|
finally {
|
|
Stop-ProbeProcess -Process $process
|
|
|
|
Remove-Item -LiteralPath $stdoutPath, $stderrPath, $probeLogPath -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
function Set-ConfigValue {
|
|
param(
|
|
[string[]]$Lines,
|
|
[string]$Key,
|
|
[string]$Value
|
|
)
|
|
|
|
$pattern = '^\s*' + [regex]::Escape($Key) + '\s*='
|
|
$replacement = "$Key = $Value"
|
|
$found = $false
|
|
|
|
for ($i = 0; $i -lt $Lines.Count; $i++) {
|
|
if ($Lines[$i] -match $pattern) {
|
|
$Lines[$i] = $replacement
|
|
$found = $true
|
|
break
|
|
}
|
|
}
|
|
|
|
if (-not $found) {
|
|
$Lines += $replacement
|
|
}
|
|
|
|
return ,$Lines
|
|
}
|
|
|
|
function Remove-ConfigValues {
|
|
param(
|
|
[string[]]$Lines,
|
|
[string[]]$Keys
|
|
)
|
|
|
|
$patterns = @($Keys | ForEach-Object { '^\s*' + [regex]::Escape($_) + '\s*=' })
|
|
$kept = @()
|
|
|
|
foreach ($line in $Lines) {
|
|
$remove = $false
|
|
foreach ($pattern in $patterns) {
|
|
if ($line -match $pattern) {
|
|
$remove = $true
|
|
break
|
|
}
|
|
}
|
|
|
|
if (-not $remove) {
|
|
$kept += $line
|
|
}
|
|
}
|
|
|
|
return ,$kept
|
|
}
|
|
|
|
function Remove-LegacyDisplayPrepCommands {
|
|
param([string[]]$Lines)
|
|
|
|
$pattern = '^\s*global_prep_cmd\s*=\s*(.+?)\s*$'
|
|
|
|
for ($i = 0; $i -lt $Lines.Count; $i++) {
|
|
if ($Lines[$i] -notmatch $pattern) {
|
|
continue
|
|
}
|
|
|
|
$json = $Matches[1]
|
|
try {
|
|
$commands = @($json | ConvertFrom-Json)
|
|
if ($commands.Count -eq 1 -and $commands[0] -is [Array]) {
|
|
$commands = $commands[0]
|
|
}
|
|
}
|
|
catch {
|
|
return ,$Lines
|
|
}
|
|
|
|
$kept = @()
|
|
foreach ($command in $commands) {
|
|
$do = if ($null -ne $command.do) { [string]$command.do } else { '' }
|
|
$undo = if ($null -ne $command.undo) { [string]$command.undo } else { '' }
|
|
$combined = "$do $undo"
|
|
$isLegacyDisplayCommand = $combined -match '(?i)(idd_an\.bat|idd_aus\.bat|DisplaySwitch(\.exe)?\s+(/internal|/external|/extend|/clone|[1234]))'
|
|
|
|
if (-not $isLegacyDisplayCommand) {
|
|
$kept += $command
|
|
}
|
|
}
|
|
|
|
$Lines[$i] = 'global_prep_cmd = ' + (ConvertTo-Json -InputObject $kept -Compress -Depth 10)
|
|
return ,$Lines
|
|
}
|
|
|
|
return ,$Lines
|
|
}
|
|
|
|
function Save-SunshineConfig {
|
|
param(
|
|
[string]$ConfigPath,
|
|
[pscustomobject]$SelectedDisplay
|
|
)
|
|
|
|
if (-not (Test-Path -LiteralPath $ConfigPath)) {
|
|
throw "Sunshine config not found: $ConfigPath"
|
|
}
|
|
|
|
$backupPath = '{0}.bak-{1}' -f $ConfigPath, (Get-Date -Format 'yyyyMMdd-HHmmss')
|
|
Copy-Item -LiteralPath $ConfigPath -Destination $backupPath
|
|
|
|
$lines = @(Get-Content -LiteralPath $ConfigPath)
|
|
$lines = Remove-LegacyDisplayPrepCommands -Lines $lines
|
|
$lines = Set-ConfigValue -Lines $lines -Key 'output_name' -Value $SelectedDisplay.DeviceId
|
|
$lines = Set-ConfigValue -Lines $lines -Key 'dd_configuration_option' -Value 'ensure_only_display'
|
|
$lines = Set-ConfigValue -Lines $lines -Key 'dd_resolution_option' -Value 'auto'
|
|
$lines = Set-ConfigValue -Lines $lines -Key 'dd_refresh_rate_option' -Value 'auto'
|
|
$lines = Set-ConfigValue -Lines $lines -Key 'dd_config_revert_delay' -Value '3000'
|
|
|
|
Set-Content -LiteralPath $ConfigPath -Value $lines -Encoding UTF8
|
|
return $backupPath
|
|
}
|
|
|
|
function Reset-SunshineDisplayConfig {
|
|
param([string]$ConfigPath)
|
|
|
|
if (-not (Test-Path -LiteralPath $ConfigPath)) {
|
|
throw "Sunshine config not found: $ConfigPath"
|
|
}
|
|
|
|
$backupPath = '{0}.bak-{1}' -f $ConfigPath, (Get-Date -Format 'yyyyMMdd-HHmmss')
|
|
Copy-Item -LiteralPath $ConfigPath -Destination $backupPath
|
|
|
|
$keysToRemove = @(
|
|
'output_name'
|
|
'dd_configuration_option'
|
|
'dd_resolution_option'
|
|
'dd_refresh_rate_option'
|
|
'dd_config_revert_delay'
|
|
)
|
|
|
|
$lines = @(Get-Content -LiteralPath $ConfigPath)
|
|
$lines = Remove-ConfigValues -Lines $lines -Keys $keysToRemove
|
|
Set-Content -LiteralPath $ConfigPath -Value $lines -Encoding UTF8
|
|
return $backupPath
|
|
}
|
|
|
|
function Show-MonitorMenu {
|
|
param([object[]]$Devices)
|
|
|
|
Write-Host ''
|
|
Write-Host 'Sunshine Streaming-Monitor auswaehlen'
|
|
Write-Host '===================================='
|
|
Write-Host ''
|
|
|
|
for ($i = 0; $i -lt $Devices.Count; $i++) {
|
|
$device = $Devices[$i]
|
|
$state = if ($device.Active) { 'aktiv' } else { 'inaktiv' }
|
|
$primary = if ($device.Primary) { ', primaer' } else { '' }
|
|
$displayName = if ([string]::IsNullOrWhiteSpace($device.DisplayName)) { '-' } else { $device.DisplayName }
|
|
$resolution = if ([string]::IsNullOrWhiteSpace($device.Resolution)) { '-' } else { $device.Resolution }
|
|
$refreshRate = if ([string]::IsNullOrWhiteSpace($device.RefreshRate)) { '-' } else { $device.RefreshRate }
|
|
$edid = if ([string]::IsNullOrWhiteSpace($device.Edid)) { '-' } else { $device.Edid }
|
|
|
|
Write-Host ('[{0}] {1}' -f ($i + 1), $device.Name)
|
|
Write-Host (' ID : {0}' -f $device.DeviceId)
|
|
Write-Host (' DisplayName : {0}' -f $displayName)
|
|
Write-Host (' Status : {0}{1}' -f $state, $primary)
|
|
Write-Host (' Modus : {0}, {1}' -f $resolution, $refreshRate)
|
|
Write-Host (' EDID : {0}' -f $edid)
|
|
Write-Host ''
|
|
}
|
|
|
|
Write-Host '[R] Sunshine-Monitor-Einstellungen auf Default zuruecksetzen'
|
|
Write-Host '[Q] Abbrechen'
|
|
Write-Host ''
|
|
|
|
while ($true) {
|
|
$choice = (Read-Host 'Auswahl').Trim()
|
|
|
|
if ($choice -match '^(q|Q)$') {
|
|
return [pscustomobject]@{ Action = 'quit'; Display = $null }
|
|
}
|
|
|
|
if ($choice -match '^(r|R)$') {
|
|
return [pscustomobject]@{ Action = 'reset'; Display = $null }
|
|
}
|
|
|
|
$number = 0
|
|
if ([int]::TryParse($choice, [ref]$number) -and $number -ge 1 -and $number -le $Devices.Count) {
|
|
return [pscustomobject]@{ Action = 'select'; Display = $Devices[$number - 1] }
|
|
}
|
|
|
|
Write-Host 'Ungueltige Auswahl. Bitte Zahl, R oder Q eingeben.'
|
|
}
|
|
}
|
|
|
|
function Pause-IfInteractive {
|
|
if (-not $Silent -and -not $ListOnly -and $env:SDS_NO_PAUSE -ne '1') {
|
|
Write-Host ''
|
|
Read-Host 'Enter zum Schliessen' | Out-Null
|
|
}
|
|
}
|
|
|
|
function Restart-Elevated {
|
|
param(
|
|
[string]$RequestedAction,
|
|
[string]$SelectedDeviceId
|
|
)
|
|
|
|
$commands = @(
|
|
('set "SDS_ACTION={0}"' -f $RequestedAction)
|
|
('set "SDS_SUNSHINE_DIR={0}"' -f $SunshineDir)
|
|
('set "SDS_NO_RESTART={0}"' -f ($(if ($NoRestart) { '1' } else { '0' })))
|
|
)
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($SelectedDeviceId)) {
|
|
$commands += ('set "SDS_DEVICE_ID={0}"' -f $SelectedDeviceId)
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($env:SDS_CONFIG_PATH)) {
|
|
$commands += ('set "SDS_CONFIG_PATH={0}"' -f $env:SDS_CONFIG_PATH)
|
|
}
|
|
|
|
if ($Silent) {
|
|
$commands += 'set "SDS_SILENT=1"'
|
|
}
|
|
|
|
$commands += ('"{0}"' -f $BatchPath)
|
|
$command = $commands -join ' && '
|
|
Start-Process -FilePath $env:ComSpec -ArgumentList ('/c ' + $command) -Verb RunAs
|
|
}
|
|
|
|
function Restart-SunshineServiceIfRequested {
|
|
param([switch]$NoRestart)
|
|
|
|
if ($NoRestart) {
|
|
return
|
|
}
|
|
|
|
$answer = (Read-Host 'Sunshine jetzt neu starten, damit die Aenderung sofort aktiv wird? [j/N]').Trim()
|
|
if ($answer -notmatch '^(j|J|y|Y)$') {
|
|
return
|
|
}
|
|
|
|
$services = @(Get-Service | Where-Object {
|
|
$_.Name -like '*Sunshine*' -or $_.DisplayName -like '*Sunshine*'
|
|
})
|
|
|
|
if ($services.Count -eq 0) {
|
|
Write-Host 'Kein Sunshine-Dienst gefunden. Starte Sunshine manuell neu.'
|
|
return
|
|
}
|
|
|
|
foreach ($service in $services) {
|
|
Restart-Service -Name $service.Name -Force
|
|
}
|
|
|
|
Write-Host 'Sunshine wurde neu gestartet.'
|
|
}
|
|
|
|
$configPath = if ([string]::IsNullOrWhiteSpace($env:SDS_CONFIG_PATH)) { Join-Path $SunshineDir 'config\sunshine.conf' } else { $env:SDS_CONFIG_PATH }
|
|
|
|
try {
|
|
if ($Action -eq 'reset') {
|
|
if (-not (Test-CanWriteFile -Path $configPath) -and -not (Test-IsAdministrator)) {
|
|
Restart-Elevated -RequestedAction 'reset' -SelectedDeviceId ''
|
|
exit
|
|
}
|
|
|
|
$backupPath = Reset-SunshineDisplayConfig -ConfigPath $configPath
|
|
|
|
if ($Silent) {
|
|
Write-Output ("Reset: Sunshine display settings removed")
|
|
Write-Output ("Config: {0}" -f $configPath)
|
|
Write-Output ("Backup: {0}" -f $backupPath)
|
|
exit
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host 'Sunshine-Monitor-Einstellungen wurden auf Default zurueckgesetzt.'
|
|
Write-Host ("Config : {0}" -f $configPath)
|
|
Write-Host ("Backup : {0}" -f $backupPath)
|
|
Write-Host ''
|
|
Restart-SunshineServiceIfRequested -NoRestart:$NoRestart
|
|
Pause-IfInteractive
|
|
exit
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($DeviceId)) {
|
|
$devices = @(Get-SunshineDisplayDevicesDirect -InstallDir $SunshineDir)
|
|
}
|
|
else {
|
|
$devices = @(Get-SunshineDisplayDevicesDirect -InstallDir $SunshineDir)
|
|
}
|
|
|
|
if ($ListOnly) {
|
|
$devices | Format-Table Name, DeviceId, DisplayName, Active, Primary, Resolution, RefreshRate -AutoSize
|
|
exit
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($DeviceId)) {
|
|
$menuResult = Show-MonitorMenu -Devices $devices
|
|
if ($menuResult.Action -eq 'quit') {
|
|
Write-Host 'Abgebrochen.'
|
|
Pause-IfInteractive
|
|
exit
|
|
}
|
|
|
|
if ($menuResult.Action -eq 'reset') {
|
|
if (-not (Test-CanWriteFile -Path $configPath) -and -not (Test-IsAdministrator)) {
|
|
Restart-Elevated -RequestedAction 'reset' -SelectedDeviceId ''
|
|
exit
|
|
}
|
|
|
|
$backupPath = Reset-SunshineDisplayConfig -ConfigPath $configPath
|
|
Write-Host ''
|
|
Write-Host 'Sunshine-Monitor-Einstellungen wurden auf Default zurueckgesetzt.'
|
|
Write-Host ("Config : {0}" -f $configPath)
|
|
Write-Host ("Backup : {0}" -f $backupPath)
|
|
Write-Host ''
|
|
Restart-SunshineServiceIfRequested -NoRestart:$NoRestart
|
|
Pause-IfInteractive
|
|
exit
|
|
}
|
|
|
|
$selectedDisplay = $menuResult.Display
|
|
}
|
|
else {
|
|
$selectedDisplay = $devices | Where-Object { $_.DeviceId -ieq $DeviceId } | Select-Object -First 1
|
|
if ($null -eq $selectedDisplay) {
|
|
throw "Display device id not found in Sunshine output: $DeviceId"
|
|
}
|
|
}
|
|
|
|
if ($null -eq $selectedDisplay) {
|
|
exit
|
|
}
|
|
|
|
if (-not (Test-CanWriteFile -Path $configPath) -and -not (Test-IsAdministrator)) {
|
|
Restart-Elevated -RequestedAction 'select' -SelectedDeviceId $selectedDisplay.DeviceId
|
|
exit
|
|
}
|
|
|
|
$backupPath = Save-SunshineConfig -ConfigPath $configPath -SelectedDisplay $selectedDisplay
|
|
|
|
if ($Silent) {
|
|
Write-Output ("Selected: {0}" -f $selectedDisplay.Name)
|
|
Write-Output ("DeviceId: {0}" -f $selectedDisplay.DeviceId)
|
|
Write-Output ("Config: {0}" -f $configPath)
|
|
Write-Output ("Backup: {0}" -f $backupPath)
|
|
exit
|
|
}
|
|
|
|
Write-Host ''
|
|
Write-Host 'Sunshine-Konfiguration gespeichert.'
|
|
Write-Host ("Ausgewaehlt : {0}" -f $selectedDisplay.Name)
|
|
Write-Host ("ID : {0}" -f $selectedDisplay.DeviceId)
|
|
Write-Host ("Config : {0}" -f $configPath)
|
|
Write-Host ("Backup : {0}" -f $backupPath)
|
|
Write-Host ''
|
|
|
|
Restart-SunshineServiceIfRequested -NoRestart:$NoRestart
|
|
Pause-IfInteractive
|
|
}
|
|
catch {
|
|
Write-Error $_
|
|
Pause-IfInteractive
|
|
exit 1
|
|
}
|