1

Im trying to create 2 batch files that will silently install app on remote PCs and facing problems with main file (second one - silent.bat - placed in ./Installation with .exe file and exist to pass parameters to that .exe install file, tested 100 times, have no issues, so it will not be considered here).

Main file take 7 parameters in cmd line:

  1. Computer name
  2. Username
  3. Password
  4. Name of an app
  5. Directory
  6. as well as 7 just inside-app parameters. Up to 9 total, but i have 7.

First 3 are for main batch, others should be passed futher.

Main file - Remote_install.bat - consist of 2 parts:

  1. Elevation

First part is lightly changed Matt's answer that helps me elevate my batch and avoid UAC attention:

 @pushd %~dp0
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================
if %1.==. set res_pcname=F
 if "%~1"=="None" set res_pcname=F
 if "%~1"=="ELEV" set res_pcname=F
 if "%res_pcname%"=="F" (
    set PcName=%COMPUTERNAME%
 ) else (
    set PcName=%1
 )
 type NUL > %~dp0log_%PcName%.txt
 ECHO ===================================================================== >> %~dp0log_%PcName%.txt
 ECHO "Installation started" >> %~dp0log_%PcName%.txt

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 set winSysFolder=System32
 set "batchPath=%~dpnx0"
 for %%k in (%0) do set batchName=%%~nk
 set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
 setlocal EnableDelayedExpansion

:checkPrivileges
  NET FILE 1>NUL 2>NUL
  if '%errorlevel%' == '0' ( 
    echo "Got privileges" >> %~dp0log_%PcName%.txt
    goto gotPrivileges
 ) else ( 
    echo "Getting privileges" >> %~dp0log_%PcName%.txt
    goto getPrivileges )

:getPrivileges
  if '%1'=='ELEV' (shift /1 & goto gotPrivileges)
  ECHO.
  ECHO **************************************
  ECHO Invoking UAC for Privilege Escalation 
  ECHO **************************************

  ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
  ECHO args = "ELEV " >> "%vbsGetPrivileges%"
  ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
  ECHO args = args ^& strArg ^& " "  >> "%vbsGetPrivileges%"
  ECHO Next >> "%vbsGetPrivileges%"
  
  if '%cmdInvoke%'=='1' goto InvokeCmd 

  ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
  echo "Got privileges" >> %~dp0log_%PcName%.txt
  goto ExecElevation

:InvokeCmd
  ECHO args = "/c " + "!batchPath!" + " " + args >> "%vbsGetPrivileges%"
  ECHO UAC.ShellExecute "%SystemRoot%\%winSysFolder%\cmd.exe", args, "", "runas", 1 >> "%vbsGetPrivileges%"
  ECHO "Invoked" >> %~dp0log_%PcName%.txt

:ExecElevation
 "%SystemRoot%\%winSysFolder%\WScript.exe" "%vbsGetPrivileges%" %*
 exit /B

:gotPrivileges
 setlocal & cd /d %~dp0
 if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul  &  shift /1)

Changes are all about logs.

  1. Copy and schedule

Second part check parameters that passed onto batch file, connect to remote pc (xcopy make the job done even without net run tho), copy files to c:/temp and scedule an installation (and runns it). Main idea from here.

set __compat_layer=runasinvoker

set res_pcname=T
if %1.==. set res_pcname=F
if "%~1"=="None" set res_pcname=F
if "%res_pcname%"=="F" (
    set PcName=%COMPUTERNAME%
) else (
    set PcName=%1
)

echo %PcName% >> %~dp0log_%PcName%.txt

if  %2. NEQ . set res_login=%2
if "%~2"=="None" set res_login=""

if  %3. NEQ . set res_pw=%3
if "%~3"=="None" set res_pw=""

echo %batchName% Arguments: P1=%1 P2=%2 P3=%3 P4=%4 P5=%5 P6=%6 P7=%7 >> %~dp0log_%PcName%.txt

net use "%PcName%" %res_pw% /user:%res_login% >> %~dp0log_%PcName%.txt
XCOPY %~dp0 "\\%PcName%\C$\temp\appName" /y /i /s /e >> %~dp0log_%PcName%.txt

