Compare commits
3 Commits
0c43a0b619
...
65086f4407
| Author | SHA1 | Date | |
|---|---|---|---|
| 65086f4407 | |||
| 6d3271c144 | |||
| d979fd81c1 |
@@ -1,222 +1,205 @@
|
||||
@ECHO OFF
|
||||
REM CHECKUPD.BAT - Check for available updates without applying them
|
||||
REM Quick status check to see if network has newer files
|
||||
REM
|
||||
REM Usage: CHECKUPD
|
||||
REM
|
||||
REM Checks these sources:
|
||||
REM T:\COMMON\ProdSW\*.bat
|
||||
REM T:\%MACHINE%\ProdSW\*.*
|
||||
REM T:\COMMON\DOS\*.NEW
|
||||
REM
|
||||
REM Version: 1.3 - Fixed directory checks (use *.* not \NUL for DOS 6.22)
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 1: Verify machine name is set
|
||||
REM ==================================================================
|
||||
|
||||
IF NOT "%MACHINE%"=="" GOTO CHECK_DRIVE
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO.
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO.
|
||||
ECHO Set MACHINE in AUTOEXEC.BAT:
|
||||
ECHO SET MACHINE=TS-4R
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 2: Verify T: drive is accessible
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_DRIVE
|
||||
REM Verify T: drive is accessible
|
||||
REM DOS 6.22: Direct file test is most reliable
|
||||
IF NOT EXIST T:\*.* GOTO NO_T_DRIVE
|
||||
GOTO START_CHECK
|
||||
|
||||
:NO_T_DRIVE
|
||||
C:
|
||||
ECHO.
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO.
|
||||
ECHO Run: C:\STARTNET.BAT
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 3: Display check banner
|
||||
REM ==================================================================
|
||||
|
||||
:START_CHECK
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Update Check: %MACHINE%
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Initialize flags (no counters - not critical for functionality)
|
||||
SET COMMON=
|
||||
SET MACHINEFILES=
|
||||
SET SYSFILE=
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 4: Check COMMON batch files
|
||||
REM ==================================================================
|
||||
|
||||
ECHO [1/3] Checking T:\COMMON\ProdSW for batch file updates...
|
||||
|
||||
REM DOS 6.22: Check for files, not directory with \NUL
|
||||
IF NOT EXIST T:\COMMON\ProdSW\*.* GOTO NO_COMMON
|
||||
|
||||
REM Check for files on network
|
||||
FOR %%F IN (T:\COMMON\ProdSW\*.BAT) DO CALL :CHECK_COMMON_FILE %%F
|
||||
|
||||
IF "%COMMON%"=="" ECHO [OK] No updates in COMMON
|
||||
IF NOT "%COMMON%"=="" ECHO [FOUND] Updates available in COMMON
|
||||
|
||||
ECHO.
|
||||
GOTO CHECK_MACHINE
|
||||
|
||||
:NO_COMMON
|
||||
ECHO [SKIP] T:\COMMON\ProdSW not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 5: Check machine-specific files
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_MACHINE
|
||||
ECHO [2/3] Checking T:\%MACHINE%\ProdSW for machine-specific updates...
|
||||
|
||||
REM DOS 6.22: Check for files, not directory with \NUL
|
||||
IF NOT EXIST T:\%MACHINE%\ProdSW\*.* GOTO NO_MACHINE_DIR
|
||||
|
||||
REM Check for any files (BAT, EXE, DAT)
|
||||
FOR %%F IN (T:\%MACHINE%\ProdSW\*.*) DO CALL :COUNT_FILE
|
||||
|
||||
IF "%MACHINEFILES%"=="" ECHO [OK] No updates for %MACHINE%
|
||||
IF NOT "%MACHINEFILES%"=="" ECHO [FOUND] Updates available for %MACHINE%
|
||||
|
||||
ECHO.
|
||||
GOTO CHECK_SYSTEM
|
||||
|
||||
:NO_MACHINE_DIR
|
||||
ECHO [SKIP] T:\%MACHINE%\ProdSW not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 6: Check system file updates
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_SYSTEM
|
||||
ECHO [3/3] Checking T:\COMMON\DOS for system file updates...
|
||||
|
||||
REM DOS 6.22: Check for files, not directory with \NUL
|
||||
IF NOT EXIST T:\COMMON\DOS\*.* GOTO NO_DOS_DIR
|
||||
|
||||
REM Check for .NEW files
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW SET SYSFILE=FOUND
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW ECHO [FOUND] AUTOEXEC.NEW (system reboot required)
|
||||
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW SET SYSFILE=FOUND
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW ECHO [FOUND] CONFIG.NEW (system reboot required)
|
||||
|
||||
IF "%SYSFILE%"=="" ECHO [OK] No system file updates
|
||||
|
||||
ECHO.
|
||||
GOTO SHOW_SUMMARY
|
||||
|
||||
:NO_DOS_DIR
|
||||
ECHO [SKIP] T:\COMMON\DOS not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 7: Show summary and recommendations
|
||||
REM ==================================================================
|
||||
|
||||
:SHOW_SUMMARY
|
||||
REM Determine if any updates found
|
||||
SET HASUPDATES=
|
||||
IF NOT "%COMMON%"=="" SET HASUPDATES=YES
|
||||
IF NOT "%MACHINEFILES%"=="" SET HASUPDATES=YES
|
||||
IF NOT "%SYSFILE%"=="" SET HASUPDATES=YES
|
||||
|
||||
ECHO ==============================================================
|
||||
ECHO Update Summary
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Available updates:
|
||||
IF NOT "%COMMON%"=="" ECHO [FOUND] Common batch files
|
||||
IF "%COMMON%"=="" ECHO [OK] Common batch files
|
||||
IF NOT "%MACHINEFILES%"=="" ECHO [FOUND] Machine-specific files
|
||||
IF "%MACHINEFILES%"=="" ECHO [OK] Machine-specific files
|
||||
IF NOT "%SYSFILE%"=="" ECHO [FOUND] System files
|
||||
IF "%SYSFILE%"=="" ECHO [OK] System files
|
||||
ECHO.
|
||||
|
||||
REM Provide recommendation
|
||||
IF "%HASUPDATES%"=="" GOTO NO_UPDATES_AVAILABLE
|
||||
|
||||
ECHO Recommendation:
|
||||
ECHO Run NWTOC to download and install updates
|
||||
ECHO.
|
||||
IF NOT "%SYSFILE%"=="" ECHO [WARNING] System file updates will require reboot
|
||||
IF NOT "%SYSFILE%"=="" ECHO.
|
||||
|
||||
GOTO END
|
||||
|
||||
:NO_UPDATES_AVAILABLE
|
||||
ECHO Status: All files are up to date
|
||||
ECHO.
|
||||
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM HELPER SUBROUTINES
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_COMMON_FILE
|
||||
REM Check if network file is newer than local file
|
||||
REM %1 = network file path (e.g., T:\COMMON\ProdSW\NWTOC.BAT)
|
||||
|
||||
REM Extract filename from path
|
||||
SET NETFILE=%1
|
||||
SET FILENAME=%~nx1
|
||||
|
||||
REM Check if local file exists
|
||||
IF NOT EXIST C:\BAT\%FILENAME% SET COMMON=FOUND
|
||||
IF NOT EXIST C:\BAT\%FILENAME% GOTO CHECK_COMMON_DONE
|
||||
|
||||
REM Both files exist - network file available
|
||||
REM NOTE: DOS 6.22 cannot easily compare file dates
|
||||
REM We just check if network file exists (already confirmed above)
|
||||
SET COMMON=FOUND
|
||||
|
||||
:CHECK_COMMON_DONE
|
||||
GOTO END_SUBROUTINE
|
||||
|
||||
:COUNT_FILE
|
||||
REM Flag that machine-specific files exist
|
||||
SET MACHINEFILES=FOUND
|
||||
GOTO END_SUBROUTINE
|
||||
|
||||
:END_SUBROUTINE
|
||||
REM Return point for all subroutines (replaces :EOF)
|
||||
|
||||
REM ==================================================================
|
||||
REM CLEANUP AND EXIT
|
||||
REM ==================================================================
|
||||
|
||||
:END
|
||||
REM Clean up environment variables
|
||||
SET COMMON=
|
||||
SET MACHINEFILES=
|
||||
SET SYSFILE=
|
||||
SET HASUPDATES=
|
||||
SET NETFILE=
|
||||
SET FILENAME=
|
||||
@ECHO OFF
|
||||
REM CHECKUPD.BAT - Check for available updates without applying them
|
||||
REM Quick status check to see if network has newer files
|
||||
REM
|
||||
REM Usage: CHECKUPD
|
||||
REM
|
||||
REM Checks these sources:
|
||||
REM T:\COMMON\ProdSW\*.bat
|
||||
REM T:\%MACHINE%\ProdSW\*.*
|
||||
REM T:\COMMON\DOS\*.NEW
|
||||
REM
|
||||
REM Version: 1.3 - Removed %~nx1 syntax for DOS 6.22 compatibility
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 1: Verify machine name is set
|
||||
REM ==================================================================
|
||||
|
||||
IF NOT "%MACHINE%"=="" GOTO CHECK_DRIVE
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO.
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO.
|
||||
ECHO Set MACHINE in AUTOEXEC.BAT:
|
||||
ECHO SET MACHINE=TS-4R
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 2: Verify T: drive is accessible
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_DRIVE
|
||||
REM Verify T: drive is accessible
|
||||
REM DOS 6.22: Direct file test is most reliable
|
||||
IF NOT EXIST T:\*.* GOTO NO_T_DRIVE
|
||||
GOTO START_CHECK
|
||||
|
||||
:NO_T_DRIVE
|
||||
C:
|
||||
ECHO.
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO.
|
||||
ECHO Run: C:\STARTNET.BAT
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 3: Display check banner
|
||||
REM ==================================================================
|
||||
|
||||
:START_CHECK
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Update Check: %MACHINE%
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Initialize flags (no counters - not critical for functionality)
|
||||
SET COMMON=
|
||||
SET MACHINEFILES=
|
||||
SET SYSFILE=
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 4: Check COMMON batch files
|
||||
REM ==================================================================
|
||||
|
||||
ECHO [1/3] Checking T:\COMMON\ProdSW for batch file updates...
|
||||
|
||||
IF NOT EXIST T:\COMMON\ProdSW\NUL GOTO NO_COMMON
|
||||
|
||||
REM Check for files on network
|
||||
FOR %%F IN (T:\COMMON\ProdSW\*.BAT) DO CALL :CHECK_COMMON_FILE %%F
|
||||
|
||||
IF "%COMMON%"=="" ECHO [OK] No updates in COMMON
|
||||
IF NOT "%COMMON%"=="" ECHO [FOUND] Updates available in COMMON
|
||||
|
||||
ECHO.
|
||||
GOTO CHECK_MACHINE
|
||||
|
||||
:NO_COMMON
|
||||
ECHO [SKIP] T:\COMMON\ProdSW not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 5: Check machine-specific files
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_MACHINE
|
||||
ECHO [2/3] Checking T:\%MACHINE%\ProdSW for machine-specific updates...
|
||||
|
||||
IF NOT EXIST T:\%MACHINE%\ProdSW\NUL GOTO NO_MACHINE_DIR
|
||||
|
||||
REM Check for any files (BAT, EXE, DAT)
|
||||
FOR %%F IN (T:\%MACHINE%\ProdSW\*.*) DO CALL :COUNT_FILE
|
||||
|
||||
IF "%MACHINEFILES%"=="" ECHO [OK] No updates for %MACHINE%
|
||||
IF NOT "%MACHINEFILES%"=="" ECHO [FOUND] Updates available for %MACHINE%
|
||||
|
||||
ECHO.
|
||||
GOTO CHECK_SYSTEM
|
||||
|
||||
:NO_MACHINE_DIR
|
||||
ECHO [SKIP] T:\%MACHINE%\ProdSW not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 6: Check system file updates
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_SYSTEM
|
||||
ECHO [3/3] Checking T:\COMMON\DOS for system file updates...
|
||||
|
||||
IF NOT EXIST T:\COMMON\DOS\NUL GOTO NO_DOS_DIR
|
||||
|
||||
REM Check for .NEW files
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW SET SYSFILE=FOUND
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW ECHO [FOUND] AUTOEXEC.NEW (system reboot required)
|
||||
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW SET SYSFILE=FOUND
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW ECHO [FOUND] CONFIG.NEW (system reboot required)
|
||||
|
||||
IF "%SYSFILE%"=="" ECHO [OK] No system file updates
|
||||
|
||||
ECHO.
|
||||
GOTO SHOW_SUMMARY
|
||||
|
||||
:NO_DOS_DIR
|
||||
ECHO [SKIP] T:\COMMON\DOS not found
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 7: Show summary and recommendations
|
||||
REM ==================================================================
|
||||
|
||||
:SHOW_SUMMARY
|
||||
REM Determine if any updates found
|
||||
SET HASUPDATES=
|
||||
IF NOT "%COMMON%"=="" SET HASUPDATES=YES
|
||||
IF NOT "%MACHINEFILES%"=="" SET HASUPDATES=YES
|
||||
IF NOT "%SYSFILE%"=="" SET HASUPDATES=YES
|
||||
|
||||
ECHO ==============================================================
|
||||
ECHO Update Summary
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Available updates:
|
||||
IF NOT "%COMMON%"=="" ECHO [FOUND] Common batch files
|
||||
IF "%COMMON%"=="" ECHO [OK] Common batch files
|
||||
IF NOT "%MACHINEFILES%"=="" ECHO [FOUND] Machine-specific files
|
||||
IF "%MACHINEFILES%"=="" ECHO [OK] Machine-specific files
|
||||
IF NOT "%SYSFILE%"=="" ECHO [FOUND] System files
|
||||
IF "%SYSFILE%"=="" ECHO [OK] System files
|
||||
ECHO.
|
||||
|
||||
REM Provide recommendation
|
||||
IF "%HASUPDATES%"=="" GOTO NO_UPDATES_AVAILABLE
|
||||
|
||||
ECHO Recommendation:
|
||||
ECHO Run NWTOC to download and install updates
|
||||
ECHO.
|
||||
IF NOT "%SYSFILE%"=="" ECHO [WARNING] System file updates will require reboot
|
||||
IF NOT "%SYSFILE%"=="" ECHO.
|
||||
|
||||
GOTO END
|
||||
|
||||
:NO_UPDATES_AVAILABLE
|
||||
ECHO Status: All files are up to date
|
||||
ECHO.
|
||||
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM HELPER SUBROUTINES
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_COMMON_FILE
|
||||
REM Flag that network files exist (DOS 6.22 cannot extract filename from path)
|
||||
REM Simply mark updates as available if any network file is found
|
||||
SET COMMON=FOUND
|
||||
GOTO END_SUBROUTINE
|
||||
|
||||
:COUNT_FILE
|
||||
REM Flag that machine-specific files exist
|
||||
SET MACHINEFILES=FOUND
|
||||
GOTO END_SUBROUTINE
|
||||
|
||||
:END_SUBROUTINE
|
||||
REM Return point for all subroutines (replaces :EOF)
|
||||
|
||||
REM ==================================================================
|
||||
REM CLEANUP AND EXIT
|
||||
REM ==================================================================
|
||||
|
||||
:END
|
||||
REM Clean up environment variables
|
||||
SET COMMON=
|
||||
SET MACHINEFILES=
|
||||
SET SYSFILE=
|
||||
SET HASUPDATES=
|
||||
SET NETFILE=
|
||||
SET FILENAME=
|
||||
|
||||
@@ -1,268 +1,65 @@
|
||||
@ECHO OFF
|
||||
REM Computer to Network - Upload local changes and test data to network
|
||||
REM Programs: C:\BAT -> T:\COMMON\ProdSW or T:\%MACHINE%\ProdSW
|
||||
REM Test data: C:\ATE -> T:\%MACHINE%\LOGS (for database import)
|
||||
REM Version: 2.1 - Fixed drive test for DOS 6.22 reliability
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM Verify MACHINE environment variable is set
|
||||
IF NOT "%MACHINE%"=="" GOTO CHECK_DRIVE
|
||||
|
||||
ECHO.
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO.
|
||||
ECHO MACHINE must be set in AUTOEXEC.BAT
|
||||
ECHO Run DEPLOY.BAT to configure this machine
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:CHECK_DRIVE
|
||||
REM Verify T: drive is accessible
|
||||
REM DOS 6.22: Direct file test is most reliable
|
||||
IF NOT EXIST T:\*.* GOTO NO_T_DRIVE
|
||||
GOTO CHECK_TARGET
|
||||
|
||||
:NO_T_DRIVE
|
||||
C:
|
||||
ECHO.
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO.
|
||||
ECHO Network drive must be mapped to \\D2TESTNAS\test
|
||||
ECHO Run: C:\STARTNET.BAT
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:CHECK_TARGET
|
||||
REM Default target is machine-specific
|
||||
SET TARGET=MACHINE
|
||||
SET TARGETDIR=T:\%MACHINE%\ProdSW
|
||||
SET LOGSDIR=T:\%MACHINE%\LOGS
|
||||
|
||||
REM Check for COMMON parameter
|
||||
IF "%1"=="COMMON" SET TARGET=COMMON
|
||||
IF "%1"=="common" SET TARGET=COMMON
|
||||
IF "%1"=="Common" SET TARGET=COMMON
|
||||
|
||||
IF "%TARGET%"=="COMMON" SET TARGETDIR=T:\COMMON\ProdSW
|
||||
|
||||
REM Confirm COMMON upload (affects all machines)
|
||||
IF NOT "%TARGET%"=="COMMON" GOTO DISPLAY_BANNER
|
||||
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO [WARNING] COMMON Upload Confirmation
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO You are about to upload files to COMMON location
|
||||
ECHO This will affect ALL DOS machines at Dataforth
|
||||
ECHO.
|
||||
ECHO Other machines will receive these files on next reboot
|
||||
ECHO.
|
||||
ECHO Continue? (Y/N)
|
||||
ECHO.
|
||||
|
||||
REM Wait for user input (DOS 6.22 compatible)
|
||||
CHOICE /C:YN /N
|
||||
IF ERRORLEVEL 2 GOTO UPLOAD_CANCELLED
|
||||
IF ERRORLEVEL 1 GOTO DISPLAY_BANNER
|
||||
|
||||
:UPLOAD_CANCELLED
|
||||
ECHO.
|
||||
ECHO [INFO] Upload cancelled
|
||||
ECHO.
|
||||
ECHO To upload to machine-specific location, run: CTONW
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:DISPLAY_BANNER
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Upload: %MACHINE% to Network
|
||||
ECHO ==============================================================
|
||||
ECHO Source: C:\BAT, C:\ATE
|
||||
IF "%TARGET%"=="COMMON" ECHO Target: %TARGETDIR%
|
||||
IF "%TARGET%"=="MACHINE" ECHO Targets: %TARGETDIR% (programs)
|
||||
IF "%TARGET%"=="MACHINE" ECHO %LOGSDIR% (test data)
|
||||
ECHO Target type: %TARGET%
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Verify source directories exist
|
||||
IF NOT EXIST C:\BAT\*.* GOTO NO_BAT_DIR
|
||||
GOTO CHECK_TARGET_DIR
|
||||
|
||||
:NO_BAT_DIR
|
||||
ECHO [ERROR] C:\BAT directory not found
|
||||
ECHO No files to upload
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:CHECK_TARGET_DIR
|
||||
REM Create machine directory if uploading to machine-specific location
|
||||
IF "%TARGET%"=="MACHINE" IF NOT EXIST T:\%MACHINE%\*.* MD T:\%MACHINE%
|
||||
|
||||
REM Create ProdSW directory
|
||||
IF NOT EXIST %TARGETDIR%\*.* MD %TARGETDIR%
|
||||
|
||||
REM Verify ProdSW directory was created
|
||||
IF NOT EXIST %TARGETDIR%\*.* GOTO TARGET_DIR_ERROR
|
||||
|
||||
ECHO [OK] Target directory ready: %TARGETDIR%
|
||||
|
||||
REM Create LOGS directory for machine-specific uploads
|
||||
IF "%TARGET%"=="MACHINE" IF NOT EXIST %LOGSDIR%\*.* MD %LOGSDIR%
|
||||
IF "%TARGET%"=="MACHINE" IF NOT EXIST %LOGSDIR%\*.* GOTO LOGS_DIR_ERROR
|
||||
IF "%TARGET%"=="MACHINE" ECHO [OK] Logs directory ready: %LOGSDIR%
|
||||
|
||||
ECHO.
|
||||
|
||||
:UPLOAD_BATCH_FILES
|
||||
ECHO [1/3] Uploading batch files from C:\BAT...
|
||||
|
||||
REM Backup existing files on network before overwriting
|
||||
ECHO Creating backups on network (.BAK files)...
|
||||
FOR %%F IN (%TARGETDIR%\*.BAT) DO COPY %%F %%~dpnF.BAK >NUL 2>NUL
|
||||
|
||||
REM Copy batch files to network
|
||||
ECHO Copying files to %TARGETDIR%...
|
||||
XCOPY C:\BAT\*.BAT %TARGETDIR%\ /Y
|
||||
IF ERRORLEVEL 4 GOTO UPLOAD_ERROR_INIT
|
||||
IF ERRORLEVEL 2 GOTO UPLOAD_ERROR_USER
|
||||
IF ERRORLEVEL 1 ECHO [WARNING] No batch files found in C:\BAT
|
||||
IF NOT ERRORLEVEL 1 ECHO [OK] Batch files uploaded
|
||||
|
||||
ECHO.
|
||||
|
||||
:UPLOAD_PROGRAMS
|
||||
REM Skip programs for COMMON target (batch files only)
|
||||
IF "%TARGET%"=="COMMON" GOTO SKIP_PROGRAMS
|
||||
|
||||
ECHO [2/3] Uploading programs and config from C:\ATE...
|
||||
|
||||
REM Check if ATE directory exists
|
||||
IF NOT EXIST C:\ATE\*.* GOTO NO_ATE_DIR
|
||||
|
||||
REM Copy programs (.EXE, .BAT, .CFG) - exclude DAT files (they go to LOGS)
|
||||
ECHO Copying programs to %TARGETDIR%...
|
||||
XCOPY C:\ATE\*.EXE %TARGETDIR%\ /S /Y >NUL 2>NUL
|
||||
XCOPY C:\ATE\*.BAT %TARGETDIR%\ /S /Y >NUL 2>NUL
|
||||
XCOPY C:\ATE\*.CFG %TARGETDIR%\ /S /Y >NUL 2>NUL
|
||||
XCOPY C:\ATE\*.TXT %TARGETDIR%\ /S /Y >NUL 2>NUL
|
||||
ECHO [OK] Programs uploaded to ProdSW
|
||||
|
||||
ECHO.
|
||||
GOTO UPLOAD_TEST_DATA
|
||||
|
||||
:NO_ATE_DIR
|
||||
ECHO [INFO] C:\ATE directory not found
|
||||
ECHO Only batch files were uploaded
|
||||
GOTO SKIP_TEST_DATA
|
||||
|
||||
:SKIP_PROGRAMS
|
||||
ECHO [2/3] Skipping programs/data (COMMON target only gets batch files)
|
||||
ECHO.
|
||||
GOTO SKIP_TEST_DATA
|
||||
|
||||
:UPLOAD_TEST_DATA
|
||||
ECHO [3/3] Uploading test data to LOGS...
|
||||
|
||||
REM Create log subdirectories
|
||||
IF NOT EXIST %LOGSDIR%\8BLOG\*.* MD %LOGSDIR%\8BLOG
|
||||
IF NOT EXIST %LOGSDIR%\DSCLOG\*.* MD %LOGSDIR%\DSCLOG
|
||||
IF NOT EXIST %LOGSDIR%\HVLOG\*.* MD %LOGSDIR%\HVLOG
|
||||
IF NOT EXIST %LOGSDIR%\PWRLOG\*.* MD %LOGSDIR%\PWRLOG
|
||||
IF NOT EXIST %LOGSDIR%\RMSLOG\*.* MD %LOGSDIR%\RMSLOG
|
||||
IF NOT EXIST %LOGSDIR%\7BLOG\*.* MD %LOGSDIR%\7BLOG
|
||||
|
||||
REM Upload test data files to appropriate log folders
|
||||
ECHO Uploading test data files...
|
||||
|
||||
REM 8-channel data: 8BDATA -> 8BLOG
|
||||
IF EXIST C:\ATE\8BDATA\*.* XCOPY C:\ATE\8BDATA\*.DAT %LOGSDIR%\8BLOG\ /Y >NUL 2>NUL
|
||||
|
||||
REM DSC data: DSCDATA -> DSCLOG
|
||||
IF EXIST C:\ATE\DSCDATA\*.* XCOPY C:\ATE\DSCDATA\*.DAT %LOGSDIR%\DSCLOG\ /Y >NUL 2>NUL
|
||||
|
||||
REM HV data: HVDATA -> HVLOG
|
||||
IF EXIST C:\ATE\HVDATA\*.* XCOPY C:\ATE\HVDATA\*.DAT %LOGSDIR%\HVLOG\ /Y >NUL 2>NUL
|
||||
|
||||
REM Power data: PWRDATA -> PWRLOG
|
||||
IF EXIST C:\ATE\PWRDATA\*.* XCOPY C:\ATE\PWRDATA\*.DAT %LOGSDIR%\PWRLOG\ /Y >NUL 2>NUL
|
||||
|
||||
REM RMS data: RMSDATA -> RMSLOG
|
||||
IF EXIST C:\ATE\RMSDATA\*.* XCOPY C:\ATE\RMSDATA\*.DAT %LOGSDIR%\RMSLOG\ /Y >NUL 2>NUL
|
||||
|
||||
REM 7-channel data: 7BDATA -> 7BLOG
|
||||
IF EXIST C:\ATE\7BDATA\*.* XCOPY C:\ATE\7BDATA\*.DAT %LOGSDIR%\7BLOG\ /Y >NUL 2>NUL
|
||||
|
||||
ECHO [OK] Test data uploaded to LOGS (for database import)
|
||||
|
||||
GOTO UPLOAD_COMPLETE
|
||||
|
||||
:SKIP_TEST_DATA
|
||||
REM No test data upload for COMMON target
|
||||
GOTO UPLOAD_COMPLETE
|
||||
|
||||
:UPLOAD_COMPLETE
|
||||
ECHO ==============================================================
|
||||
ECHO Upload Complete
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Files uploaded to:
|
||||
ECHO %TARGETDIR% (software/config)
|
||||
IF "%TARGET%"=="MACHINE" ECHO %LOGSDIR% (test data for database import)
|
||||
ECHO.
|
||||
IF "%TARGET%"=="COMMON" ECHO [WARNING] Files uploaded to COMMON - will affect ALL machines
|
||||
IF "%TARGET%"=="COMMON" ECHO Other machines will receive these files on next reboot
|
||||
ECHO.
|
||||
ECHO Backup files (.BAK) created on network
|
||||
ECHO.
|
||||
IF "%TARGET%"=="MACHINE" ECHO To share these files with all machines, run: CTONW COMMON
|
||||
ECHO.
|
||||
GOTO END
|
||||
|
||||
:TARGET_DIR_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Could not create target directory
|
||||
ECHO Target: %TARGETDIR%
|
||||
ECHO.
|
||||
ECHO Check: T: drive writable, sufficient disk space, stable network
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:LOGS_DIR_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Could not create LOGS directory
|
||||
ECHO Target: %LOGSDIR%
|
||||
ECHO.
|
||||
ECHO Check: T: drive writable, sufficient disk space, stable network
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:UPLOAD_ERROR_INIT
|
||||
ECHO.
|
||||
ECHO [ERROR] Upload initialization failed
|
||||
ECHO Possible causes: Insufficient memory, invalid path, or drive not accessible
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:UPLOAD_ERROR_USER
|
||||
ECHO.
|
||||
ECHO [ERROR] Upload terminated by user (Ctrl+C)
|
||||
ECHO Upload may be incomplete - run CTONW again
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
REM Clean up environment variables
|
||||
SET TARGET=
|
||||
SET TARGETDIR=
|
||||
SET LOGSDIR=
|
||||
@ECHO OFF
|
||||
REM Computer to Network - Upload local files to network
|
||||
REM Version: 2.5 - Added /I flag, removed 2>NUL (DOS 6.22)
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM Check MACHINE variable
|
||||
IF "%MACHINE%"=="" GOTO NO_MACHINE
|
||||
|
||||
REM Check T: drive
|
||||
IF NOT EXIST T:\*.* GOTO NO_DRIVE
|
||||
|
||||
REM Display banner
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Upload: %MACHINE% to Network
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Create target directories (ignore errors with >NUL)
|
||||
MD T:\%MACHINE% >NUL
|
||||
MD T:\%MACHINE%\ProdSW >NUL
|
||||
MD T:\%MACHINE%\LOGS >NUL
|
||||
|
||||
REM Copy batch files (XCOPY /Y /I = no prompts, assume directory)
|
||||
ECHO Copying C:\BAT\*.BAT to T:\%MACHINE%\ProdSW...
|
||||
XCOPY C:\BAT\*.BAT T:\%MACHINE%\ProdSW /Y /I >NUL
|
||||
ECHO [OK] Batch files copied
|
||||
ECHO.
|
||||
|
||||
REM Check for ATE directory
|
||||
IF NOT EXIST C:\ATE\*.* GOTO SKIP_ATE
|
||||
|
||||
REM Copy ATE files
|
||||
ECHO Copying C:\ATE files to T:\%MACHINE%\ProdSW...
|
||||
IF EXIST C:\ATE\*.EXE XCOPY C:\ATE\*.EXE T:\%MACHINE%\ProdSW /Y /I >NUL
|
||||
IF EXIST C:\ATE\*.DAT XCOPY C:\ATE\*.DAT T:\%MACHINE%\ProdSW /Y /I >NUL
|
||||
IF EXIST C:\ATE\*.CFG XCOPY C:\ATE\*.CFG T:\%MACHINE%\ProdSW /Y /I >NUL
|
||||
ECHO [OK] ATE files copied
|
||||
ECHO.
|
||||
GOTO DONE
|
||||
|
||||
:SKIP_ATE
|
||||
ECHO [INFO] No C:\ATE directory - skipping
|
||||
ECHO.
|
||||
|
||||
:DONE
|
||||
ECHO ==============================================================
|
||||
ECHO Upload Complete
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
GOTO END
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO Run DEPLOY.BAT first
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_DRIVE
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO Run C:\STARTNET.BAT first
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
|
||||
@@ -1,189 +1,87 @@
|
||||
@ECHO OFF
|
||||
REM One-time deployment script for DOS Update System
|
||||
REM Installs automatic update system on DOS 6.22 machines
|
||||
REM Usage: T:\COMMON\ProdSW\DEPLOY.BAT machine-name
|
||||
REM Example: T:\COMMON\ProdSW\DEPLOY.BAT TS-4R
|
||||
REM Version: 2.0 - Simplified deployment
|
||||
REM Last modified: 2026-01-19
|
||||
|
||||
CLS
|
||||
|
||||
REM Check machine name parameter provided
|
||||
IF "%1"=="" GOTO NO_MACHINE_NAME
|
||||
|
||||
REM Save machine name to variable
|
||||
SET MACHINE=%1
|
||||
|
||||
ECHO ==============================================================
|
||||
ECHO DOS Update System - Deployment
|
||||
ECHO ==============================================================
|
||||
ECHO Machine: %MACHINE%
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Installing automatic update system...
|
||||
ECHO.
|
||||
ECHO Files to install:
|
||||
ECHO - AUTOEXEC.BAT (startup configuration)
|
||||
ECHO - NWTOC.BAT (download updates)
|
||||
ECHO - CTONW.BAT (upload test data)
|
||||
ECHO - UPDATE.BAT (full backup)
|
||||
ECHO - CHECKUPD.BAT (check updates)
|
||||
ECHO - STAGE.BAT (system file updates)
|
||||
ECHO - REBOOT.BAT (apply staged updates)
|
||||
ECHO.
|
||||
PAUSE
|
||||
ECHO.
|
||||
|
||||
REM Create C:\BAT directory
|
||||
ECHO [1/3] Creating C:\BAT directory...
|
||||
IF NOT EXIST C:\BAT\*.* MD C:\BAT
|
||||
IF NOT EXIST C:\BAT\*.* GOTO BAT_DIR_ERROR
|
||||
ECHO [OK] C:\BAT directory ready
|
||||
ECHO.
|
||||
|
||||
REM Copy batch files from network to local machine
|
||||
ECHO [2/3] Copying batch files to C:\BAT...
|
||||
XCOPY T:\COMMON\ProdSW\NWTOC.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] NWTOC.BAT
|
||||
|
||||
XCOPY T:\COMMON\ProdSW\CTONW.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] CTONW.BAT
|
||||
|
||||
XCOPY T:\COMMON\ProdSW\UPDATE.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] UPDATE.BAT
|
||||
|
||||
XCOPY T:\COMMON\ProdSW\CHECKUPD.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] CHECKUPD.BAT
|
||||
|
||||
XCOPY T:\COMMON\ProdSW\STAGE.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] STAGE.BAT
|
||||
|
||||
XCOPY T:\COMMON\ProdSW\REBOOT.BAT C:\BAT\ /Y
|
||||
IF ERRORLEVEL 4 GOTO COPY_ERROR
|
||||
ECHO [OK] REBOOT.BAT
|
||||
|
||||
ECHO [OK] All batch files installed
|
||||
ECHO.
|
||||
|
||||
REM Install AUTOEXEC.BAT with machine name
|
||||
ECHO [3/3] Installing AUTOEXEC.BAT...
|
||||
|
||||
REM Copy template and modify machine name
|
||||
COPY T:\COMMON\ProdSW\AUTOEXEC.BAT C:\AUTOEXEC.TMP /Y >NUL
|
||||
IF ERRORLEVEL 1 GOTO AUTOEXEC_ERROR
|
||||
|
||||
REM Create new AUTOEXEC with correct machine name
|
||||
REM Filter out existing SET MACHINE line and rebuild with new one
|
||||
ECHO @ECHO OFF > C:\AUTOEXEC.BAT
|
||||
TYPE C:\AUTOEXEC.TMP | FIND /V "@ECHO OFF" | FIND /V "SET MACHINE=" > C:\AUTOEXEC.TM1
|
||||
ECHO REM Dataforth Test Machine Startup - DOS 6.22 >> C:\AUTOEXEC.BAT
|
||||
ECHO REM Automatically runs after CONFIG.SYS during boot >> C:\AUTOEXEC.BAT
|
||||
ECHO REM Version: 3.0 - Auto-update system integrated >> C:\AUTOEXEC.BAT
|
||||
ECHO REM Last modified: 2026-01-19 >> C:\AUTOEXEC.BAT
|
||||
ECHO. >> C:\AUTOEXEC.BAT
|
||||
ECHO REM Set machine identity (configured by DEPLOY.BAT) >> C:\AUTOEXEC.BAT
|
||||
ECHO SET MACHINE=%MACHINE% >> C:\AUTOEXEC.BAT
|
||||
ECHO. >> C:\AUTOEXEC.BAT
|
||||
REM Filter out header comment lines using temp files (DOS 6.22 compatible)
|
||||
TYPE C:\AUTOEXEC.TM1 | FIND /V "REM Dataforth" > C:\AUTOEXEC.TM2
|
||||
TYPE C:\AUTOEXEC.TM2 | FIND /V "REM Automatically" > C:\AUTOEXEC.TM3
|
||||
TYPE C:\AUTOEXEC.TM3 | FIND /V "REM Version:" > C:\AUTOEXEC.TM4
|
||||
TYPE C:\AUTOEXEC.TM4 | FIND /V "REM Last modified" > C:\AUTOEXEC.TM5
|
||||
TYPE C:\AUTOEXEC.TM5 | FIND /V "REM Set machine identity" >> C:\AUTOEXEC.BAT
|
||||
|
||||
REM Clean up temp files
|
||||
DEL C:\AUTOEXEC.TMP
|
||||
DEL C:\AUTOEXEC.TM1
|
||||
DEL C:\AUTOEXEC.TM2
|
||||
DEL C:\AUTOEXEC.TM3
|
||||
DEL C:\AUTOEXEC.TM4
|
||||
DEL C:\AUTOEXEC.TM5
|
||||
|
||||
ECHO [OK] AUTOEXEC.BAT installed with MACHINE=%MACHINE%
|
||||
ECHO.
|
||||
|
||||
REM Create machine folder on network for backups
|
||||
IF NOT EXIST T:\%MACHINE%\*.* MD T:\%MACHINE%
|
||||
IF NOT EXIST T:\%MACHINE%\*.* GOTO MACHINE_FOLDER_WARNING
|
||||
ECHO [OK] Network backup folder created: T:\%MACHINE%
|
||||
ECHO.
|
||||
GOTO DEPLOYMENT_COMPLETE
|
||||
|
||||
:MACHINE_FOLDER_WARNING
|
||||
ECHO [WARNING] Could not create T:\%MACHINE% folder
|
||||
ECHO Backups will not work until this folder exists
|
||||
ECHO.
|
||||
|
||||
:DEPLOYMENT_COMPLETE
|
||||
CLS
|
||||
ECHO ==============================================================
|
||||
ECHO Deployment Complete!
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Machine: %MACHINE%
|
||||
ECHO.
|
||||
ECHO The automatic update system is now installed.
|
||||
ECHO.
|
||||
ECHO What happens on next reboot:
|
||||
ECHO 1. Network client starts (C:\STARTNET.BAT)
|
||||
ECHO 2. Software updates download automatically (NWTOC)
|
||||
ECHO 3. Test data uploads automatically (CTONW)
|
||||
ECHO 4. System ready for testing
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO REBOOT NOW
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Press Ctrl+Alt+Del to reboot
|
||||
ECHO.
|
||||
ECHO After reboot, the system will be fully operational.
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_MACHINE_NAME
|
||||
ECHO.
|
||||
ECHO [ERROR] Machine name not provided
|
||||
ECHO.
|
||||
ECHO Usage: DEPLOY.BAT machine-name
|
||||
ECHO Example: DEPLOY.BAT TS-4R
|
||||
ECHO.
|
||||
ECHO Machine name must match network folder (T:\machine-name\)
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:BAT_DIR_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Could not create C:\BAT directory
|
||||
ECHO Insufficient permissions or disk full
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:COPY_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Failed to copy files from network
|
||||
ECHO.
|
||||
ECHO Check: T: drive accessible, C: drive has space
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:AUTOEXEC_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Could not copy AUTOEXEC.BAT template
|
||||
ECHO.
|
||||
ECHO Verify T:\COMMON\ProdSW\AUTOEXEC.BAT exists
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
REM Clean up environment variable
|
||||
SET MACHINE=
|
||||
@ECHO OFF
|
||||
REM One-time deployment script for DOS Update System
|
||||
REM Usage: T:\COMMON\ProdSW\DEPLOY.BAT machine-name
|
||||
REM Version: 2.3 - Removed 2>NUL (DOS 6.22 only supports >NUL)
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
CLS
|
||||
|
||||
REM Check machine name parameter
|
||||
IF "%1"=="" GOTO NO_MACHINE
|
||||
|
||||
REM Save machine name
|
||||
SET MACHINE=%1
|
||||
|
||||
ECHO ==============================================================
|
||||
ECHO DOS Update System - Deployment
|
||||
ECHO ==============================================================
|
||||
ECHO Machine: %MACHINE%
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Press any key to install...
|
||||
PAUSE >NUL
|
||||
ECHO.
|
||||
|
||||
REM Create directories (ignore errors with >NUL)
|
||||
MD C:\BAT >NUL
|
||||
MD T:\%MACHINE% >NUL
|
||||
|
||||
ECHO [1/2] Copying batch files to C:\BAT...
|
||||
XCOPY T:\COMMON\ProdSW\NWTOC.BAT C:\BAT /Y >NUL
|
||||
XCOPY T:\COMMON\ProdSW\CTONW.BAT C:\BAT /Y >NUL
|
||||
XCOPY T:\COMMON\ProdSW\UPDATE.BAT C:\BAT /Y >NUL
|
||||
XCOPY T:\COMMON\ProdSW\CHECKUPD.BAT C:\BAT /Y >NUL
|
||||
XCOPY T:\COMMON\ProdSW\STAGE.BAT C:\BAT /Y >NUL
|
||||
XCOPY T:\COMMON\ProdSW\REBOOT.BAT C:\BAT /Y >NUL
|
||||
ECHO [OK] Batch files installed
|
||||
ECHO.
|
||||
|
||||
ECHO [2/2] Installing AUTOEXEC.BAT...
|
||||
REM Create AUTOEXEC.BAT with machine name
|
||||
ECHO @ECHO OFF > C:\AUTOEXEC.BAT
|
||||
ECHO REM Dataforth Test Machine - DOS 6.22 >> C:\AUTOEXEC.BAT
|
||||
ECHO SET MACHINE=%MACHINE% >> C:\AUTOEXEC.BAT
|
||||
ECHO SET PATH=C:\DOS;C:\NET;C:\BAT;C:\BATCH;C:\ >> C:\AUTOEXEC.BAT
|
||||
ECHO PROMPT $P$G >> C:\AUTOEXEC.BAT
|
||||
ECHO SET TEMP=C:\TEMP >> C:\AUTOEXEC.BAT
|
||||
ECHO SET TMP=C:\TEMP >> C:\AUTOEXEC.BAT
|
||||
ECHO MD C:\TEMP >NUL >> C:\AUTOEXEC.BAT
|
||||
ECHO CLS >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO. >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO Dataforth Test Machine: %MACHINE% >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO. >> C:\AUTOEXEC.BAT
|
||||
ECHO IF EXIST C:\STARTNET.BAT CALL C:\STARTNET.BAT >> C:\AUTOEXEC.BAT
|
||||
ECHO IF NOT EXIST T:\*.* GOTO NONET >> C:\AUTOEXEC.BAT
|
||||
ECHO IF EXIST C:\BAT\NWTOC.BAT CALL C:\BAT\NWTOC.BAT >> C:\AUTOEXEC.BAT
|
||||
ECHO IF EXIST C:\BAT\CTONW.BAT CALL C:\BAT\CTONW.BAT >> C:\AUTOEXEC.BAT
|
||||
ECHO GOTO READY >> C:\AUTOEXEC.BAT
|
||||
ECHO :NONET >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO [ERROR] Network not available >> C:\AUTOEXEC.BAT
|
||||
ECHO :READY >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO. >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO System Ready >> C:\AUTOEXEC.BAT
|
||||
ECHO ECHO. >> C:\AUTOEXEC.BAT
|
||||
ECHO CD \ATE >> C:\AUTOEXEC.BAT
|
||||
ECHO menux >> C:\AUTOEXEC.BAT
|
||||
ECHO [OK] AUTOEXEC.BAT installed with MACHINE=%MACHINE%
|
||||
ECHO.
|
||||
|
||||
ECHO ==============================================================
|
||||
ECHO Deployment Complete - REBOOT NOW
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO.
|
||||
ECHO [ERROR] Machine name not provided
|
||||
ECHO.
|
||||
ECHO Usage: DEPLOY.BAT machine-name
|
||||
ECHO Example: DEPLOY.BAT TS-4R
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
SET MACHINE=
|
||||
|
||||
@@ -1,208 +1,86 @@
|
||||
@ECHO OFF
|
||||
REM Network to Computer - Download software updates from network to local C: drive
|
||||
REM Updates: T:\COMMON\ProdSW -> C:\BAT, T:\%MACHINE%\ProdSW -> C:\BAT and C:\ATE
|
||||
REM Version: 2.5 - Replaced XCOPY with simple COPY (more reliable in DOS 6.22)
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM Verify MACHINE environment variable is set
|
||||
IF NOT "%MACHINE%"=="" GOTO CHECK_DRIVE
|
||||
|
||||
ECHO.
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO.
|
||||
ECHO MACHINE must be set in AUTOEXEC.BAT
|
||||
ECHO Run DEPLOY.BAT to configure this machine
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:CHECK_DRIVE
|
||||
REM Verify T: drive is accessible
|
||||
REM DOS 6.22: Direct file test is most reliable
|
||||
IF NOT EXIST T:\*.* GOTO NO_T_DRIVE
|
||||
GOTO START_UPDATE
|
||||
|
||||
:NO_T_DRIVE
|
||||
C:
|
||||
ECHO.
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO.
|
||||
ECHO Network drive must be mapped to \\D2TESTNAS\test
|
||||
ECHO Run: C:\STARTNET.BAT
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:START_UPDATE
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Download Updates: %MACHINE% from Network
|
||||
ECHO ==============================================================
|
||||
ECHO Source: T:\COMMON and T:\%MACHINE%
|
||||
ECHO Target: C:\BAT, C:\ATE, C:\NET
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Verify update directories exist on network
|
||||
REM DOS 6.22: Check for files in ProdSW, not empty COMMON directory
|
||||
IF NOT EXIST T:\COMMON\ProdSW\*.* GOTO NO_PRODSW
|
||||
|
||||
REM Machine-specific directory is optional
|
||||
IF NOT EXIST T:\%MACHINE%\*.* GOTO SKIP_MACHINE_CHECK
|
||||
IF NOT EXIST T:\%MACHINE%\ProdSW\*.* GOTO SKIP_MACHINE_CHECK
|
||||
GOTO UPDATE_BATCH_FILES
|
||||
|
||||
:NO_PRODSW
|
||||
ECHO [ERROR] T:\COMMON\ProdSW directory not found
|
||||
ECHO Update directory is missing
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:SKIP_MACHINE_CHECK
|
||||
ECHO [INFO] T:\%MACHINE%\ProdSW not found - skipping machine-specific updates
|
||||
ECHO.
|
||||
|
||||
:UPDATE_BATCH_FILES
|
||||
ECHO [1/4] Updating batch files from T:\COMMON\ProdSW...
|
||||
|
||||
REM Create C:\BAT directory if needed
|
||||
IF NOT EXIST C:\BAT\*.* MD C:\BAT
|
||||
|
||||
REM Backup existing batch files before update
|
||||
ECHO Creating backups (.BAK files)...
|
||||
FOR %%F IN (C:\BAT\*.BAT) DO COPY %%F %%~dpnF.BAK >NUL 2>NUL
|
||||
|
||||
REM Copy batch files from COMMON (simple COPY, not XCOPY)
|
||||
ECHO Copying updated files...
|
||||
COPY T:\COMMON\ProdSW\*.BAT C:\BAT /Y >NUL
|
||||
IF ERRORLEVEL 1 GOTO UPDATE_ERROR_INIT
|
||||
ECHO [OK] Batch files updated from COMMON
|
||||
|
||||
ECHO.
|
||||
|
||||
:UPDATE_MACHINE_FILES
|
||||
ECHO [2/4] Updating machine-specific files from T:\%MACHINE%\ProdSW...
|
||||
|
||||
REM Check if machine-specific directory exists
|
||||
IF NOT EXIST T:\%MACHINE%\ProdSW\*.* GOTO SKIP_MACHINE_FILES
|
||||
|
||||
REM Create directories if needed
|
||||
IF NOT EXIST C:\BAT\*.* MD C:\BAT
|
||||
IF NOT EXIST C:\ATE\*.* MD C:\ATE
|
||||
|
||||
REM Copy batch files
|
||||
ECHO Copying batch files to C:\BAT...
|
||||
FOR %%F IN (T:\%MACHINE%\ProdSW\*.BAT) DO COPY %%F C:\BAT\ /Y >NUL 2>NUL
|
||||
IF NOT ERRORLEVEL 1 ECHO [OK] Machine-specific batch files updated
|
||||
|
||||
REM Copy executables
|
||||
ECHO Copying programs to C:\ATE...
|
||||
FOR %%F IN (T:\%MACHINE%\ProdSW\*.EXE) DO COPY %%F C:\ATE\ /Y >NUL 2>NUL
|
||||
IF NOT ERRORLEVEL 1 ECHO [OK] Machine-specific programs updated
|
||||
|
||||
REM Copy data files
|
||||
ECHO Copying data files to C:\ATE...
|
||||
FOR %%F IN (T:\%MACHINE%\ProdSW\*.DAT) DO COPY %%F C:\ATE\ /Y >NUL 2>NUL
|
||||
IF NOT ERRORLEVEL 1 ECHO [OK] Machine-specific data files updated
|
||||
|
||||
GOTO CHECK_SYSTEM_FILES
|
||||
|
||||
:SKIP_MACHINE_FILES
|
||||
ECHO [SKIP] No machine-specific directory
|
||||
ECHO.
|
||||
|
||||
:CHECK_SYSTEM_FILES
|
||||
ECHO [3/4] Checking for system file updates...
|
||||
|
||||
REM Check if DOS directory exists on network
|
||||
IF NOT EXIST T:\COMMON\DOS\*.* GOTO NO_SYSTEM_FILES
|
||||
|
||||
REM Check for AUTOEXEC.NEW or CONFIG.NEW
|
||||
SET SYSUPD=0
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW SET SYSUPD=1
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW SET SYSUPD=1
|
||||
|
||||
REM If no system updates, continue to network files
|
||||
IF "%SYSUPD%"=="0" GOTO NO_SYSTEM_FILES
|
||||
|
||||
REM System files need updating - stage them for reboot
|
||||
ECHO [FOUND] System file updates available
|
||||
ECHO Staging AUTOEXEC.BAT and/or CONFIG.SYS updates...
|
||||
ECHO.
|
||||
|
||||
IF EXIST T:\COMMON\DOS\AUTOEXEC.NEW COPY T:\COMMON\DOS\AUTOEXEC.NEW C:\AUTOEXEC.NEW >NUL
|
||||
IF EXIST T:\COMMON\DOS\CONFIG.NEW COPY T:\COMMON\DOS\CONFIG.NEW C:\CONFIG.NEW >NUL
|
||||
|
||||
REM Call staging script if it exists
|
||||
IF EXIST C:\BAT\STAGE.BAT GOTO CALL_STAGE
|
||||
|
||||
ECHO [WARNING] C:\BAT\STAGE.BAT not found
|
||||
ECHO System files copied to C:\AUTOEXEC.NEW and C:\CONFIG.NEW
|
||||
ECHO Manually copy these files after reboot
|
||||
ECHO.
|
||||
GOTO UPDATE_COMPLETE
|
||||
|
||||
:CALL_STAGE
|
||||
CALL C:\BAT\STAGE.BAT
|
||||
GOTO END
|
||||
|
||||
:NO_SYSTEM_FILES
|
||||
ECHO [OK] No system file updates
|
||||
ECHO.
|
||||
|
||||
:CHECK_NET_FILES
|
||||
ECHO [4/4] Checking for network client updates...
|
||||
|
||||
REM Check if NET directory exists on network
|
||||
IF NOT EXIST T:\COMMON\NET\*.* GOTO NO_NET_FILES
|
||||
|
||||
REM Backup network client files
|
||||
ECHO Creating backups of C:\NET\...
|
||||
FOR %%F IN (C:\NET\*.DOS) DO COPY %%F %%~dpnF.BAK >NUL 2>NUL
|
||||
|
||||
REM Copy network files (simple COPY, not XCOPY)
|
||||
ECHO Copying updated network files...
|
||||
COPY T:\COMMON\NET\*.* C:\NET /Y >NUL
|
||||
IF NOT ERRORLEVEL 1 ECHO [OK] Network client files updated
|
||||
GOTO UPDATE_COMPLETE
|
||||
|
||||
:NO_NET_FILES
|
||||
ECHO [OK] No network client updates
|
||||
ECHO.
|
||||
|
||||
:UPDATE_COMPLETE
|
||||
ECHO ==============================================================
|
||||
ECHO Update Complete
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
ECHO Files updated from:
|
||||
ECHO T:\COMMON\ProdSW -> C:\BAT
|
||||
ECHO T:\%MACHINE%\ProdSW -> C:\BAT and C:\ATE
|
||||
ECHO.
|
||||
ECHO Backup files (.BAK) created in C:\BAT
|
||||
ECHO.
|
||||
IF "%SYSUPD%"=="1" ECHO [WARNING] Reboot required to apply system changes
|
||||
IF "%SYSUPD%"=="1" ECHO Run REBOOT or press Ctrl+Alt+Del
|
||||
ECHO.
|
||||
GOTO END
|
||||
|
||||
:UPDATE_ERROR_INIT
|
||||
ECHO.
|
||||
ECHO [ERROR] Update initialization failed
|
||||
ECHO Possible causes: Insufficient memory, invalid path, or drive not accessible
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:UPDATE_ERROR_USER
|
||||
ECHO.
|
||||
ECHO [ERROR] Update terminated by user (Ctrl+C)
|
||||
ECHO Update may be incomplete - run NWTOC again
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
REM Clean up environment variables
|
||||
SET SYSUPD=
|
||||
@ECHO OFF
|
||||
REM Network to Computer - Download software updates from network to local C: drive
|
||||
REM Version: 2.8 - Added /I flag, removed 2>NUL (DOS 6.22)
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM Check MACHINE variable
|
||||
IF "%MACHINE%"=="" GOTO NO_MACHINE
|
||||
|
||||
REM Check T: drive
|
||||
IF NOT EXIST T:\*.* GOTO NO_DRIVE
|
||||
|
||||
REM Display banner
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Download Updates: %MACHINE% from Network
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
|
||||
REM Create local directories (ignore errors with >NUL)
|
||||
MD C:\BAT >NUL
|
||||
MD C:\ATE >NUL
|
||||
MD C:\NET >NUL
|
||||
|
||||
REM Check for COMMON updates
|
||||
IF NOT EXIST T:\COMMON\ProdSW\*.* GOTO NO_COMMON
|
||||
|
||||
ECHO [1/3] Copying from T:\COMMON\ProdSW to C:\BAT...
|
||||
XCOPY T:\COMMON\ProdSW\*.BAT C:\BAT /Y /I >NUL
|
||||
ECHO [OK] Common batch files updated
|
||||
ECHO.
|
||||
|
||||
REM Check for machine-specific updates
|
||||
IF NOT EXIST T:\%MACHINE%\ProdSW\*.* GOTO SKIP_MACHINE
|
||||
|
||||
ECHO [2/3] Copying from T:\%MACHINE%\ProdSW...
|
||||
IF EXIST T:\%MACHINE%\ProdSW\*.BAT XCOPY T:\%MACHINE%\ProdSW\*.BAT C:\BAT /Y /I >NUL
|
||||
IF EXIST T:\%MACHINE%\ProdSW\*.EXE XCOPY T:\%MACHINE%\ProdSW\*.EXE C:\ATE /Y /I >NUL
|
||||
IF EXIST T:\%MACHINE%\ProdSW\*.DAT XCOPY T:\%MACHINE%\ProdSW\*.DAT C:\ATE /Y /I >NUL
|
||||
IF EXIST T:\%MACHINE%\ProdSW\*.CFG XCOPY T:\%MACHINE%\ProdSW\*.CFG C:\ATE /Y /I >NUL
|
||||
ECHO [OK] Machine-specific files updated
|
||||
ECHO.
|
||||
GOTO CHECK_NET
|
||||
|
||||
:SKIP_MACHINE
|
||||
ECHO [2/3] No machine-specific updates (T:\%MACHINE%\ProdSW not found)
|
||||
ECHO.
|
||||
|
||||
:CHECK_NET
|
||||
REM Check for network client updates
|
||||
IF NOT EXIST T:\COMMON\NET\*.* GOTO SKIP_NET
|
||||
|
||||
ECHO [3/3] Copying from T:\COMMON\NET to C:\NET...
|
||||
XCOPY T:\COMMON\NET\*.* C:\NET /Y /I >NUL
|
||||
ECHO [OK] Network files updated
|
||||
ECHO.
|
||||
GOTO DONE
|
||||
|
||||
:SKIP_NET
|
||||
ECHO [3/3] No network updates (T:\COMMON\NET not found)
|
||||
ECHO.
|
||||
|
||||
:DONE
|
||||
ECHO ==============================================================
|
||||
ECHO Download Complete
|
||||
ECHO ==============================================================
|
||||
ECHO.
|
||||
GOTO END
|
||||
|
||||
:NO_COMMON
|
||||
ECHO [ERROR] T:\COMMON\ProdSW not found
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO [ERROR] MACHINE variable not set
|
||||
ECHO Run DEPLOY.BAT first
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_DRIVE
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO Run C:\STARTNET.BAT first
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:END
|
||||
|
||||
199
projects/dataforth-dos/batch-files/UPDATE-PRODSW.BAT
Executable file
199
projects/dataforth-dos/batch-files/UPDATE-PRODSW.BAT
Executable file
@@ -0,0 +1,199 @@
|
||||
@ECHO OFF
|
||||
REM UPDATE.BAT - Backup Dataforth test machine to network storage
|
||||
REM Usage: UPDATE [machine-name]
|
||||
REM Example: UPDATE TS-4R
|
||||
REM
|
||||
REM If machine-name not provided, uses MACHINE environment variable
|
||||
REM from AUTOEXEC.BAT
|
||||
REM
|
||||
REM Version: 2.3 - Fixed XCOPY trailing backslash for DOS 6.22
|
||||
REM Last modified: 2026-01-20
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 1: Determine machine name
|
||||
REM ==================================================================
|
||||
|
||||
IF NOT "%1"=="" GOTO USE_PARAM
|
||||
IF NOT "%MACHINE%"=="" GOTO USE_ENV
|
||||
|
||||
:NO_MACHINE
|
||||
ECHO.
|
||||
ECHO [ERROR] Machine name not specified
|
||||
ECHO.
|
||||
ECHO Usage: UPDATE machine-name
|
||||
ECHO Example: UPDATE TS-4R
|
||||
ECHO.
|
||||
ECHO Or set MACHINE variable in AUTOEXEC.BAT:
|
||||
ECHO SET MACHINE=TS-4R
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:USE_PARAM
|
||||
SET MACHINE=%1
|
||||
GOTO CHECK_DRIVE
|
||||
|
||||
:USE_ENV
|
||||
REM Machine name from environment variable
|
||||
GOTO CHECK_DRIVE
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 2: Verify T: drive is accessible
|
||||
REM ==================================================================
|
||||
|
||||
:CHECK_DRIVE
|
||||
ECHO Checking network drive T:...
|
||||
|
||||
REM DOS 6.22: Direct file test is most reliable
|
||||
IF NOT EXIST T:\*.* GOTO NO_T_DRIVE
|
||||
|
||||
ECHO [OK] T: drive accessible
|
||||
GOTO START_BACKUP
|
||||
|
||||
:NO_T_DRIVE
|
||||
ECHO.
|
||||
ECHO [ERROR] T: drive not available
|
||||
ECHO.
|
||||
ECHO Network drive T: must be mapped to \\D2TESTNAS\test
|
||||
ECHO.
|
||||
ECHO Run STARTNET.BAT to map network drives:
|
||||
ECHO C:\STARTNET.BAT
|
||||
ECHO.
|
||||
ECHO Or map manually:
|
||||
ECHO NET USE T: \\D2TESTNAS\test /YES
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 3: Create backup directory structure
|
||||
REM ==================================================================
|
||||
|
||||
:START_BACKUP
|
||||
ECHO.
|
||||
ECHO ==============================================================
|
||||
ECHO Backup: Machine %MACHINE%
|
||||
ECHO ==============================================================
|
||||
ECHO Source: C:\
|
||||
ECHO Target: T:\%MACHINE%\BACKUP
|
||||
ECHO.
|
||||
|
||||
REM Create machine directory if it doesn't exist
|
||||
IF NOT EXIST T:\%MACHINE%\NUL MD T:\%MACHINE%
|
||||
|
||||
REM Create backup directory
|
||||
IF NOT EXIST T:\%MACHINE%\BACKUP\NUL MD T:\%MACHINE%\BACKUP
|
||||
|
||||
REM Check if backup directory was created successfully
|
||||
IF NOT EXIST T:\%MACHINE%\BACKUP\*.* GOTO BACKUP_DIR_ERROR
|
||||
|
||||
ECHO [OK] Backup directory ready
|
||||
ECHO.
|
||||
|
||||
REM ==================================================================
|
||||
REM STEP 4: Perform backup
|
||||
REM ==================================================================
|
||||
|
||||
ECHO Starting backup...
|
||||
ECHO This may take several minutes depending on file count.
|
||||
ECHO.
|
||||
|
||||
REM XCOPY options for DOS 6.22:
|
||||
REM /S = Copy subdirectories (except empty ones)
|
||||
REM /E = Copy subdirectories (including empty ones)
|
||||
REM /Y = Suppress prompts (auto-overwrite)
|
||||
REM /H = Copy hidden and system files
|
||||
REM /K = Copy attributes
|
||||
REM /C = Continue on errors
|
||||
REM
|
||||
REM NOTE: /D flag removed - requires date parameter in DOS 6.22 (/D:mm-dd-yy)
|
||||
REM NOTE: /Q flag not available in DOS 6.22 (added in later Windows versions)
|
||||
|
||||
XCOPY C:\*.* T:\%MACHINE%\BACKUP /S /E /Y /H /K /C
|
||||
|
||||
REM Check XCOPY error level
|
||||
REM 0 = Files copied OK
|
||||
REM 1 = No files found to copy
|
||||
REM 2 = User terminated (Ctrl+C)
|
||||
REM 4 = Initialization error (insufficient memory, invalid path, etc)
|
||||
REM 5 = Disk write error
|
||||
|
||||
IF ERRORLEVEL 5 GOTO DISK_ERROR
|
||||
IF ERRORLEVEL 4 GOTO INIT_ERROR
|
||||
IF ERRORLEVEL 2 GOTO USER_ABORT
|
||||
IF ERRORLEVEL 1 GOTO NO_FILES
|
||||
|
||||
ECHO.
|
||||
ECHO [OK] Backup completed successfully
|
||||
ECHO.
|
||||
ECHO Files backed up to: T:\%MACHINE%\BACKUP
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM ERROR HANDLERS
|
||||
REM ==================================================================
|
||||
|
||||
:BACKUP_DIR_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Could not create backup directory
|
||||
ECHO Target: T:\%MACHINE%\BACKUP
|
||||
ECHO.
|
||||
ECHO Check:
|
||||
ECHO - T: drive is writable
|
||||
ECHO - Sufficient disk space on T:
|
||||
ECHO - Network connection is stable
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:DISK_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Disk write error
|
||||
ECHO.
|
||||
ECHO Possible causes:
|
||||
ECHO - Target drive is full
|
||||
ECHO - Network connection lost
|
||||
ECHO - Permission denied
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:INIT_ERROR
|
||||
ECHO.
|
||||
ECHO [ERROR] Backup initialization failed
|
||||
ECHO.
|
||||
ECHO Possible causes:
|
||||
ECHO - Insufficient memory
|
||||
ECHO - Invalid path
|
||||
ECHO - Target drive not accessible
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:USER_ABORT
|
||||
ECHO.
|
||||
ECHO [WARNING] Backup terminated by user (Ctrl+C)
|
||||
ECHO.
|
||||
ECHO Backup may be incomplete!
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
:NO_FILES
|
||||
ECHO.
|
||||
ECHO [WARNING] No files found to copy
|
||||
ECHO.
|
||||
ECHO This may indicate:
|
||||
ECHO - All files are already up to date (/D option)
|
||||
ECHO - Source drive is empty
|
||||
ECHO.
|
||||
PAUSE
|
||||
GOTO END
|
||||
|
||||
REM ==================================================================
|
||||
REM CLEANUP AND EXIT
|
||||
REM ==================================================================
|
||||
|
||||
:END
|
||||
REM Clean up environment variables (DOS has limited space)
|
||||
SET OLDDRV=
|
||||
@@ -1,5 +1,5 @@
|
||||
@ECHO OFF
|
||||
REM UPDATE.BAT - Redirect to DEPLOY.BAT in proper location
|
||||
REM Usage: UPDATE.BAT machine-name
|
||||
REM Example: UPDATE.BAT TS-4R
|
||||
CALL T:\COMMON\ProdSW\DEPLOY.BAT %1
|
||||
@ECHO OFF
|
||||
REM UPDATE.BAT - Redirect to DEPLOY.BAT in proper location
|
||||
REM Usage: UPDATE.BAT machine-name
|
||||
REM Example: UPDATE.BAT TS-4R
|
||||
CALL T:\COMMON\ProdSW\DEPLOY.BAT %1
|
||||
|
||||
@@ -1,19 +1,56 @@
|
||||
#Requires -Version 2.0
|
||||
<#
|
||||
.SYNOPSIS
|
||||
GuruRMM Legacy Agent - PowerShell-based agent for Windows Server 2008 R2 and older systems
|
||||
GuruRMM Legacy Agent for Windows Server 2008 R2 and older systems.
|
||||
|
||||
.DESCRIPTION
|
||||
Lightweight RMM agent that:
|
||||
- Registers with GuruRMM server using site code
|
||||
- Reports system information
|
||||
- Executes remote scripts/commands
|
||||
- Monitors system health
|
||||
This PowerShell-based agent is designed for legacy Windows systems that cannot
|
||||
run the modern Rust-based GuruRMM agent. It provides basic RMM functionality
|
||||
including registration, heartbeat, system info collection, and remote command
|
||||
execution.
|
||||
|
||||
IMPORTANT: This agent is intended for legacy systems only. For Windows 10/
|
||||
Server 2016 and newer, use the native Rust agent instead.
|
||||
|
||||
.PARAMETER ConfigPath
|
||||
Path to the agent configuration file. Default: $env:ProgramData\GuruRMM\agent.json
|
||||
|
||||
.PARAMETER ServerUrl
|
||||
The URL of the GuruRMM server (e.g., https://rmm.example.com)
|
||||
|
||||
.PARAMETER SiteCode
|
||||
The site code for agent registration (e.g., ACME-CORP-1234)
|
||||
|
||||
.PARAMETER AllowInsecureTLS
|
||||
[SECURITY RISK] Disables SSL/TLS certificate validation. Required ONLY for
|
||||
systems with self-signed certificates or broken certificate chains.
|
||||
|
||||
WARNING: This flag makes the connection vulnerable to man-in-the-middle
|
||||
attacks. Only use on isolated networks or when absolutely necessary.
|
||||
|
||||
This flag must be explicitly provided - certificate validation is enabled
|
||||
by default.
|
||||
|
||||
.PARAMETER Register
|
||||
Register this agent with the server.
|
||||
|
||||
.EXAMPLE
|
||||
# Secure installation (recommended)
|
||||
.\GuruRMM-Agent.ps1 -Register -ServerUrl "https://rmm.example.com" -SiteCode "ACME-CORP-1234"
|
||||
|
||||
.EXAMPLE
|
||||
# Insecure installation (legacy systems with self-signed certs ONLY)
|
||||
.\GuruRMM-Agent.ps1 -Register -ServerUrl "https://rmm.example.com" -SiteCode "ACME-CORP-1234" -AllowInsecureTLS
|
||||
|
||||
.EXAMPLE
|
||||
# Run the agent
|
||||
.\GuruRMM-Agent.ps1
|
||||
|
||||
.NOTES
|
||||
Compatible with PowerShell 2.0+ (Windows Server 2008 R2)
|
||||
Version: 1.1.0
|
||||
Requires: PowerShell 2.0+
|
||||
Platforms: Windows Server 2008 R2, Windows 7, and newer
|
||||
Author: GuruRMM
|
||||
Version: 1.0.0
|
||||
#>
|
||||
|
||||
param(
|
||||
@@ -27,18 +64,23 @@ param(
|
||||
[string]$SiteCode,
|
||||
|
||||
[Parameter()]
|
||||
[string]$ServerUrl = "https://rmm-api.azcomputerguru.com"
|
||||
[string]$ServerUrl = "https://rmm-api.azcomputerguru.com",
|
||||
|
||||
[Parameter()]
|
||||
[switch]$AllowInsecureTLS
|
||||
)
|
||||
|
||||
# ============================================================================
|
||||
# Configuration
|
||||
# ============================================================================
|
||||
|
||||
$script:Version = "1.0.0"
|
||||
$script:Version = "1.1.0"
|
||||
$script:AgentType = "powershell-legacy"
|
||||
$script:ConfigDir = "$env:ProgramData\GuruRMM"
|
||||
$script:LogFile = "$script:ConfigDir\agent.log"
|
||||
$script:PollInterval = 60 # seconds
|
||||
$script:AllowInsecureTLS = $AllowInsecureTLS
|
||||
$script:TLSInitialized = $false
|
||||
|
||||
# ============================================================================
|
||||
# Logging
|
||||
@@ -67,6 +109,63 @@ function Write-Log {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# TLS Initialization
|
||||
# ============================================================================
|
||||
|
||||
function Initialize-TLS {
|
||||
if ($script:TLSInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
# Configure TLS - prefer TLS 1.2
|
||||
try {
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
||||
Write-Log "TLS 1.2 configured successfully" "INFO"
|
||||
} catch {
|
||||
Write-Log "TLS 1.2 not available, trying TLS 1.1" "WARN"
|
||||
try {
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls11
|
||||
} catch {
|
||||
Write-Log "TLS 1.1 not available - using system default TLS" "WARN"
|
||||
try {
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls
|
||||
} catch {
|
||||
Write-Log "TLS configuration failed - connection security may be limited" "WARN"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Certificate validation - ONLY disable if explicitly requested
|
||||
if ($script:AllowInsecureTLS) {
|
||||
Write-Log "============================================" "WARN"
|
||||
Write-Log "[SECURITY WARNING] Certificate validation DISABLED" "WARN"
|
||||
Write-Log "This makes the connection vulnerable to MITM attacks" "WARN"
|
||||
Write-Log "Only use on legacy systems with self-signed certificates" "WARN"
|
||||
Write-Log "============================================" "WARN"
|
||||
|
||||
# Log to Windows Event Log for audit trail
|
||||
try {
|
||||
$source = "GuruRMM"
|
||||
if (-not [System.Diagnostics.EventLog]::SourceExists($source)) {
|
||||
New-EventLog -LogName Application -Source $source -ErrorAction SilentlyContinue
|
||||
}
|
||||
Write-EventLog -LogName Application -Source $source -EventId 1001 -EntryType Warning `
|
||||
-Message "GuruRMM agent started with certificate validation disabled (-AllowInsecureTLS). This is a security risk."
|
||||
} catch {
|
||||
Write-Log "Could not write to Windows Event Log: $_" "WARN"
|
||||
}
|
||||
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||
} else {
|
||||
Write-Log "Certificate validation ENABLED (secure mode)" "INFO"
|
||||
# Ensure callback is reset to default (validate certificates)
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null
|
||||
}
|
||||
|
||||
$script:TLSInitialized = $true
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# HTTP Functions (PS 2.0 compatible)
|
||||
# ============================================================================
|
||||
@@ -82,6 +181,9 @@ function Invoke-ApiRequest {
|
||||
$url = "$($script:Config.ServerUrl)$Endpoint"
|
||||
|
||||
try {
|
||||
# Initialize TLS settings (only runs once)
|
||||
Initialize-TLS
|
||||
|
||||
# Use .NET WebClient for PS 2.0 compatibility
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
$webClient.Headers.Add("Content-Type", "application/json")
|
||||
@@ -91,17 +193,6 @@ function Invoke-ApiRequest {
|
||||
$webClient.Headers.Add("Authorization", "Bearer $ApiKey")
|
||||
}
|
||||
|
||||
# Handle TLS (important for older systems)
|
||||
try {
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
||||
} catch {
|
||||
# Fallback for systems without TLS 1.2
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls
|
||||
}
|
||||
|
||||
# Ignore certificate errors for self-signed certs (optional)
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||
|
||||
if ($Method -eq "GET") {
|
||||
$response = $webClient.DownloadString($url)
|
||||
} else {
|
||||
|
||||
@@ -15,8 +15,20 @@
|
||||
.PARAMETER ServerUrl
|
||||
The GuruRMM server URL (default: https://rmm-api.azcomputerguru.com)
|
||||
|
||||
.PARAMETER AllowInsecureTLS
|
||||
[SECURITY RISK] Disables SSL/TLS certificate validation. Required ONLY for
|
||||
systems with self-signed certificates or broken certificate chains.
|
||||
|
||||
WARNING: This flag makes the connection vulnerable to man-in-the-middle
|
||||
attacks. Only use on isolated networks or when absolutely necessary.
|
||||
|
||||
.EXAMPLE
|
||||
# Secure installation (recommended)
|
||||
.\Install-GuruRMM.ps1 -SiteCode DARK-GROVE-7839
|
||||
|
||||
.EXAMPLE
|
||||
# Insecure installation (legacy systems with self-signed certs ONLY)
|
||||
.\Install-GuruRMM.ps1 -SiteCode DARK-GROVE-7839 -AllowInsecureTLS
|
||||
#>
|
||||
|
||||
param(
|
||||
@@ -24,7 +36,10 @@ param(
|
||||
[string]$SiteCode,
|
||||
|
||||
[Parameter()]
|
||||
[string]$ServerUrl = "https://rmm-api.azcomputerguru.com"
|
||||
[string]$ServerUrl = "https://rmm-api.azcomputerguru.com",
|
||||
|
||||
[Parameter()]
|
||||
[switch]$AllowInsecureTLS
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@@ -112,8 +127,15 @@ try {
|
||||
|
||||
# Step 3: Register agent
|
||||
Write-Status "Registering with GuruRMM server..."
|
||||
if ($AllowInsecureTLS) {
|
||||
Write-Status "[SECURITY WARNING] Installing with certificate validation DISABLED" "WARN"
|
||||
Write-Status "This makes the connection vulnerable to MITM attacks" "WARN"
|
||||
}
|
||||
try {
|
||||
$registerArgs = "-ExecutionPolicy Bypass -File `"$destScript`" -SiteCode `"$SiteCode`" -ServerUrl `"$ServerUrl`""
|
||||
if ($AllowInsecureTLS) {
|
||||
$registerArgs += " -AllowInsecureTLS"
|
||||
}
|
||||
$process = Start-Process powershell.exe -ArgumentList $registerArgs -Wait -PassThru -NoNewWindow
|
||||
|
||||
if ($process.ExitCode -ne 0) {
|
||||
@@ -137,13 +159,19 @@ try {
|
||||
|
||||
# Step 5: Create scheduled task
|
||||
try {
|
||||
# Create the task to run at startup and every 5 minutes
|
||||
# Create the task to run at startup
|
||||
$taskCommand = "powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$destScript`""
|
||||
if ($AllowInsecureTLS) {
|
||||
$taskCommand += " -AllowInsecureTLS"
|
||||
}
|
||||
|
||||
# Create task that runs at system startup
|
||||
schtasks /create /tn $TaskName /tr $taskCommand /sc onstart /ru SYSTEM /rl HIGHEST /f | Out-Null
|
||||
|
||||
Write-Status "Scheduled task created: $TaskName" "OK"
|
||||
if ($AllowInsecureTLS) {
|
||||
Write-Status "Task configured with -AllowInsecureTLS flag" "WARN"
|
||||
}
|
||||
} catch {
|
||||
Write-Status "Failed to create scheduled task: $($_.Exception.Message)" "ERROR"
|
||||
Write-Status "You may need to manually create the task" "WARN"
|
||||
|
||||
@@ -45,6 +45,9 @@ thiserror = "1"
|
||||
# UUID for identifiers
|
||||
uuid = { version = "1", features = ["v4", "serde"] }
|
||||
|
||||
# URL parsing for download validation
|
||||
url = "2"
|
||||
|
||||
# SHA256 checksums for update verification
|
||||
sha2 = "0.10"
|
||||
|
||||
|
||||
@@ -457,14 +457,14 @@ WantedBy=multi-user.target
|
||||
anyhow::bail!("systemctl enable failed");
|
||||
}
|
||||
|
||||
println!("\n✓ GuruRMM Agent installed successfully!");
|
||||
println!("\n[OK] GuruRMM Agent installed successfully!");
|
||||
println!("\nInstalled files:");
|
||||
println!(" Binary: {}", binary_dest);
|
||||
println!(" Config: {}", config_dest);
|
||||
println!(" Service: {}", unit_file);
|
||||
|
||||
if config_needs_manual_edit {
|
||||
println!("\n⚠️ IMPORTANT: Edit {} with your server URL and API key!", config_dest);
|
||||
println!("\n[WARNING] IMPORTANT: Edit {} with your server URL and API key!", config_dest);
|
||||
println!("\nNext steps:");
|
||||
println!(" 1. Edit {} with your server URL and API key", config_dest);
|
||||
println!(" 2. Start the service: sudo systemctl start {}", SERVICE_NAME);
|
||||
@@ -475,9 +475,9 @@ WantedBy=multi-user.target
|
||||
.status();
|
||||
|
||||
if status.is_ok() && status.unwrap().success() {
|
||||
println!("✓ Service started successfully!");
|
||||
println!("[OK] Service started successfully!");
|
||||
} else {
|
||||
println!("⚠️ Failed to start service. Check logs: sudo journalctl -u {} -f", SERVICE_NAME);
|
||||
println!("[WARNING] Failed to start service. Check logs: sudo journalctl -u {} -f", SERVICE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +556,7 @@ async fn uninstall_systemd_service() -> Result<()> {
|
||||
.args(["daemon-reload"])
|
||||
.status();
|
||||
|
||||
println!("\n✓ GuruRMM Agent uninstalled successfully!");
|
||||
println!("\n[OK] GuruRMM Agent uninstalled successfully!");
|
||||
println!("\nNote: Config directory {} was preserved.", CONFIG_DIR);
|
||||
println!("Remove it manually if no longer needed: sudo rm -rf {}", CONFIG_DIR);
|
||||
|
||||
@@ -582,7 +582,7 @@ async fn start_service() -> Result<()> {
|
||||
.context("Failed to start service")?;
|
||||
|
||||
if status.success() {
|
||||
println!("** Service started successfully");
|
||||
println!("[OK] Service started successfully");
|
||||
println!("Check status: sudo systemctl status gururmm-agent");
|
||||
} else {
|
||||
anyhow::bail!("Failed to start service. Check: sudo journalctl -u gururmm-agent -n 50");
|
||||
@@ -616,7 +616,7 @@ async fn stop_service() -> Result<()> {
|
||||
.context("Failed to stop service")?;
|
||||
|
||||
if status.success() {
|
||||
println!("** Service stopped successfully");
|
||||
println!("[OK] Service stopped successfully");
|
||||
} else {
|
||||
anyhow::bail!("Failed to stop service");
|
||||
}
|
||||
|
||||
@@ -177,7 +177,36 @@ impl AgentUpdater {
|
||||
}
|
||||
|
||||
/// Download the new binary to a temp file
|
||||
///
|
||||
/// Security: Validates URL against allowed domains and requires HTTPS for external hosts
|
||||
async fn download_binary(&self, url: &str) -> Result<PathBuf> {
|
||||
// Validate URL is from trusted domain
|
||||
let allowed_domains = [
|
||||
"rmm-api.azcomputerguru.com",
|
||||
"downloads.azcomputerguru.com",
|
||||
"172.16.3.30", // Internal server
|
||||
];
|
||||
|
||||
let parsed_url = url::Url::parse(url)
|
||||
.context("Invalid download URL")?;
|
||||
|
||||
let host = parsed_url.host_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("No host in download URL"))?;
|
||||
|
||||
if !allowed_domains.iter().any(|d| host == *d || host.ends_with(&format!(".{}", d))) {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Download URL host '{}' not in allowed domains",
|
||||
host
|
||||
));
|
||||
}
|
||||
|
||||
// Require HTTPS (except for local/internal IPs)
|
||||
if parsed_url.scheme() != "https" && !host.starts_with("172.16.") && !host.starts_with("192.168.") {
|
||||
return Err(anyhow::anyhow!("Download URL must use HTTPS"));
|
||||
}
|
||||
|
||||
info!("[OK] URL validation passed: {}", url);
|
||||
|
||||
let response = self.http_client.get(url)
|
||||
.send()
|
||||
.await
|
||||
@@ -273,10 +302,26 @@ impl AgentUpdater {
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn create_unix_rollback_watchdog(&self) -> Result<()> {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let backup_path = self.config.backup_path();
|
||||
let binary_path = &self.config.binary_path;
|
||||
let timeout = self.config.rollback_timeout_secs;
|
||||
|
||||
// Use secure directory instead of /tmp/ (world-writable)
|
||||
let script_dir = PathBuf::from("/var/run/gururmm");
|
||||
|
||||
// Create directory if needed with restricted permissions (owner only)
|
||||
if !script_dir.exists() {
|
||||
tokio::fs::create_dir_all(&script_dir).await
|
||||
.context("Failed to create secure script directory")?;
|
||||
std::fs::set_permissions(&script_dir, std::fs::Permissions::from_mode(0o700))
|
||||
.context("Failed to set script directory permissions")?;
|
||||
}
|
||||
|
||||
// Use UUID in filename to prevent predictable paths
|
||||
let script_path = script_dir.join(format!("rollback-{}.sh", Uuid::new_v4()));
|
||||
|
||||
let script = format!(r#"#!/bin/bash
|
||||
# GuruRMM Rollback Watchdog
|
||||
# Auto-generated - will be deleted after successful update
|
||||
@@ -284,49 +329,50 @@ impl AgentUpdater {
|
||||
BACKUP="{backup}"
|
||||
BINARY="{binary}"
|
||||
TIMEOUT={timeout}
|
||||
SCRIPT_PATH="{script}"
|
||||
|
||||
sleep $TIMEOUT
|
||||
|
||||
# Check if agent service is running
|
||||
if ! systemctl is-active --quiet gururmm-agent 2>/dev/null; then
|
||||
echo "Agent not running after update, rolling back..."
|
||||
echo "[WARNING] Agent not running after update, rolling back..."
|
||||
if [ -f "$BACKUP" ]; then
|
||||
cp "$BACKUP" "$BINARY"
|
||||
chmod +x "$BINARY"
|
||||
systemctl start gururmm-agent
|
||||
echo "Rollback completed"
|
||||
echo "[OK] Rollback completed"
|
||||
else
|
||||
echo "No backup file found!"
|
||||
echo "[ERROR] No backup file found!"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Clean up this script
|
||||
rm -f /tmp/gururmm-rollback.sh
|
||||
rm -f "$SCRIPT_PATH"
|
||||
"#,
|
||||
backup = backup_path.display(),
|
||||
binary = binary_path.display(),
|
||||
timeout = timeout
|
||||
timeout = timeout,
|
||||
script = script_path.display()
|
||||
);
|
||||
|
||||
let script_path = PathBuf::from("/tmp/gururmm-rollback.sh");
|
||||
fs::write(&script_path, script).await?;
|
||||
fs::write(&script_path, script).await
|
||||
.context("Failed to write rollback script")?;
|
||||
|
||||
// Make executable and run in background
|
||||
tokio::process::Command::new("chmod")
|
||||
.arg("+x")
|
||||
.arg(&script_path)
|
||||
.status()
|
||||
.await?;
|
||||
// Set restrictive permissions (700 - owner only)
|
||||
std::fs::set_permissions(&script_path, std::fs::Permissions::from_mode(0o700))
|
||||
.context("Failed to set rollback script permissions")?;
|
||||
|
||||
// Spawn as detached background process
|
||||
tokio::process::Command::new("nohup")
|
||||
// Spawn as detached background process using setsid (not nohup with "&" literal arg)
|
||||
tokio::process::Command::new("setsid")
|
||||
.arg("bash")
|
||||
.arg(&script_path)
|
||||
.arg("&")
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn()
|
||||
.context("Failed to spawn rollback watchdog")?;
|
||||
|
||||
info!("Rollback watchdog started (timeout: {}s)", timeout);
|
||||
info!("[OK] Rollback watchdog started (timeout: {}s)", timeout);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -524,12 +570,29 @@ Remove-Item -Path $MyInvocation.MyCommand.Path -Force
|
||||
pub async fn cancel_rollback_watchdog(&self) {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// Kill the watchdog script
|
||||
// Kill any running rollback watchdog scripts
|
||||
let _ = tokio::process::Command::new("pkill")
|
||||
.args(["-f", "gururmm-rollback.sh"])
|
||||
.args(["-f", "rollback-.*\\.sh"])
|
||||
.status()
|
||||
.await;
|
||||
let _ = fs::remove_file("/tmp/gururmm-rollback.sh").await;
|
||||
|
||||
// Clean up the secure script directory
|
||||
let script_dir = PathBuf::from("/var/run/gururmm");
|
||||
if script_dir.exists() {
|
||||
// Remove all rollback scripts in the directory
|
||||
if let Ok(mut entries) = tokio::fs::read_dir(&script_dir).await {
|
||||
while let Ok(Some(entry)) = entries.next_entry().await {
|
||||
let path = entry.path();
|
||||
if path.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.map(|n| n.starts_with("rollback-"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
let _ = fs::remove_file(&path).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from "axios";
|
||||
import axios, { AxiosError } from "axios";
|
||||
|
||||
// Default to production URL, override with VITE_API_URL for local dev
|
||||
const API_URL = import.meta.env.VITE_API_URL || "https://rmm-api.azcomputerguru.com";
|
||||
@@ -10,22 +10,41 @@ export const api = axios.create({
|
||||
},
|
||||
});
|
||||
|
||||
// Add auth token to requests
|
||||
// Token management - use sessionStorage (cleared on tab close) instead of localStorage
|
||||
// This provides better security against XSS attacks as tokens are not persisted
|
||||
const TOKEN_KEY = "gururmm_auth_token";
|
||||
|
||||
export const getToken = (): string | null => {
|
||||
return sessionStorage.getItem(TOKEN_KEY);
|
||||
};
|
||||
|
||||
export const setToken = (token: string): void => {
|
||||
sessionStorage.setItem(TOKEN_KEY, token);
|
||||
};
|
||||
|
||||
export const clearToken = (): void => {
|
||||
sessionStorage.removeItem(TOKEN_KEY);
|
||||
};
|
||||
|
||||
// Request interceptor - add auth header
|
||||
api.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem("token");
|
||||
const token = getToken();
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
// Handle auth errors
|
||||
// Response interceptor - handle 401 unauthorized
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
(error: AxiosError) => {
|
||||
if (error.response?.status === 401) {
|
||||
localStorage.removeItem("token");
|
||||
window.location.href = "/login";
|
||||
clearToken();
|
||||
// Use a more graceful redirect that preserves SPA state
|
||||
if (window.location.pathname !== "/login") {
|
||||
window.location.href = "/login";
|
||||
}
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
@@ -156,9 +175,31 @@ export interface RegisterRequest {
|
||||
|
||||
// API functions
|
||||
export const authApi = {
|
||||
login: (data: LoginRequest) => api.post<LoginResponse>("/api/auth/login", data),
|
||||
register: (data: RegisterRequest) => api.post<LoginResponse>("/api/auth/register", data),
|
||||
login: async (data: LoginRequest): Promise<LoginResponse> => {
|
||||
const response = await api.post<LoginResponse>("/api/auth/login", data);
|
||||
if (response.data.token) {
|
||||
setToken(response.data.token);
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
|
||||
register: async (data: RegisterRequest): Promise<LoginResponse> => {
|
||||
const response = await api.post<LoginResponse>("/api/auth/register", data);
|
||||
if (response.data.token) {
|
||||
setToken(response.data.token);
|
||||
}
|
||||
return response.data;
|
||||
},
|
||||
|
||||
me: () => api.get<User>("/api/auth/me"),
|
||||
|
||||
logout: (): void => {
|
||||
clearToken();
|
||||
},
|
||||
|
||||
isAuthenticated: (): boolean => {
|
||||
return !!getToken();
|
||||
},
|
||||
};
|
||||
|
||||
export const agentsApi = {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
|
||||
import { User, authApi } from "../api/client";
|
||||
import { User, authApi, getToken, clearToken } from "../api/client";
|
||||
|
||||
interface AuthContextType {
|
||||
user: User | null;
|
||||
token: string | null;
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
login: (email: string, password: string) => Promise<void>;
|
||||
register: (email: string, password: string, name?: string) => Promise<void>;
|
||||
@@ -14,46 +14,49 @@ const AuthContext = createContext<AuthContextType | null>(null);
|
||||
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [token, setToken] = useState<string | null>(() => localStorage.getItem("token"));
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
// Check authentication status on mount
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
authApi
|
||||
.me()
|
||||
.then((res) => setUser(res.data))
|
||||
.catch(() => {
|
||||
localStorage.removeItem("token");
|
||||
setToken(null);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
} else {
|
||||
const checkAuth = async () => {
|
||||
const token = getToken();
|
||||
if (token) {
|
||||
try {
|
||||
const res = await authApi.me();
|
||||
setUser(res.data);
|
||||
} catch {
|
||||
// Token is invalid or expired, clear it
|
||||
clearToken();
|
||||
setUser(null);
|
||||
}
|
||||
}
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [token]);
|
||||
};
|
||||
|
||||
checkAuth();
|
||||
}, []);
|
||||
|
||||
const login = async (email: string, password: string) => {
|
||||
const res = await authApi.login({ email, password });
|
||||
localStorage.setItem("token", res.data.token);
|
||||
setToken(res.data.token);
|
||||
setUser(res.data.user);
|
||||
const response = await authApi.login({ email, password });
|
||||
// Token is automatically stored by authApi.login
|
||||
setUser(response.user);
|
||||
};
|
||||
|
||||
const register = async (email: string, password: string, name?: string) => {
|
||||
const res = await authApi.register({ email, password, name });
|
||||
localStorage.setItem("token", res.data.token);
|
||||
setToken(res.data.token);
|
||||
setUser(res.data.user);
|
||||
const response = await authApi.register({ email, password, name });
|
||||
// Token is automatically stored by authApi.register
|
||||
setUser(response.user);
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("token");
|
||||
setToken(null);
|
||||
authApi.logout();
|
||||
setUser(null);
|
||||
};
|
||||
|
||||
const isAuthenticated = authApi.isAuthenticated();
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, token, isLoading, login, register, logout }}>
|
||||
<AuthContext.Provider value={{ user, isAuthenticated, isLoading, login, register, logout }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { useState, FormEvent } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { AxiosError } from "axios";
|
||||
import { useAuth } from "../hooks/useAuth";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "../components/Card";
|
||||
import { Input } from "../components/Input";
|
||||
import { Button } from "../components/Button";
|
||||
|
||||
interface ApiErrorResponse {
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function Login() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
@@ -21,8 +27,15 @@ export function Login() {
|
||||
try {
|
||||
await login(email, password);
|
||||
navigate("/");
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error || "Login failed. Please try again.");
|
||||
} catch (err) {
|
||||
if (err instanceof AxiosError) {
|
||||
const errorData = err.response?.data as ApiErrorResponse | undefined;
|
||||
setError(errorData?.error || errorData?.message || err.message || "Login failed. Please try again.");
|
||||
} else if (err instanceof Error) {
|
||||
setError(err.message);
|
||||
} else {
|
||||
setError("An unexpected error occurred");
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { useState, FormEvent } from "react";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { AxiosError } from "axios";
|
||||
import { useAuth } from "../hooks/useAuth";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "../components/Card";
|
||||
import { Input } from "../components/Input";
|
||||
import { Button } from "../components/Button";
|
||||
|
||||
interface ApiErrorResponse {
|
||||
error?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export function Register() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
@@ -34,8 +40,15 @@ export function Register() {
|
||||
try {
|
||||
await register(email, password, name || undefined);
|
||||
navigate("/");
|
||||
} catch (err: any) {
|
||||
setError(err.response?.data?.error || "Registration failed. Please try again.");
|
||||
} catch (err) {
|
||||
if (err instanceof AxiosError) {
|
||||
const errorData = err.response?.data as ApiErrorResponse | undefined;
|
||||
setError(errorData?.error || errorData?.message || err.message || "Registration failed. Please try again.");
|
||||
} else if (err instanceof Error) {
|
||||
setError(err.message);
|
||||
} else {
|
||||
setError("An unexpected error occurred");
|
||||
}
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
1276
projects/msp-tools/guru-rmm/docs/REMEDIATION_PLAN.md
Normal file
1276
projects/msp-tools/guru-rmm/docs/REMEDIATION_PLAN.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ axum = { version = "0.7", features = ["ws", "macros"] }
|
||||
axum-extra = { version = "0.9", features = ["typed-header"] }
|
||||
tower = { version = "0.5", features = ["util", "timeout"] }
|
||||
tower-http = { version = "0.6", features = ["cors", "trace", "compression-gzip"] }
|
||||
http = "1"
|
||||
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -8,6 +8,7 @@ use axum::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::auth::AuthUser;
|
||||
use crate::db::{self, AgentResponse, AgentStats};
|
||||
use crate::ws::{generate_api_key, hash_api_key};
|
||||
use crate::AppState;
|
||||
@@ -29,10 +30,20 @@ pub struct RegisterAgentRequest {
|
||||
}
|
||||
|
||||
/// Register a new agent (generates API key)
|
||||
/// Requires authentication to prevent unauthorized agent registration.
|
||||
pub async fn register_agent(
|
||||
State(state): State<AppState>,
|
||||
user: AuthUser,
|
||||
Json(req): Json<RegisterAgentRequest>,
|
||||
) -> Result<Json<RegisterAgentResponse>, (StatusCode, String)> {
|
||||
// Log who is registering the agent
|
||||
tracing::info!(
|
||||
user_id = %user.user_id,
|
||||
hostname = %req.hostname,
|
||||
os_type = %req.os_type,
|
||||
"Agent registration initiated by user"
|
||||
);
|
||||
|
||||
// Generate a new API key
|
||||
let api_key = generate_api_key(&state.config.auth.api_key_prefix);
|
||||
let api_key_hash = hash_api_key(&api_key);
|
||||
@@ -50,6 +61,12 @@ pub async fn register_agent(
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
|
||||
|
||||
tracing::info!(
|
||||
user_id = %user.user_id,
|
||||
agent_id = %agent.id,
|
||||
"Agent registered successfully"
|
||||
);
|
||||
|
||||
Ok(Json(RegisterAgentResponse {
|
||||
agent_id: agent.id,
|
||||
api_key, // Return the plain API key (only shown once!)
|
||||
@@ -59,8 +76,10 @@ pub async fn register_agent(
|
||||
}
|
||||
|
||||
/// List all agents
|
||||
/// Requires authentication.
|
||||
pub async fn list_agents(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
) -> Result<Json<Vec<AgentResponse>>, (StatusCode, String)> {
|
||||
let agents = db::get_all_agents(&state.db)
|
||||
.await
|
||||
@@ -71,8 +90,10 @@ pub async fn list_agents(
|
||||
}
|
||||
|
||||
/// Get a specific agent
|
||||
/// Requires authentication.
|
||||
pub async fn get_agent(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<Json<AgentResponse>, (StatusCode, String)> {
|
||||
let agent = db::get_agent_by_id(&state.db, id)
|
||||
@@ -84,8 +105,10 @@ pub async fn get_agent(
|
||||
}
|
||||
|
||||
/// Delete an agent
|
||||
/// Requires authentication.
|
||||
pub async fn delete_agent(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<StatusCode, (StatusCode, String)> {
|
||||
// Check if agent is connected and disconnect it
|
||||
@@ -106,8 +129,10 @@ pub async fn delete_agent(
|
||||
}
|
||||
|
||||
/// Get agent statistics
|
||||
/// Requires authentication.
|
||||
pub async fn get_stats(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
) -> Result<Json<AgentStats>, (StatusCode, String)> {
|
||||
let stats = db::get_agent_stats(&state.db)
|
||||
.await
|
||||
@@ -123,8 +148,10 @@ pub struct MoveAgentRequest {
|
||||
}
|
||||
|
||||
/// Move an agent to a different site
|
||||
/// Requires authentication.
|
||||
pub async fn move_agent(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
Json(req): Json<MoveAgentRequest>,
|
||||
) -> Result<Json<AgentResponse>, (StatusCode, String)> {
|
||||
@@ -149,8 +176,10 @@ pub async fn move_agent(
|
||||
}
|
||||
|
||||
/// List all agents with full details (site/client info)
|
||||
/// Requires authentication.
|
||||
pub async fn list_agents_with_details(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
) -> Result<Json<Vec<db::AgentWithDetails>>, (StatusCode, String)> {
|
||||
let agents = db::get_all_agents_with_details(&state.db)
|
||||
.await
|
||||
@@ -160,8 +189,10 @@ pub async fn list_agents_with_details(
|
||||
}
|
||||
|
||||
/// List unassigned agents (not belonging to any site)
|
||||
/// Requires authentication.
|
||||
pub async fn list_unassigned_agents(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
) -> Result<Json<Vec<AgentResponse>>, (StatusCode, String)> {
|
||||
let agents = db::get_unassigned_agents(&state.db)
|
||||
.await
|
||||
@@ -172,8 +203,10 @@ pub async fn list_unassigned_agents(
|
||||
}
|
||||
|
||||
/// Get extended state for an agent (network interfaces, uptime, etc.)
|
||||
/// Requires authentication.
|
||||
pub async fn get_agent_state(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<Json<db::AgentState>, (StatusCode, String)> {
|
||||
let agent_state = db::get_agent_state(&state.db, id)
|
||||
|
||||
@@ -8,6 +8,7 @@ use axum::{
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::auth::AuthUser;
|
||||
use crate::db::{self, Command};
|
||||
use crate::ws::{CommandPayload, ServerMessage};
|
||||
use crate::AppState;
|
||||
@@ -43,23 +44,33 @@ pub struct CommandsQuery {
|
||||
}
|
||||
|
||||
/// Send a command to an agent
|
||||
/// Requires authentication. Logs the user who sent the command for audit trail.
|
||||
pub async fn send_command(
|
||||
State(state): State<AppState>,
|
||||
user: AuthUser,
|
||||
Path(agent_id): Path<Uuid>,
|
||||
Json(req): Json<SendCommandRequest>,
|
||||
) -> Result<Json<SendCommandResponse>, (StatusCode, String)> {
|
||||
// Log the command being sent for audit trail
|
||||
tracing::info!(
|
||||
user_id = %user.user_id,
|
||||
agent_id = %agent_id,
|
||||
command_type = %req.command_type,
|
||||
"Command sent by user"
|
||||
);
|
||||
|
||||
// Verify agent exists
|
||||
let agent = db::get_agent_by_id(&state.db, agent_id)
|
||||
let _agent = db::get_agent_by_id(&state.db, agent_id)
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
|
||||
.ok_or((StatusCode::NOT_FOUND, "Agent not found".to_string()))?;
|
||||
|
||||
// Create command record
|
||||
// Create command record with user ID for audit trail
|
||||
let create = db::CreateCommand {
|
||||
agent_id,
|
||||
command_type: req.command_type.clone(),
|
||||
command_text: req.command.clone(),
|
||||
created_by: None, // TODO: Get from JWT
|
||||
created_by: Some(user.user_id),
|
||||
};
|
||||
|
||||
let command = db::create_command(&state.db, create)
|
||||
@@ -100,8 +111,10 @@ pub async fn send_command(
|
||||
}
|
||||
|
||||
/// List recent commands
|
||||
/// Requires authentication.
|
||||
pub async fn list_commands(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Query(query): Query<CommandsQuery>,
|
||||
) -> Result<Json<Vec<Command>>, (StatusCode, String)> {
|
||||
let limit = query.limit.unwrap_or(50).min(500);
|
||||
@@ -114,8 +127,10 @@ pub async fn list_commands(
|
||||
}
|
||||
|
||||
/// Get a specific command by ID
|
||||
/// Requires authentication.
|
||||
pub async fn get_command(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
) -> Result<Json<Command>, (StatusCode, String)> {
|
||||
let command = db::get_command_by_id(&state.db, id)
|
||||
|
||||
@@ -5,10 +5,11 @@ use axum::{
|
||||
http::StatusCode,
|
||||
Json,
|
||||
};
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::auth::AuthUser;
|
||||
use crate::db::{self, Metrics, MetricsSummary};
|
||||
use crate::AppState;
|
||||
|
||||
@@ -26,13 +27,15 @@ pub struct MetricsQuery {
|
||||
}
|
||||
|
||||
/// Get metrics for a specific agent
|
||||
/// Requires authentication.
|
||||
pub async fn get_agent_metrics(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
Path(id): Path<Uuid>,
|
||||
Query(query): Query<MetricsQuery>,
|
||||
) -> Result<Json<Vec<Metrics>>, (StatusCode, String)> {
|
||||
// First verify the agent exists
|
||||
let agent = db::get_agent_by_id(&state.db, id)
|
||||
let _agent = db::get_agent_by_id(&state.db, id)
|
||||
.await
|
||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
|
||||
.ok_or((StatusCode::NOT_FOUND, "Agent not found".to_string()))?;
|
||||
@@ -54,8 +57,10 @@ pub async fn get_agent_metrics(
|
||||
}
|
||||
|
||||
/// Get summary metrics across all agents
|
||||
/// Requires authentication.
|
||||
pub async fn get_summary(
|
||||
State(state): State<AppState>,
|
||||
_user: AuthUser,
|
||||
) -> Result<Json<MetricsSummary>, (StatusCode, String)> {
|
||||
let summary = db::get_metrics_summary(&state.db)
|
||||
.await
|
||||
|
||||
@@ -24,7 +24,8 @@ use axum::{
|
||||
};
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use tokio::sync::RwLock;
|
||||
use tower_http::cors::{Any, CorsLayer};
|
||||
use http::HeaderValue;
|
||||
use tower_http::cors::{AllowOrigin, CorsLayer};
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::info;
|
||||
|
||||
@@ -129,11 +130,34 @@ async fn main() -> Result<()> {
|
||||
|
||||
/// Build the application router
|
||||
fn build_router(state: AppState) -> Router {
|
||||
// CORS configuration (allow dashboard access)
|
||||
// TODO: Add rate limiting for registration endpoints using tower-governor
|
||||
// Currently, registration is protected by AuthUser authentication.
|
||||
// For additional protection against brute-force attacks, consider adding:
|
||||
// - tower-governor crate for per-IP rate limiting on /api/agents/register
|
||||
// - Configurable limits via environment variables
|
||||
// Reference: https://docs.rs/tower-governor/latest/tower_governor/
|
||||
|
||||
// CORS configuration - restrict to specific dashboard origin
|
||||
let dashboard_origin = std::env::var("DASHBOARD_URL")
|
||||
.unwrap_or_else(|_| "https://rmm.azcomputerguru.com".to_string());
|
||||
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin(Any)
|
||||
.allow_methods(Any)
|
||||
.allow_headers(Any);
|
||||
.allow_origin(AllowOrigin::exact(
|
||||
HeaderValue::from_str(&dashboard_origin).expect("Invalid DASHBOARD_URL"),
|
||||
))
|
||||
.allow_methods([
|
||||
http::Method::GET,
|
||||
http::Method::POST,
|
||||
http::Method::PUT,
|
||||
http::Method::DELETE,
|
||||
http::Method::OPTIONS,
|
||||
])
|
||||
.allow_headers([
|
||||
http::header::AUTHORIZATION,
|
||||
http::header::CONTENT_TYPE,
|
||||
http::header::ACCEPT,
|
||||
])
|
||||
.allow_credentials(true);
|
||||
|
||||
Router::new()
|
||||
// Health check
|
||||
|
||||
Reference in New Issue
Block a user