v1.8.93: rewrite update script from VBS+PowerShell to plain BAT with logging

VBS→PowerShell chain was silently failing. BAT is simpler, doesn't depend
on execution policy, and writes detailed log to %TEMP%\sm_update.log
for debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-03-02 04:13:36 -05:00
parent bc48aea1e4
commit 273666236a
3 changed files with 79 additions and 56 deletions

View File

@@ -262,75 +262,98 @@ class UpdateChecker:
return self._apply_linux(binary_path, current_exe)
def _apply_windows(self, new_exe: str, current_exe: str) -> bool:
"""Windows update: PowerShell script waits for exit, copies, launches."""
"""Windows update: BAT script waits for exit, copies, launches."""
try:
tmp_dir = tempfile.gettempdir()
ps_path = os.path.join(tmp_dir, "sm_update.ps1")
vbs_path = os.path.join(tmp_dir, "sm_update.vbs")
bat_path = os.path.join(tmp_dir, "sm_update.bat")
log_path = os.path.join(tmp_dir, "sm_update.log")
pid = os.getpid()
mei_dir = getattr(sys, '_MEIPASS', '')
exe_dir = os.path.dirname(current_exe)
ps_content = f"""
$pid = {pid}
$src = '{new_exe}'
$dst = '{current_exe}'
$tempDir = '{tmp_dir}'
bat_content = f"""@echo off
chcp 65001 >nul 2>&1
set "LOGFILE={log_path}"
set "SRC={new_exe}"
set "DST={current_exe}"
set "PID={pid}"
set "TMPDIR={tmp_dir}"
# Wait for old process to exit
while (Get-Process -Id $pid -ErrorAction SilentlyContinue) {{
Start-Sleep -Seconds 1
}}
Start-Sleep -Seconds 3
echo [%date% %time%] Update script started >> "%LOGFILE%"
echo [%date% %time%] PID to wait for: %PID% >> "%LOGFILE%"
echo [%date% %time%] SRC: %SRC% >> "%LOGFILE%"
echo [%date% %time%] DST: %DST% >> "%LOGFILE%"
# Clean ALL stale _MEI directories (best-effort, skip locked)
try {{
Get-ChildItem -Path $tempDir -Directory -Filter '_MEI*' -ErrorAction SilentlyContinue | ForEach-Object {{
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}}
}} catch {{}}
Start-Sleep -Seconds 1
:wait_loop
tasklist /FI "PID eq %PID%" 2>nul | find "%PID%" >nul
if %errorlevel%==0 (
echo [%date% %time%] Waiting for PID %PID% to exit... >> "%LOGFILE%"
timeout /t 1 /nobreak >nul
goto wait_loop
)
# Copy with retry
$copied = $false
for ($i = 0; $i -lt 5; $i++) {{
try {{
Copy-Item -Path $src -Destination $dst -Force
$srcSize = (Get-Item $src).Length
$dstSize = (Get-Item $dst).Length
if ($srcSize -eq $dstSize) {{
$copied = $true
break
}}
}} catch {{}}
Start-Sleep -Seconds 2
}}
echo [%date% %time%] Process exited, waiting 3s... >> "%LOGFILE%"
timeout /t 3 /nobreak >nul
if (-not $copied) {{ exit 1 }}
rem Clean stale _MEI directories
echo [%date% %time%] Cleaning _MEI directories... >> "%LOGFILE%"
for /d %%D in ("%TMPDIR%\\_MEI*") do (
rmdir /s /q "%%D" >nul 2>&1
)
timeout /t 1 /nobreak >nul
Start-Sleep -Seconds 2
rem Copy with retry
echo [%date% %time%] Starting copy... >> "%LOGFILE%"
set COPIED=0
for /L %%i in (1,1,5) do (
if !COPIED!==0 (
copy /Y "%SRC%" "%DST%" >nul 2>&1
if exist "%DST%" (
echo [%date% %time%] Copy attempt %%i done >> "%LOGFILE%"
set COPIED=1
) else (
echo [%date% %time%] Copy attempt %%i failed >> "%LOGFILE%"
timeout /t 2 /nobreak >nul
)
)
)
# Launch new exe via cmd start (clean environment, proper path handling)
Start-Process cmd.exe -ArgumentList '/c', 'start', '""', ('"{0}"' -f $dst) -WindowStyle Hidden
if %COPIED%==0 (
echo [%date% %time%] FAILED: could not copy after 5 attempts >> "%LOGFILE%"
pause
goto cleanup
)
# Cleanup
Start-Sleep -Seconds 3
Remove-Item -Path $src -Force -ErrorAction SilentlyContinue
Remove-Item -Path '{ps_path}' -Force -ErrorAction SilentlyContinue
echo [%date% %time%] Copy successful, launching... >> "%LOGFILE%"
timeout /t 2 /nobreak >nul
rem Launch new exe
echo [%date% %time%] Starting: %DST% >> "%LOGFILE%"
start "" "%DST%"
echo [%date% %time%] Launch command issued >> "%LOGFILE%"
timeout /t 2 /nobreak >nul
:cleanup
rem Delete downloaded update file
del /f /q "%SRC%" >nul 2>&1
echo [%date% %time%] Cleanup done >> "%LOGFILE%"
rem Self-delete
del /f /q "%~f0" >nul 2>&1
"""
with open(ps_path, "w", encoding="utf-8") as f:
f.write(ps_content)
# Enable delayed expansion for variables inside for loops
bat_content = bat_content.replace("@echo off",
"@echo off\nsetlocal enabledelayedexpansion")
# VBS wrapper launches PowerShell hidden (no window flash)
vbs_content = (
'CreateObject("Wscript.Shell").Run '
'"powershell -ExecutionPolicy Bypass -WindowStyle Hidden '
f'-File ""{ps_path}""""", 0, False\n'
with open(bat_path, "w", encoding="utf-8") as f:
f.write(bat_content)
log.info(f"Update BAT: {bat_path}, log: {log_path}")
# Launch BAT minimized (not hidden — need cmd.exe to run)
subprocess.Popen(
["cmd.exe", "/c", "start", "/min", "", bat_path],
creationflags=_SUBPROCESS_FLAGS,
)
with open(vbs_path, "w") as f:
f.write(vbs_content)
os.startfile(vbs_path)
return True
except Exception as e:

Binary file not shown.

View File

@@ -1,6 +1,6 @@
"""Version info for ServerManager."""
__version__ = "1.8.92"
__version__ = "1.8.93"
__app_name__ = "ServerManager"
__author__ = "aibot777"
__description__ = "Desktop GUI for managing remote servers"