diff --git a/iozone/.gitignore b/iozone/.gitignore new file mode 100644 index 0000000..c9461af --- /dev/null +++ b/iozone/.gitignore @@ -0,0 +1,5 @@ +* +!.gitignore +!config.json +!install_iozone.ps1 +!install_iozone_worker.ps1 diff --git a/iozone/config.json b/iozone/config.json new file mode 100644 index 0000000..a19211d --- /dev/null +++ b/iozone/config.json @@ -0,0 +1,11 @@ +{ + "download_url": "https://www.iozone.org/src/current/IozoneSetup.exe", + "file_name": "IozoneSetup.exe", + "install_cmd": "powershell", + "install_args": "-ExecutionPolicy Bypass -File @sw_path@\\install_iozone.ps1 -SwPath @sw_path@", + "install_dest": "client", + "install_time": { + "kit": "after", + "driver": "before" + } +} diff --git a/iozone/install_iozone.ps1 b/iozone/install_iozone.ps1 new file mode 100644 index 0000000..2e7e73c --- /dev/null +++ b/iozone/install_iozone.ps1 @@ -0,0 +1,70 @@ +<# +.SYNOPSIS + Launcher for iozone Clickteam installer GUI automation. + Runs in Session 0 (WinRM); schedules the worker on the interactive desktop. +.DESCRIPTION + ExtraSoftwareManager runs this script via WinRM (Session 0), which has + no interactive desktop. The Clickteam installer requires a visible GUI, + so this launcher creates a scheduled task to run install_iozone_worker.ps1 + on the interactive desktop (Session 1). It then polls for a result file + written by the worker and returns PASS/FAIL to the manager. +#> +param([string]$SwPath) + +$ErrorActionPreference = "Stop" + +$workDir = "C:\AutoHCK\iozone_install" +$resultFile = Join-Path $workDir "result.txt" +$workerLog = Join-Path $workDir "worker.log" +$workerScript = Join-Path $SwPath "install_iozone_worker.ps1" +$installerExe = Join-Path $SwPath "IozoneSetup.exe" +$taskName = "AutoHCK_InstallIozone" +$timeoutSec = 120 + +function Get-InteractiveUser { + $winlogon = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" + $u = (Get-ItemProperty -Path $winlogon -Name "DefaultUserName" -ErrorAction SilentlyContinue).DefaultUserName + if ($u) { return $u } + return "Administrator" +} + +New-Item -ItemType Directory -Force -Path $workDir | Out-Null +Remove-Item -Force $resultFile -ErrorAction SilentlyContinue +Remove-Item -Force $workerLog -ErrorAction SilentlyContinue + +$user = Get-InteractiveUser +Write-Output "Installing iozone via interactive session (user=$user, sw_path=$SwPath)" + +Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue + +$arg = "-NoProfile -ExecutionPolicy Bypass -File `"$workerScript`" -InstallerPath `"$installerExe`"" +$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $arg +$principal = New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Highest +$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -MultipleInstances IgnoreNew +Register-ScheduledTask -TaskName $taskName -Action $action -Principal $principal -Settings $settings -Force | Out-Null +Start-ScheduledTask -TaskName $taskName +Write-Output "Scheduled task started; waiting for result..." + +$deadline = (Get-Date).AddSeconds($timeoutSec) +while ((Get-Date) -lt $deadline) { + if (Test-Path $resultFile) { + $text = (Get-Content -Path $resultFile -Raw).Trim() + Write-Output $text + if (Test-Path $workerLog) { + Write-Output "--- worker.log ---" + Get-Content -Path $workerLog | ForEach-Object { Write-Output $_ } + } + Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue + if ($text -like "PASS:*") { exit 0 } + exit 1 + } + Start-Sleep -Seconds 2 +} + +Write-Output "FAIL: timed out waiting for iozone install" +if (Test-Path $workerLog) { + Write-Output "--- worker.log ---" + Get-Content -Path $workerLog | ForEach-Object { Write-Output $_ } +} +Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue +exit 1 diff --git a/iozone/install_iozone_worker.ps1 b/iozone/install_iozone_worker.ps1 new file mode 100644 index 0000000..1ccc306 --- /dev/null +++ b/iozone/install_iozone_worker.ps1 @@ -0,0 +1,175 @@ +<# +.SYNOPSIS + GUI automation worker for IozoneSetup.exe (Clickteam Install Creator). + Runs in the interactive desktop session via scheduled task. +.DESCRIPTION + Uses Win32 PostMessage BM_CLICK to click buttons directly by handle, + bypassing keyboard focus issues with SConfig console. + Navigates the 6-page Clickteam wizard: + 1. Welcome -> Next + 2. Directory -> Next (accept default) + 3. Create dir? -> Yes + 4. Confirmation -> Start + 5. Complete -> Next + 6. Publisher -> Exit + Writes PASS:/FAIL: to C:\AutoHCK\iozone_install\result.txt. +#> +param([string]$InstallerPath) + +$workDir = "C:\AutoHCK\iozone_install" +$resultFile = Join-Path $workDir "result.txt" +$logFile = Join-Path $workDir "worker.log" + +New-Item -ItemType Directory -Force -Path $workDir | Out-Null +New-Item -ItemType Directory -Force -Path "C:\temp" | Out-Null + +Start-Transcript -Path $logFile -Force +$ErrorActionPreference = "Stop" + +Add-Type -TypeDefinition @" +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +public class ClickButton { + public delegate bool EnumChildProc(IntPtr hWnd, IntPtr lParam); + + [DllImport("user32.dll")] public static extern IntPtr FindWindow(string cls, string title); + [DllImport("user32.dll")] public static extern bool EnumChildWindows(IntPtr parent, EnumChildProc cb, IntPtr lParam); + [DllImport("user32.dll")] public static extern int GetWindowText(IntPtr h, StringBuilder s, int max); + [DllImport("user32.dll")] public static extern int GetClassName(IntPtr h, StringBuilder s, int max); + [DllImport("user32.dll")] public static extern bool PostMessage(IntPtr h, uint msg, IntPtr w, IntPtr l); + [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr h); + + private const uint BM_CLICK = 0x00F5; + + public static bool ClickByText(string winTitle, string btnSubstring) { + IntPtr wnd = FindWindow(null, winTitle); + if (wnd == IntPtr.Zero) return false; + + IntPtr found = IntPtr.Zero; + EnumChildWindows(wnd, (h, l) => { + var cls = new StringBuilder(256); + GetClassName(h, cls, 256); + if (cls.ToString() != "Button") return true; + + var txt = new StringBuilder(256); + GetWindowText(h, txt, 256); + if (txt.ToString().IndexOf(btnSubstring, StringComparison.OrdinalIgnoreCase) >= 0) { + found = h; + return false; + } + return true; + }, IntPtr.Zero); + + if (found == IntPtr.Zero) return false; + return PostMessage(found, BM_CLICK, IntPtr.Zero, IntPtr.Zero); + } + + public static List ListControls(string winTitle) { + var r = new List(); + IntPtr wnd = FindWindow(null, winTitle); + if (wnd == IntPtr.Zero) { r.Add("Window not found"); return r; } + EnumChildWindows(wnd, (h, l) => { + var t = new StringBuilder(256); GetWindowText(h, t, 256); + var c = new StringBuilder(256); GetClassName(h, c, 256); + if (t.Length > 0) r.Add("[" + t + "] cls=" + c); + return true; + }, IntPtr.Zero); + return r; + } + + public static bool WindowExists(string winTitle) { + return FindWindow(null, winTitle) != IntPtr.Zero; + } +} +"@ + +try { + Write-Output "Worker session=$([System.Diagnostics.Process]::GetCurrentProcess().SessionId)" + Write-Output "InstallerPath=$InstallerPath" + + $localExe = "C:\temp\IozoneSetup.exe" + $srcResolved = (Resolve-Path $InstallerPath -ErrorAction SilentlyContinue).Path + if ($srcResolved -ne $localExe -and (Test-Path $InstallerPath)) { + Copy-Item -Path $InstallerPath -Destination $localExe -Force + Write-Output "Copied to $localExe" + } elseif (-not (Test-Path $localExe)) { + throw "Installer not found" + } else { + Write-Output "Installer already at $localExe" + } + + $title = "Iozone3_483 Install Program" + + Write-Output "Launching installer..." + $proc = Start-Process -FilePath $localExe -PassThru + Write-Output "PID=$($proc.Id)" + Start-Sleep -Seconds 5 + + if (-not [ClickButton]::WindowExists($title)) { + throw "Installer window not found" + } + Write-Output "Window found" + + $ok = [ClickButton]::ClickByText($title, "Next") + Write-Output "Step 1 Next: $ok" + Start-Sleep -Seconds 2 + + $ok = [ClickButton]::ClickByText($title, "Next") + Write-Output "Step 2 Next: $ok" + Start-Sleep -Seconds 2 + + Start-Sleep -Seconds 1 + $ok = [ClickButton]::ClickByText($title, "Yes") + if (-not $ok) { + $wsh = New-Object -ComObject WScript.Shell + $wsh.AppActivate($title) + Start-Sleep -Milliseconds 300 + $wsh.SendKeys("{ENTER}") + Write-Output "Step 3 Yes: fallback SendKeys Enter" + } else { + Write-Output "Step 3 Yes: $ok" + } + Start-Sleep -Seconds 2 + + $controls = [ClickButton]::ListControls($title) + Write-Output "Step 4 controls: $($controls -join ', ')" + $ok = [ClickButton]::ClickByText($title, "Start") + Write-Output "Step 4 Start: $ok" + Start-Sleep -Seconds 8 + + $ok = [ClickButton]::ClickByText($title, "Next") + Write-Output "Step 5 Next: $ok" + Start-Sleep -Seconds 2 + + $ok = [ClickButton]::ClickByText($title, "xit") + Write-Output "Step 6 Exit: $ok" + Start-Sleep -Seconds 2 + + if (-not $proc.HasExited) { + Write-Output "Waiting for process..." + $proc.WaitForExit(30000) + } + Write-Output "Exited=$($proc.HasExited)" + + $iozoneExe = "C:\Program Files (x86)\Benchmarks\Iozone3_483\iozone.exe" + if (Test-Path $iozoneExe) { + Write-Output "SUCCESS: $iozoneExe" + Set-Content $resultFile "PASS: iozone installed at $iozoneExe" + } else { + $found = Get-ChildItem C:\ -Filter iozone.exe -Recurse -Depth 4 -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($found) { + Write-Output "Found at $($found.FullName)" + Set-Content $resultFile "PASS: iozone installed at $($found.FullName)" + } else { + throw "iozone.exe not found after install" + } + } +} catch { + Write-Output "ERROR: $_" + Set-Content $resultFile "FAIL: $_" +} + +Stop-Transcript