for %%a in ("\\%PcName%\C:\temp\appName\Installation\*.bat") do (
    set "bat_file=%%a "%4" "%5" "%6" "%7""
)
if %res_login% NEQ "" (
    if %res_pw% NEQ "" (
        schtasks.exe /create /S %PcName% /RU %2 /RP %3 /SC Once /TN InstallApp /TR "%bat_file%" /ST 18:30 >> %~dp0log_%PcName%.txt)
) else (
    schtasks.exe /create /S %PcName% /SC Once /TN InstallApp/TR "%bat_file%" /ST 18:30 >> %~dp0log_%PcName%.txt
)
schtasks.exe /run /S %PcName% /TN InstallVISIM >> %~dp0log_%PcName%.txt
schtasks.exe /delete /S %PcName% /TN InstallVISIM /F >> %~dp0log_%PcName%.txt
@popd

echo.
echo...Script Complete....
echo.

I set invoker just in case and re-check pc name, user login, and pass.

Parameters can be passed manually from another batch, command prompt, or, in my case, set in PyQt-made gui and send through popen.cmd2line

Qt GUI

Batch files runs for every group box with computer info. Also, gui is used to show logs from every computer im installing app on, have some saved configs, and helps me check if instalation is finnished with winreg.openkey.

PROBLEMS ARE:

  1. I meet a 67 error while trying to connect to remote pc, no futher explanation from cmd prompt. Tried to reinstall net drivers and changed net fisibility. No use. Do i even need that?

  2. Batch files just DO NOT run on net drivers. Even if i have mapped 'em. Just pop window and close immediately.

  3. Batch breakes right after copying files. I have catch that moment with pauses in different places, may xcopy close programm after completion? is it cause syntaxis is screwed?

  4. Running with empty parameters create error from task scheduler : '' - is invalid argument. I replace '' with None and back when press run button in qt, but if anyone will try to run batch naked in cmd prompt it will cause errors. While i have some sort of check for empty ones. Still, getting here requires to pass through xcopy, and batch usually breakes there.

  5. I have unstable performance in python: a. i cant read registry (probably because script runs way faster that installment). Registry is created with innosetup as uninstall info, so i know for sure that registry is there in some point. b. i set up sleep(1) while cycle with count up to 30 to check every second on registry (winreg.open key) and app literally dies while asleep. It should be, its normal. Is there any pattern that will ease that moment?

             try:
                 ConnectRegistry(f"{comps.findChildren(QLineEdit)[0].text()}", HKEY_LOCAL_MACHINE)
             except OSError:
                 self.tb_log.append(f"Error: computer with {comps.findChildren(QLineEdit)[0].text()} doesnt exist")
                 success = False
             while True and success:
                 try:
                     reg = OpenKey(HKEY_LOCAL_MACHINE, keypath)
                     CloseKey(reg)
                 except OSError:
                     cnt += 1
                     if cnt == 31:
                         self.tb_log.append("Error during installation: no registry files")
                         break
                     sleep(1)
                 else:
                     self.tb_log.append("Finished successfully")
                     break
    

I'll be glad to recieve any help with that problems, fellas and ladies! Psexec, wmic, powershell are out of my liege, but im a little bit skilled in python.., so, any ideas, really.

Sorry for any mistakes and wierd writings, if any explanation is needed - im here. If full python project is needed - give me a sign, i'll give you git link, but there is nothing noticeable - just main window transfer and some btn.connect functions.

  • 1
    `if %res_login% NEQ ""` is only true, if `%res_login%` is literally `""`. If it is empty, this line leads to a severe (script breaking) syntax error. – Stephan Feb 28 '22 at 16:56
  • @Stephan, Thank you! That dealt with problem #3. Can you explain please why unset variable is not empty string (="")? – Artem.Kandalintsev Feb 28 '22 at 17:06
  • 1
    `""` isn't an empty string. It's two doublequotes. See [here](https://stackoverflow.com/a/25206281/2152082) for an explanation why it fails if the variable is empty. – Stephan Feb 28 '22 at 17:30
  • 1
    Most basic parameter check; `if "%~7" == "" (echo not enough parameters & goto :eof )` – Stephan Feb 28 '22 at 17:36

0 Answers0