Private/Find-Prerequisites.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Multi-level prerequisite detection functions for installer .DESCRIPTION Detect Python, ffmpeg, VoiceMeeter, and BeyondATC using progressive detection: 1. PATH environment variable (fastest) 2. Registry (for old installations) 3. Common filesystem paths (fallback) Returns hashtable with Found, Path, Version, Method #> function Find-Python { [OutputType([hashtable])] param() # Level 1: Check winget default location (AppData) - HIGHEST PRIORITY try { $pythonExe = Get-ChildItem -Path "$env:LOCALAPPDATA\Programs\Python\*\python.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($pythonExe) { $version = & $pythonExe.FullName --version 2>&1 return @{ Found = $true Path = $pythonExe.FullName Version = $version Method = "FileSystem (winget/AppData)" } } } catch {} # Level 2: Check Program Files (machine-scope or manual installs) try { $pythonExe = Get-ChildItem -Path "C:\Program Files\Python*\python.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($pythonExe) { $version = & $pythonExe.FullName --version 2>&1 return @{ Found = $true Path = $pythonExe.FullName Version = $version Method = "FileSystem (Program Files)" } } } catch {} # Level 3: Check Registry (Python.org installations) try { $pythonReg = Get-ChildItem "HKCU:\Software\Python\PythonCore" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.InstallPath} | Select-Object -First 1 if ($pythonReg -and (Test-Path "$($pythonReg.InstallPath)python.exe")) { return @{ Found = $true Path = "$($pythonReg.InstallPath)python.exe" Version = "Unknown (Registry)" Method = "Registry" } } } catch {} # Level 4: Check PATH (fallback if PATH was updated) try { $pythonExe = (Get-Command python.exe -ErrorAction Stop).Source $version = & $pythonExe --version 2>&1 return @{ Found = $true Path = $pythonExe Version = $version Method = "PATH" } } catch {} # Not found return @{ Found = $false Path = $null Version = $null Method = $null } } function Find-FFmpeg { [OutputType([hashtable])] param() # Level 1: Check winget default location (AppData) - HIGHEST PRIORITY - NESTED DIRECTORY STRUCTURE try { $ffmpegExe = Get-ChildItem -Path "$env:LOCALAPPDATA\Microsoft\WinGet\Packages\Gyan.FFmpeg*\*\bin\ffmpeg.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($ffmpegExe) { $version = & $ffmpegExe.FullName -version 2>&1 | Select-Object -First 1 return @{ Found = $true Path = $ffmpegExe.FullName Version = $version Method = "FileSystem (winget/AppData)" } } } catch {} # Level 2: Check Program Files (machine-scope winget installs) try { $ffmpegExe = Get-ChildItem -Path "C:\Program Files\WinGet\Packages\Gyan.FFmpeg*\*\bin\ffmpeg.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($ffmpegExe) { $version = & $ffmpegExe.FullName -version 2>&1 | Select-Object -First 1 return @{ Found = $true Path = $ffmpegExe.FullName Version = $version Method = "FileSystem (Program Files/winget)" } } } catch {} # Level 3: Check Registry (Gyan.FFmpeg or similar installations) try { $ffmpegReg = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like "*FFmpeg*"} | Select-Object -First 1 if ($ffmpegReg -and $ffmpegReg.InstallLocation) { $ffmpegExe = Join-Path $ffmpegReg.InstallLocation "bin\ffmpeg.exe" if (Test-Path $ffmpegExe) { return @{ Found = $true Path = $ffmpegExe Version = $ffmpegReg.DisplayVersion Method = "Registry" } } } } catch {} # Level 4: Check other common paths (manual/traditional installs) $commonPaths = @( "C:\Program Files\FFmpeg\bin\ffmpeg.exe", "C:\Program Files (x86)\FFmpeg\bin\ffmpeg.exe", "C:\ffmpeg\bin\ffmpeg.exe" ) foreach ($path in $commonPaths) { if (Test-Path $path) { return @{ Found = $true Path = $path Version = "Unknown (FileSystem)" Method = "FileSystem (manual)" } } } # Level 5: Check PATH (fallback if PATH was updated) try { $ffmpegExe = (Get-Command ffmpeg.exe -ErrorAction Stop).Source $version = & $ffmpegExe -version 2>&1 | Select-Object -First 1 return @{ Found = $true Path = $ffmpegExe Version = $version Method = "PATH" } } catch {} return @{ Found = $false Path = $null Version = $null Method = $null } } function Find-VoiceMeeter { [OutputType([hashtable])] param() # Level 1: Registry (HKLM) - Search for VoiceMeeter with case-insensitive pattern try { $vmReg = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like "*Voicemeeter*" -or $_.DisplayName -like "*VB-Audio*"} | Select-Object -First 1 if ($vmReg -and $vmReg.InstallLocation -and (Test-Path $vmReg.InstallLocation)) { return @{ Found = $true Path = $vmReg.InstallLocation Version = $vmReg.DisplayVersion Method = "Registry (HKLM)" } } } catch {} # Level 1b: Registry (HKCU) - User-level installations try { $vmReg = Get-ChildItem "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like "*Voicemeeter*" -or $_.DisplayName -like "*VB-Audio*"} | Select-Object -First 1 if ($vmReg -and $vmReg.InstallLocation -and (Test-Path $vmReg.InstallLocation)) { return @{ Found = $true Path = $vmReg.InstallLocation Version = $vmReg.DisplayVersion Method = "Registry (HKCU)" } } } catch {} # Level 1c: Registry (WOW6432Node) - 32-bit registry on 64-bit systems try { $vmReg = Get-ChildItem "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like "*Voicemeeter*" -or $_.DisplayName -like "*VB-Audio*"} | Select-Object -First 1 if ($vmReg -and $vmReg.InstallLocation -and (Test-Path $vmReg.InstallLocation)) { return @{ Found = $true Path = $vmReg.InstallLocation Version = $vmReg.DisplayVersion Method = "Registry (WOW6432)" } } } catch {} # Level 2: Check official VoiceMeeter installation paths # Official installations use "VB\" not "VB-Audio\" # NOTE: Must use ${env:ProgramFiles(x86)} with braces - parentheses require braces in PowerShell $commonPaths = @( "C:\Program Files (x86)\VB\Voicemeeter", # 32-bit driver (primary) - hardcoded "C:\Program Files\VB\VBVoicemeeterVAIOs", # 64-bit ASIO driver - hardcoded "C:\Program Files\VB\Voicemeeter", # Alternative 64-bit location - hardcoded "${env:ProgramFiles(x86)}\VB\Voicemeeter", # 32-bit with env var (FIXED: braces required) "$env:ProgramFiles\VB\Voicemeeter", # 64-bit with env var (FIXED: correct case) "$env:ProgramFiles\VB\VBVoicemeeterVAIOs" # ASIO with env var (FIXED: correct case) ) foreach ($path in $commonPaths) { if (Test-Path $path) { return @{ Found = $true Path = $path Version = "Unknown (FileSystem)" Method = "FileSystem" } } } # Level 3: Wildcard search for VB folder (catches portable/non-standard installations) try { $vbDirs = Get-ChildItem -Path "C:\Program Files", "C:\Program Files (x86)" -Directory -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq "VB"} | Get-ChildItem -Directory -ErrorAction SilentlyContinue | Where-Object {$_.Name -like "*Voicemeeter*" -or $_.Name -like "*VAIO*"} | Select-Object -First 1 if ($vbDirs -and (Test-Path $vbDirs.FullName)) { return @{ Found = $true Path = $vbDirs.FullName Version = "Unknown (Wildcard Search)" Method = "FileSystem (Wildcard)" } } } catch {} return @{ Found = $false Path = $null Version = $null Method = $null } } function Find-BeyondATC { [OutputType([hashtable])] param() # Level 1: AppData LocalLow (OFFICIAL configuration location) $btcLocalLow = "$env:USERPROFILE\AppData\LocalLow\Skirmish Mode Games, Inc\BeyondATC" if (Test-Path $btcLocalLow) { return @{ Found = $true Path = $btcLocalLow Version = "Unknown (FileSystem)" Method = "FileSystem (AppData LocalLow)" } } # Level 2: Program Files (default installation path) $btcProgramFiles = "C:\Program Files\BeyondATC" if (Test-Path $btcProgramFiles) { return @{ Found = $true Path = $btcProgramFiles Version = "Unknown (FileSystem)" Method = "FileSystem (Program Files)" } } # Level 3: Registry (fallback - most BeyondATC installations don't register) try { $btcReg = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall" -ErrorAction Stop | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like "*BeyondATC*"} | Select-Object -First 1 if ($btcReg -and $btcReg.InstallLocation) { return @{ Found = $true Path = $btcReg.InstallLocation Version = $btcReg.DisplayVersion Method = "Registry" } } } catch {} return @{ Found = $false Path = $null Version = $null Method = $null } } Export-ModuleMember -Function @( 'Find-Python', 'Find-FFmpeg', 'Find-VoiceMeeter', 'Find-BeyondATC' ) |