param([string]$ServerUrl = 'https://checkcheckfit.com') $ErrorActionPreference = 'Stop' $env:PSModulePath = [IO.Path]::Combine($PSHOME,'Modules') + ';' + $env:PSModulePath try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $serverUri = [Uri]$ServerUrl if ($serverUri.Scheme -ne 'https') { throw 'HTTPS server required.' } $ServerUrl = $serverUri.GetLeftPart([UriPartial]::Authority) Write-Host 'Checkcheck Center Music Player' -ForegroundColor Cyan Write-Host 'This installs the music player for this Windows user and starts it at sign-in.' Write-Host 'Keep this PC awake and connect the speakers before enabling music.' $code = (Read-Host 'Enter the 8-character code from Center > Operations automation').Trim() if ($code -notmatch '^[A-Fa-f0-9]{8}$') { throw 'Invalid registration code.' } $playerDir = Join-Path $env:LOCALAPPDATA 'CheckcheckMusic' $null = New-Item -ItemType Directory -Force -Path $playerDir $downloadPath = Join-Path $playerDir 'player.download' Invoke-WebRequest -UseBasicParsing -Uri ($ServerUrl + '/operations-player.ps1?v=210') -OutFile $downloadPath -TimeoutSec 30 -MaximumRedirection 0 if ((Get-FileHash -LiteralPath $downloadPath -Algorithm SHA256).Hash.ToLowerInvariant() -ne '0c02aeb87a13a7a60df0a055d9bd58f94d47f076baaa03839d64043e6a42c079') { throw 'Player download integrity check failed.' } $parseTokens = $null; $parseErrors = $null $null = [Management.Automation.Language.Parser]::ParseFile($downloadPath, [ref]$parseTokens, [ref]$parseErrors) if ($parseErrors.Count) { throw 'Invalid player file.' } $pairBody = @{ code=$code; name=$env:COMPUTERNAME } | ConvertTo-Json -Compress $registration = Invoke-RestMethod -Method Post -Uri ($ServerUrl + '/api/operations/player/pair') -ContentType 'application/json; charset=utf-8' -Body ([Text.Encoding]::UTF8.GetBytes($pairBody)) -TimeoutSec 15 -MaximumRedirection 0 $protectedToken = ConvertTo-SecureString -String $registration.token -AsPlainText -Force | ConvertFrom-SecureString $config = @{ server=$ServerUrl; protectedToken=$protectedToken } | ConvertTo-Json -Compress [IO.File]::WriteAllText((Join-Path $playerDir 'config.json'), $config, [Text.UTF8Encoding]::new($false)) $playerPath = Join-Path $playerDir 'operations-player.ps1' # Stop only the old player belonging to this user's dedicated installation. foreach ($process in Get-CimInstance Win32_Process -Filter "Name='powershell.exe'") { if ($process.ProcessId -ne $PID -and $process.CommandLine -and $process.CommandLine.Contains($playerPath)) { Stop-Process -Id $process.ProcessId -ErrorAction SilentlyContinue } } Move-Item -LiteralPath $downloadPath -Destination $playerPath -Force $powerShellExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe' $arguments = '-NoProfile -STA -ExecutionPolicy Bypass -WindowStyle Hidden -File "' + $playerPath + '"' $shortcutPath = Join-Path ([Environment]::GetFolderPath('Startup')) 'Checkcheck Music.lnk' $shell = New-Object -ComObject WScript.Shell $shortcut = $shell.CreateShortcut($shortcutPath); $shortcut.TargetPath = $powerShellExe; $shortcut.Arguments = $arguments; $shortcut.WorkingDirectory = $playerDir; $shortcut.WindowStyle = 7; $shortcut.Save() Start-Process -FilePath $powerShellExe -ArgumentList $arguments -WindowStyle Hidden Write-Host 'Installed. Check player status in Center > Operations automation.' -ForegroundColor Green Write-Host ('Status file: ' + (Join-Path $playerDir 'status.txt')) Write-Host 'To uninstall, revoke this player in Checkcheck, then remove Checkcheck Music from Windows Startup Apps.' } catch { Write-Host ('Installation failed: ' + $_.Exception.Message) -ForegroundColor Red } $null = Read-Host 'Press Enter to close'