-
Notifications
You must be signed in to change notification settings - Fork 20
/
output.txt
13 lines (6 loc) · 17.6 KB
/
output.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
File: Installer.ps1
## Fun fact, most of this code is generated entirely using GPT-3.5 ## CHATGPT PROMPT 1 ## Explain to me how to parse a conf file in PowerShell. ## AI EXPLAINS HOW... this is important as it invokes reflective thinking. ## Having AI explain things to us first before asking ## your question, significantly improves the quality of the response. ### PROMPT 2 ### Okay, using this conf, can you write a powershell script that saves a new value to the global_prep_cmd? ### AI Generates valid code for saving to conf file ## Prompt 3 ### I think I have found a mistake, can you double check your work? ## Again, this is important for reflective thinking, having the AI ## check its work is important, as it may improve quality. ## Response: Did not find any errors. ## Prompt 4: I tried this and unfortunately my config file requires admin to save. ## AI Responses solutions ## Like before, I already knew the solution but having the AI ## respond with tips, greatly improves the quality of the next prompts ## Prompt 5 (Final with GPT3.5): Can you make this script self elevate itself. ## Repeat the same prompt principles, and basically 70% of this script is entirely written by Artificial Intelligence. Yay! ## Refactor Prompt (GPT-4): Please refactor the following code, remove duplication and define better function names, once finished you will also add documentation and comments to each function. param($install) $filePath = $($MyInvocation.MyCommand.Path) $scriptRoot = Split-Path $filePath -Parent $scriptPath = "$scriptRoot\ResolutionMatcher.ps1" # This script modifies the global_prep_cmd setting in the Sunshine configuration file # to add a command that runs ResolutionMatcher.ps1 # Check if the current user has administrator privileges $isAdmin = [bool]([System.Security.Principal.WindowsIdentity]::GetCurrent().groups -match 'S-1-5-32-544') # If the current user is not an administrator, re-launch the script with elevated privileges if (-not $isAdmin) { Start-Process powershell.exe -Verb RunAs -ArgumentList "-ExecutionPolicy Bypass -NoExit -File `"$filePath`" $install" exit } function Test-AndRequest-SunshineConfig { param( [string]$InitialPath ) # Check if the initial path exists if (Test-Path $InitialPath) { Write-Host "File found at: $InitialPath" return $InitialPath } else { # Show error message dialog [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null [System.Windows.Forms.MessageBox]::Show("Sunshine configuration could not be found. Please locate it.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error) | Out-Null # Open file dialog $fileDialog = New-Object System.Windows.Forms.OpenFileDialog $fileDialog.Title = "Open sunshine.conf" $fileDialog.Filter = "Configuration files (*.conf)|*.conf" $fileDialog.InitialDirectory = [System.IO.Path]::GetDirectoryName($InitialPath) if ($fileDialog.ShowDialog() -eq "OK") { $selectedPath = $fileDialog.FileName # Check if the selected path is valid if (Test-Path $selectedPath) { Write-Host "File selected: $selectedPath" return $selectedPath } else { Write-Error "Invalid file path selected." } } else { Write-Error "Sunshine Configuiration file dialog was canceled or no valid file was selected." exit 1 } } } # Define the path to the Sunshine configuration file $confPath = Test-AndRequest-SunshineConfig -InitialPath "C:\Program Files\Sunshine\config\sunshine.conf" $scriptRoot = Split-Path $scriptPath -Parent # Get the current value of global_prep_cmd from the configuration file function Get-GlobalPrepCommand { # Read the contents of the configuration file into an array of strings $config = Get-Content -Path $confPath # Find the line that contains the global_prep_cmd setting $globalPrepCmdLine = $config | Where-Object { $_ -match '^global_prep_cmd\s*=' } # Extract the current value of global_prep_cmd if ($globalPrepCmdLine -match '=\s*(.+)$') { return $matches[1] } else { Write-Information "Unable to extract current value of global_prep_cmd, this probably means user has not setup prep commands yet." return [object[]]@() } } # Remove any existing commands that contain ResolutionMatcher from the global_prep_cmd value function Remove-ResolutionMatcherCommand { # Get the current value of global_prep_cmd as a JSON string $globalPrepCmdJson = Get-GlobalPrepCommand -ConfigPath $confPath # Convert the JSON string to an array of objects $globalPrepCmdArray = $globalPrepCmdJson | ConvertFrom-Json $filteredCommands = @() # Remove any ResolutionMatcher Commands for ($i = 0; $i -lt $globalPrepCmdArray.Count; $i++) { if (-not ($globalPrepCmdArray[$i].do -like "*ResolutionMatcher*")) { $filteredCommands += $globalPrepCmdArray[$i] } } return [object[]]$filteredCommands } # Set a new value for global_prep_cmd in the configuration file function Set-GlobalPrepCommand { param ( # The new value for global_prep_cmd as an array of objects [object[]]$Value ) if ($null -eq $Value) { $Value = [object[]]@() } # Read the contents of the configuration file into an array of strings $config = Get-Content -Path $confPath # Get the current value of global_prep_cmd as a JSON string $currentValueJson = Get-GlobalPrepCommand -ConfigPath $confPath # Convert the new value to a JSON string $newValueJson = ConvertTo-Json -InputObject $Value -Compress # Replace the current value with the new value in the config array try { $config = $config -replace [regex]::Escape($currentValueJson), $newValueJson } catch { # If it failed, it probably does not exist yet. # In the event the config only has one line, we will cast this to an object array so it appends a new line automatically. if ($Value.Length -eq 0) { [object[]]$config += "global_prep_cmd = []" } else { [object[]]$config += "global_prep_cmd = $($newValueJson)" } } # Write the modified config array back to the file $config | Set-Content -Path $confPath -Force } # Add a new command to run ResolutionMatcher.ps1 to the global_prep_cmd value function Add-ResolutionMatcherCommand { # Remove any existing commands that contain ResolutionMatcher from the global_prep_cmd value $globalPrepCmdArray = Remove-ResolutionMatcherCommand -ConfigPath $confPath # Create a new object with the command to run ResolutionMatcher.ps1 $ResolutionMatcherCommand = [PSCustomObject]@{ do = "powershell.exe -executionpolicy bypass -WindowStyle Hidden -file `"$($scriptPath)`"" elevated = "false" undo = "powershell.exe -executionpolicy bypass -WindowStyle Hidden -file `"$($scriptRoot)\ResolutionMatcher-Functions.ps1`" $true" } # Add the new object to the global_prep_cmd array [object[]]$globalPrepCmdArray += $ResolutionMatcherCommand return [object[]]$globalPrepCmdArray } $commands = @() if ($install -eq "True") { $commands = Add-ResolutionMatcherCommand } else { $commands = Remove-ResolutionMatcherCommand } Set-GlobalPrepCommand $commands $sunshineService = Get-Service -ErrorAction Ignore | Where-Object { $_.Name -eq 'sunshinesvc' -or $_.Name -eq 'SunshineService' } # In order for the commands to apply we have to restart the service $sunshineService | Restart-Service -WarningAction SilentlyContinue Write-Host "If you didn't see any errors, that means the script installed without issues! You can close this window."
File: ResolutionMatcher-Functions.ps1
param($terminate) Set-Location (Split-Path $MyInvocation.MyCommand.Path -Parent) Add-Type -Path .\internals\DisplaySettings.cs # If reverting the resolution fails, you can set a manual override here. $host_resolution_override = @{ Width = 0 Height = 0 Refresh = 0 } ## Code and type generated with ChatGPT v4, 1st prompt worked flawlessly. Function Set-ScreenResolution($width, $height, $frequency) { Write-Host "Setting screen resolution to $width x $height x $frequency" $tolerance = 2 # Set the tolerance value for the frequency comparison $devMode = New-Object DisplaySettings+DEVMODE $devMode.dmSize = [System.Runtime.InteropServices.Marshal]::SizeOf($devMode) $modeNum = 0 while ([DisplaySettings]::EnumDisplaySettings([NullString]::Value, $modeNum, [ref]$devMode)) { $frequencyDiff = [Math]::Abs($devMode.dmDisplayFrequency - $frequency) if ($devMode.dmPelsWidth -eq $width -and $devMode.dmPelsHeight -eq $height -and $frequencyDiff -le $tolerance) { $result = [DisplaySettings]::ChangeDisplaySettings([ref]$devMode, 0) if ($result -eq 0) { Write-Host "Resolution changed successfully." } else { Write-Host "Failed to change resolution. Error code: $result" } break } $modeNum++ } } function Get-HostResolution { $devMode = New-Object DisplaySettings+DEVMODE $devMode.dmSize = [System.Runtime.InteropServices.Marshal]::SizeOf($devMode) $modeNum = -1 while ([DisplaySettings]::EnumDisplaySettings([NullString]::Value, $modeNum, [ref]$devMode)) { return @{ Width = $devMode.dmPelsWidth Height = $devMode.dmPelsHeight Refresh = $devMode.dmDisplayFrequency } } } function Assert-ResolutionChange($width, $height, $refresh) { # Attempt to set the resolution up to 6 times, in event of failures for ($i = 0; $i -lt 12; $i++) { $hostResolution = Get-HostResolution $refreshDiff = [Math]::Abs($hostResolution.Refresh - $refresh) if (($width -ne $hostResolution.Width) -or ($height -ne $hostResolution.Height) -or ($refreshDiff -ge 2)) { # If the resolutions don't match, set the screen resolution to the current client's resolution Write-Host "Current Resolution: $($hostResolution.Width) x $($hostResolution.Height) x $($hostResolution.Refresh)" Write-Host "Expected Requested Resolution: $width x $height x $refresh" Set-ScreenResolution $width $height $refresh } # Wait for a while before checking the resolution again Start-Sleep -Milliseconds 500 } } function Join-Overrides($width, $height, $refresh) { Write-Host "Before Override: $width x $height x $refresh" $overrides = Get-Content ".\overrides.txt" -ErrorAction SilentlyContinue foreach ($line in $overrides) { if ($null -ne $line -and "" -ne $line) { $overrides = $line | Select-String "(?<width>\d{1,})x(?<height>\d*)x?(?<refresh>\d*)?" -AllMatches $heights = $overrides[0].Matches.Groups | Where-Object { $_.Name -eq 'height' } $widths = $overrides[0].Matches.Groups | Where-Object { $_.Name -eq 'width' } $refreshes = $overrides[0].Matches.Groups | Where-Object { $_.Name -eq 'refresh' } if ($widths[0].Value -eq $width -and $heights[0].Value -eq $height -and $refreshes[0].Value -eq $refresh) { $width = $widths[1].Value $height = $heights[1].Value $refresh = $refreshes[1].Value break } } } Write-Host "After Override: $width x $height x $refresh" return @{ height = $height width = $width refresh = $refresh } } function IsCurrentlyStreaming() { return $null -ne (Get-NetUDPEndpoint -OwningProcess (Get-Process sunshine).Id -ErrorAction Ignore) } function Stop-ResolutionMatcherScript() { $pipeExists = Get-ChildItem -Path "\\.\pipe\" | Where-Object { $_.Name -eq "ResolutionMatcher" } if ($pipeExists.Length -gt 0) { $pipeName = "ResolutionMatcher" $pipe = New-Object System.IO.Pipes.NamedPipeClientStream(".", $pipeName, [System.IO.Pipes.PipeDirection]::Out) $pipe.Connect(5) $streamWriter = New-Object System.IO.StreamWriter($pipe) $streamWriter.WriteLine("Terminate") try { $streamWriter.Flush() $streamWriter.Dispose() $pipe.Dispose() } catch { # We don't care if the disposal fails, this is common with async pipes. # Also, this powershell script will terminate anyway. } } } function OnStreamStart($width, $height, $refresh) { $expectedRes = Join-Overrides -width $width -height $height -refresh $refresh Set-ScreenResolution -Width $expectedRes.Width -Height $expectedRes.Height -Freq $expectedRes.Refresh Assert-ResolutionChange -width $expectedRes.Width -height $expectedRes.Height -refresh $expectedRes.Refresh } function OnStreamEnd($hostResolution) { if (($host_resolution_override.Values | Measure-Object -Sum).Sum -gt 1000) { $hostResolution = @{ Width = $host_resolution_override['Width'] Height = $host_resolution_override['Height'] Refresh = $host_resolution_override['Refresh'] } } Set-ScreenResolution -Width $hostResolution.Width -Height $hostResolution.Height -Freq $hostResolution.Refresh } if ($terminate) { Stop-ResolutionMatcherScript | Out-Null }
File: ResolutionMatcher.ps1
param($async) $path = (Split-Path $MyInvocation.MyCommand.Path -Parent) Set-Location $path $settings = Get-Content -Path .\settings.json | ConvertFrom-Json # Since pre-commands in sunshine are synchronous, we'll launch this script again in another powershell process if ($null -eq $async) { Start-Process powershell.exe -ArgumentList "-ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`" $($MyInvocation.MyCommand.UnboundArguments) -async $true" -WindowStyle Hidden exit } Start-Transcript -Path .\log.txt . .\ResolutionMatcher-Functions.ps1 $hostResolutions = Get-HostResolution $lock = $false $mutexName = "ResolutionMatcher" $resolutionMutex = New-Object System.Threading.Mutex($false, $mutexName, [ref]$lock) # There is no need to have more than one of these scripts running. if (-not $resolutionMutex.WaitOne(0)) { Write-Host "Another instance of the script is already running. Exiting..." exit } try { # Asynchronously start the ResolutionMatcher, so we can use a named pipe to terminate it. Start-Job -Name ResolutionMatcherJob -ScriptBlock { param($path, $revertDelay) . $path\ResolutionMatcher-Functions.ps1 $lastStreamed = Get-Date Register-EngineEvent -SourceIdentifier ResolutionMatcher -Forward New-Event -SourceIdentifier ResolutionMatcher -MessageData "Start" while ($true) { try { if ((IsCurrentlyStreaming)) { $lastStreamed = Get-Date } else { if (((Get-Date) - $lastStreamed).TotalSeconds -gt $revertDelay) { New-Event -SourceIdentifier ResolutionMatcher -MessageData "End" break; } } } finally { Start-Sleep -Seconds 1 } } } -ArgumentList $path, $settings.revertDelay # To allow other powershell scripts to communicate to this one. Start-Job -Name "ResolutionMatcher-Pipe" -ScriptBlock { $pipeName = "ResolutionMatcher" Remove-Item "\\.\pipe\$pipeName" -ErrorAction Ignore $pipe = New-Object System.IO.Pipes.NamedPipeServerStream($pipeName, [System.IO.Pipes.PipeDirection]::In, 1, [System.IO.Pipes.PipeTransmissionMode]::Byte, [System.IO.Pipes.PipeOptions]::Asynchronous) $streamReader = New-Object System.IO.StreamReader($pipe) Write-Output "Waiting for named pipe to recieve kill command" $pipe.WaitForConnection() $message = $streamReader.ReadLine() if ($message -eq "Terminate") { Write-Output "Terminating pipe..." $pipe.Dispose() $streamReader.Dispose() } } $eventMessageCount = 0 Write-Host "Waiting for the next event to be called... (for starting/ending stream)" while ($true) { $eventMessageCount += 1 Start-Sleep -Seconds 1 $eventFired = Get-Event -SourceIdentifier ResolutionMatcher -ErrorAction SilentlyContinue $pipeJob = Get-Job -Name "ResolutionMatcher-Pipe" if ($null -ne $eventFired) { $eventName = $eventFired.MessageData Write-Host "Processing event: $eventName" if ($eventName -eq "Start") { OnStreamStart -width $env:SUNSHINE_CLIENT_WIDTH -height $env:SUNSHINE_CLIENT_HEIGHT -refresh $env:SUNSHINE_CLIENT_FPS } elseif ($eventName -eq "End") { OnStreamEnd $hostResolutions break; } Remove-Event -EventIdentifier $eventFired.EventIdentifier } elseif ($pipeJob.State -eq "Completed") { Write-Host "Request to terminate has been processed, script will now revert resolution." OnStreamEnd $hostResolutions break; } elseif($eventMessageCount -gt 59) { Write-Host "Still waiting for the next event to fire..." $eventMessageCount = 0 } } } finally { Remove-Item "\\.\pipe\ResolutionMatcher" -ErrorAction Ignore $resolutionMutex.ReleaseMutex() Remove-Event -SourceIdentifier ResolutionMatcher -ErrorAction Ignore Stop-Transcript }