param( [string]$TargetVersion = "2.2.0.136", [string]$DeviceInstanceId = "", [string]$DeviceHardwareIdPattern = "ACPI\AMDI0030*", [string]$BadVersion = "2.2.0.137", [string]$KnownBadInf = "", [string]$DriverZipUrl = "https://raw.githubusercontent.com/emotionbug/SER8/main/AMD-GPIO2-2.2.0.136.zip", [string]$ExpectedDriverZipSha256 = "3572505115c2d373fc11fbde9e94c3fd1e508270871d57964dfe6aa08a7954d3", [string]$DriverZipPath = "", [string]$SourceInf = "", [switch]$NoDownload, [switch]$NoInstall, [switch]$NoPause ) $ErrorActionPreference = "Stop" $logDir = Join-Path $env:USERPROFILE "Downloads\CrashDumps" $workDir = Join-Path $env:USERPROFILE "Downloads\AMD-GPIO2-Rollback" New-Item -ItemType Directory -Force -Path $logDir, $workDir | Out-Null $stamp = Get-Date -Format "yyyyMMdd-HHmmss" $log = Join-Path $logDir "amd-gpio2-github-rollback-$stamp.log" function Write-Step { param([string]$Message) $line = "[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $Message Write-Host $line Add-Content -Path $log -Value $line -Encoding UTF8 } function Run-Cmd { param([string]$CommandLine, [switch]$AllowFailure) Write-Step "> $CommandLine" $oldErrorActionPreference = $ErrorActionPreference try { $ErrorActionPreference = "Continue" $output = cmd.exe /d /c $CommandLine 2>&1 $code = $LASTEXITCODE } finally { $ErrorActionPreference = $oldErrorActionPreference } $output | Tee-Object -FilePath $log -Append Write-Step "exit code: $code" if ($code -ne 0 -and -not $AllowFailure) { throw "Command failed: $CommandLine" } return $code } function Test-Admin { $principal = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Get-InfDriverVersion { param([string]$InfPath) if (-not (Test-Path -LiteralPath $InfPath)) { return $null } $line = Select-String -Path $InfPath -Pattern "^\s*DriverVer\s*=" -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $line) { return $null } if ($line.Line -match "DriverVer\s*=\s*[^,]+,\s*([0-9.]+)") { return $Matches[1] } return $null } function Get-ActiveGpioDriver { param([string]$InstanceId) return Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceID -eq $InstanceId } | Select-Object -First 1 } function Find-AmdGpioDevice { param([string]$HardwareIdPattern) $matches = Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceID -like $HardwareIdPattern -and $_.DeviceName -like "*GPIO*" -and $_.Manufacturer -like "*Advanced Micro Devices*" } | Sort-Object DeviceID return @($matches) } function Get-PublishedInfVersion { param([string]$PublishedInf) if (-not $PublishedInf) { return $null } $infPath = Join-Path $env:WINDIR ("INF\{0}" -f $PublishedInf) return Get-InfDriverVersion -InfPath $infPath } function Find-TargetInf { param([string]$Root) if (-not (Test-Path -LiteralPath $Root)) { return $null } $matches = Get-ChildItem -Path $Root -Recurse -Filter "amdgpio2.inf" -ErrorAction SilentlyContinue | ForEach-Object { $ver = Get-InfDriverVersion -InfPath $_.FullName [pscustomobject]@{ Path = $_.FullName Version = $ver LastWriteTime = $_.LastWriteTime } } | Where-Object { $_.Version -eq $TargetVersion } | Sort-Object @{ Expression = { $_.Path -like "*W11x64*" }; Descending = $true }, LastWriteTime -Descending return ($matches | Select-Object -First 1).Path } function Assert-DriverZip { param([string]$Path) if (-not (Test-Path -LiteralPath $Path)) { throw "Driver ZIP was not found: $Path" } if ($ExpectedDriverZipSha256) { $actualSha256 = (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() if ($actualSha256 -ne $ExpectedDriverZipSha256.ToLowerInvariant()) { throw "Driver ZIP SHA256 mismatch. Expected=$ExpectedDriverZipSha256 Actual=$actualSha256 Path=$Path" } Write-Step "Driver ZIP SHA256 verified: $actualSha256" } } function Download-DriverZip { if ($NoDownload) { return "" } $downloadPath = Join-Path $workDir ("AMD-GPIO2-{0}.zip" -f $TargetVersion) if (Test-Path -LiteralPath $downloadPath) { Write-Step "Using existing driver ZIP: $downloadPath" Assert-DriverZip -Path $downloadPath return $downloadPath } Write-Step "Downloading GPIO2 driver ZIP: $DriverZipUrl" Invoke-WebRequest -Uri $DriverZipUrl -OutFile $downloadPath -UseBasicParsing Assert-DriverZip -Path $downloadPath Write-Step "Downloaded driver ZIP: $downloadPath" return $downloadPath } function Expand-DriverZip { param([string]$ZipPath) if (-not $ZipPath -or -not (Test-Path -LiteralPath $ZipPath)) { return "" } Assert-DriverZip -Path $ZipPath $extractRoot = Join-Path $workDir ("github-gpio2-{0}" -f $stamp) New-Item -ItemType Directory -Force -Path $extractRoot | Out-Null Write-Step "Extracting driver ZIP to: $extractRoot" Expand-Archive -LiteralPath $ZipPath -DestinationPath $extractRoot -Force $inf = Find-TargetInf -Root $extractRoot if ($inf) { Write-Step "Found target INF in ZIP: $inf" return $inf } return "" } if (-not (Test-Admin) -and -not $NoInstall) { Write-Host "관리자 권한으로 다시 실행합니다." $argList = @( "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$PSCommandPath`"", "-TargetVersion", "`"$TargetVersion`"", "-DeviceHardwareIdPattern", "`"$DeviceHardwareIdPattern`"", "-BadVersion", "`"$BadVersion`"", "-DriverZipUrl", "`"$DriverZipUrl`"", "-ExpectedDriverZipSha256", "`"$ExpectedDriverZipSha256`"" ) if ($DeviceInstanceId) { $argList += @("-DeviceInstanceId", "`"$DeviceInstanceId`"") } if ($KnownBadInf) { $argList += @("-KnownBadInf", "`"$KnownBadInf`"") } if ($DriverZipPath) { $argList += @("-DriverZipPath", "`"$DriverZipPath`"") } if ($SourceInf) { $argList += @("-SourceInf", "`"$SourceInf`"") } if ($NoDownload) { $argList += "-NoDownload" } if ($NoInstall) { $argList += "-NoInstall" } if ($NoPause) { $argList += "-NoPause" } Start-Process -FilePath powershell.exe -ArgumentList $argList -Verb RunAs exit 0 } Write-Step "AMD GPIO2 GitHub rollback started" Write-Step "Target GPIO2 version: $TargetVersion" Write-Step "Bad GPIO2 version to remove: $BadVersion" Write-Step "Driver ZIP URL: $DriverZipUrl" Write-Step "Log: $log" if (-not $DeviceInstanceId) { Write-Step "Auto-detecting AMD GPIO Controller with pattern: $DeviceHardwareIdPattern" $gpioDevices = Find-AmdGpioDevice -HardwareIdPattern $DeviceHardwareIdPattern if ($gpioDevices.Count -eq 0) { throw "No AMD GPIO Controller matching $DeviceHardwareIdPattern was found." } if ($gpioDevices.Count -gt 1) { Write-Step "Multiple AMD GPIO Controller candidates were found. Re-run with -DeviceInstanceId." $gpioDevices | Select-Object DeviceName, DeviceID, DriverVersion, InfName, Manufacturer | Format-List | Out-String | Tee-Object -FilePath $log -Append throw "Multiple target devices found." } $DeviceInstanceId = $gpioDevices[0].DeviceID } Write-Step "Target device: $DeviceInstanceId" Write-Step "Current AMD GPIO Controller state" $initialActive = Get-ActiveGpioDriver -InstanceId $DeviceInstanceId if (-not $initialActive) { throw "Target device was not found: $DeviceInstanceId" } $initialActive | Select-Object DeviceName, DeviceID, DriverVersion, DriverDate, InfName, Manufacturer | Format-List | Out-String | Tee-Object -FilePath $log -Append if ($initialActive.DeviceName -notlike "*GPIO*") { throw "Target device does not look like an AMD GPIO device. DeviceName=$($initialActive.DeviceName)" } $targetInf = "" if ($SourceInf) { $version = Get-InfDriverVersion -InfPath $SourceInf if ($version -ne $TargetVersion) { throw "SourceInf is not GPIO2 $TargetVersion. Path=$SourceInf Version=$version" } $targetInf = $SourceInf } if (-not $targetInf -and $DriverZipPath) { $targetInf = Expand-DriverZip -ZipPath $DriverZipPath } if (-not $targetInf) { $downloaded = Download-DriverZip if ($downloaded) { $targetInf = Expand-DriverZip -ZipPath $downloaded } } if (-not $targetInf) { throw "Could not find amdgpio2.inf version $TargetVersion. Provide -SourceInf, -DriverZipPath, or a working -DriverZipUrl." } Write-Step "Target INF selected: $targetInf" if ($NoInstall) { Write-Step "NoInstall was specified. Stopping before pnputil changes." if (-not $NoPause) { Write-Host "" Write-Host "검증 완료. 로그: $log" Write-Host "창을 닫기 전에 아무 키나 누르세요." [void][Console]::ReadKey($true) } exit 0 } Write-Step "Matching drivers before rollback" Run-Cmd ('pnputil /enum-devices /instanceid "{0}" /drivers' -f $DeviceInstanceId) -AllowFailure | Out-Null $badInfs = New-Object System.Collections.Generic.List[string] if ($KnownBadInf) { $badInfs.Add($KnownBadInf) } if ($initialActive.DriverVersion -eq $BadVersion -and $initialActive.InfName) { $badInfs.Add($initialActive.InfName) } $matchingBad = Get-ChildItem -Path (Join-Path $env:WINDIR "INF") -Filter "oem*.inf" -ErrorAction SilentlyContinue | ForEach-Object { $ver = Get-InfDriverVersion -InfPath $_.FullName if ($ver -eq $BadVersion -and (Select-String -Path $_.FullName -Pattern "amdgpio2|AMDI0030" -Quiet -ErrorAction SilentlyContinue)) { $_.Name } } foreach ($inf in $matchingBad) { $badInfs.Add($inf) } $badInfs = $badInfs | Where-Object { $_ } | Sort-Object -Unique foreach ($badInf in $badInfs) { $ver = Get-PublishedInfVersion -PublishedInf $badInf if ($ver -and $ver -ne $BadVersion) { Write-Step "Skipping $badInf because its version is $ver, not $BadVersion" continue } Write-Step "Removing bad/newer GPIO2 package if present: $badInf" Run-Cmd ('pnputil /delete-driver {0} /uninstall /force' -f $badInf) -AllowFailure | Out-Null } Write-Step "Installing target GPIO2 INF" Run-Cmd ('pnputil /add-driver "{0}" /install' -f $targetInf) -AllowFailure | Out-Null Write-Step "Scanning devices" Run-Cmd "pnputil /scan-devices" -AllowFailure | Out-Null Start-Sleep -Seconds 3 Write-Step "Matching drivers after rollback" Run-Cmd ('pnputil /enum-devices /instanceid "{0}" /drivers' -f $DeviceInstanceId) -AllowFailure | Out-Null Write-Step "Final AMD GPIO Controller state" $active = Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceID -eq $DeviceInstanceId } $active | Select-Object DeviceName, DeviceID, DriverVersion, DriverDate, InfName, Manufacturer | Format-List | Out-String | Tee-Object -FilePath $log -Append if ($active.DriverVersion -eq $TargetVersion) { Write-Step "SUCCESS: AMD GPIO2 is active at $TargetVersion." } else { Write-Step "WARNING: WMI reports $($active.DriverVersion) / $($active.InfName). If pnputil shows the target INF as installed, reboot and re-check." } Write-Step "Reboot is recommended before judging stability." if (-not $NoPause) { Write-Host "" Write-Host "완료. 로그: $log" Write-Host "창을 닫기 전에 아무 키나 누르세요." [void][Console]::ReadKey($true) }