Self-extracting executable do not recognize an existing command in System32 - windows

I'm developing a stack of Windows Batch scripts (.bat) which are subsequently converted to self-extracting executabled.
Currently I'm facing a really strange problem. I create this self-extracting executable, which, after extracting all the files, will launch the main wrapper, (SETUP.bat). The whole stack of the scripts gets running and everything goes right until some point.
One part of the stack has to commit some files with UWFMGR, and I have a loop for like this:
SETLOCAL EnableDelayedExpansion
FOR /F usebackq "tokens=*" %%F IN ("DIR /S /B /A-D") DO (
uwfmgr file commit "%%F"
)
If I run the executable, the execution of the stack does not recognize the command UWFMGR
I stopped the execution of the script, and went with the same CMD, (which it's launched by the executable), to the System32 folder to check if the UWFMGR is there. I did a DIR "uwfmgr.exe", and it's not there. But if I go with another CMD (a new one) the command is there. I even went with a file explorer to verify it and it's completely there but somehow the CMD which it's being launched by the executable cannot recognize it.
I have tried to specify the whole path in the loop like this "C:\Windows\System32\UWFMGR.exe" and it doesn't even work.
The funny thing is that if run this script it works and commits all the files required.
SETLOCAL EnableDelayedExpansion
FOR /F usebackq "tokens=*" %%F IN ("DIR /S /B /A-D") DO (
uwfmgr file commit "%%F"
)
Does anyone have any idea of why this is happening?
Check the output of the command and the errorlevel, it's 9009 (the file/command does not exist)
Do an echo to check the command I'm passing through the loop, the command is OK
I expect the executable to do the whole stack and commit the files but the executable does not recognize UWFMGR command. I use other commands in my stack and I didn't have any problem.

64-bit Windows has two system32 folders. Windows\system32 is the real folder used by 64-bit applications. 32-bit applications are automatically redirected to Windows\Syswow64 when they access system32. There is a backdoor you can use to access the real system32 folder.
You should use if exist and set to find and store a usable path:
#echo off
set app=%windir%\system32\UWFMGR.exe
set appalt=%windir%\sysnative\UWFMGR.exe
if not exist "%app%" if exist "%appalt%" set app=%appalt%
echo.I will use %app%
UWFMGR seems to be an optional feature and is probably not present by default on most machines.

I solved it after finding out the exe was created as 32bits. I had to create as 64 bits in order to make it work. Now the executable is able to use the UWFMGR.
Thank you everyone for your answers and have a nice day.
I'm using this 7sfx module, just in case anyone's wondering: "7zsd_All_x64.sfx"

Related

Access system32 from VisualStudio 2019 build script

In a post build step i want check if OpenSSH.Client and OpenSSH.Server is installed and install it if it is not there. Checking the installed features with Powershell needs administrative privileges.
Therefore i test the existence of the relevant OpenSSH commands with the following code (extract of long script)
SET /a res=0
SET /a three=3
%windir%\system32\OpenSSH\ssh-keygen.exe /?
echo Errorlevel %ERRORLEVEL%
IF %ERRORLEVEL%==%three% (SET /a res=%res%+1)
%windir%\system32\OpenSSH\ssh-keyscan.exe /?
echo Errorlevel %ERRORLEVEL%
IF %ERRORLEVEL%==%three% (SET /a res=%res%+1)
SET /a check=0
IF %res% == %check% (
echo already installed
goto skipopenSSH
)
echo installation
:skipopenSSH
By checking the existence of the commands no admin privileges are necessary for the check so a normal build will not cause a administrative popup.
On cmd.exe it works fine, but as a post build step in Visual Studio both commands in %windir%\systrem32\OpenSSH are not found, although the variable is expanded to the same c:\Windows\System32\OpenSSH\*.exe as if executed on commandline.
After trying the different find mechanisms which all fail i made a test batch file C:\Windows\System32\OpenSSH\ssh-keyscan.exe /?
which leads to a file not found error if executed as a post build step. So the real question should be: Modifies the visual studio build step commandline the path?
The directory OpenSSH exists in directory %SystemRoot%\System32 with the files ssh-keygen.exe and ssh-keyscan.exe depending on version of Windows 10. The directory %SystemRoot%\System32 is for 64-bit applications on 64-bit Windows. But Visual Studio is a 32-bit application and for that reason 32-bit Windows command processor in directory %SystemRoot%\SysWOW64 is executed to process the batch file with the commands to execute as post build step.
Microsoft documented with WOW64 Implementation Details, File System Redirector and Registry Keys Affected by WOW64 and other documentation pages how Windows on Windows 64 works.
All file system accesses to %windir%\system32\OpenSSH in the batch file processed by 32-bit %SystemRoot%\SysWOW64\cmd.exe being started by 32-bit Visual Studio results in the approach to access %SystemRoot%\SysWOW64\OpenSSH which does not exist at all. There is no subdirectory OpenSSH in Windows system directory for 32-bit applications.
One solution would be using the following code for the batch file executed as post build step.
rem This simple check is for 32-bit Windows and for 64-bit Windows with batch
rem file executed in 64-bit environment by 64-bit Windows command processor.
set FolderSSH=%SystemRoot%\System32\OpenSSH
if exist %FolderSSH%\ssh-keygen.exe if exist %FolderSSH%\ssh-keyscan.exe goto UseOpenSSH
rem This check is for 64-bit Windows with batch file executed
rem in 32-bit environment by 32-bit Windows command processor.
if exist %SystemRoot%\Sysnative\cmd.exe set FolderSSH=%SystemRoot%\Sysnative\OpenSSH
if exist %FolderSSH%\ssh-keygen.exe if exist %FolderSSH%\ssh-keyscan.exe goto UseOpenSSH
rem Search entire system drive on machines without Windows 10 or with older
rem versions of Windows 10 with OpenSSH not installed at all by default.
for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe /R %SystemDrive%\ ssh-keygen.exe 2^>nul') do (
if exist "%%~dpIssh-keyscan.exe" for %%J in ("%%~dpI.") do set "FolderSSH=%%~fJ" & goto UseOpenSSH
)
echo ERROR: ssh-keygen.exe AND ssh-keyscan.exe not found.
rem More code to handle this use case.
goto :EOF
:UseOpenSSH
echo Found ssh-keygen and ssh-keyscan in: "%FolderSSH%"
rem More code to handle this use case with existing SSH tools.
The remarks explain most of the code. The inner FOR loop is used to get the full qualified name of the directory containing ssh-keygen.exe and ssh-keyscan.exe without backslash at end of the folder path to have FolderSSH defined always without a backlash at end for further usage in the batch file.
Please note that it is safe to use %FolderSSH%\ssh-keygen.exe and %FolderSSH%\ssh-keyscan.exe without surrounding " at beginning of the batch script as it is impossible that %FolderSSH% expands to a folder path containing a space or one of these characters &()[]{}^=;!'+,`~.
But "%FolderSSH%\ssh-keygen.exe" and "%FolderSSH%\ssh-keyscan.exe" must be used on the command lines below the label UseOpenSSH because it could happen that WHERE was used to find the two executables anywhere on system drive and for that reason %FolderSSH% could expand now to a folder path containing a space or a character with a special meaning for Windows command processor outside a double quoted argument string.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
goto /?
if /?
rem /?
set /?
where /?
Read also the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded where command line with using a separate command process started in background with %ComSpec% /c and the command line between ' appended as additional arguments on which 2^>nul became already 2>nul.
The following idea also uses the where.exe command, as mentioned in the comments. This one will search the system drive for ssh-keyscan.exe, and if found will ensure that ssh-keygen.exe is also located there. If both are located in the same place, then it is considered as already installed:
#Set "dirOpenSSH="
#For /F Delims^= %%G In (
'%__AppDir__%where.exe /R %SystemDrive%\ ssh-keyscan.exe 2^>NUL'
)Do #For /F Delims^= %%H In (
'%__AppDir__%where.exe "%%~dpG.":ssh-keygen.exe 2^>NUL'
)Do #Set "dirOpenSSH=%%~dpH"
#If Defined dirOpenSSH (
Echo OpenSSH is available at %dirOpenSSH%.
%__AppDir__%timeout.exe 3 /NoBreak>NUL
GoTo skipopenSSH
)
#Echo OpenSSH is not available, beginning installation.
#%__AppDir__%timeout.exe 3 >NUL
:skipopenSSH
Please note that where.exe and timeout.exe require a minimum OS version of Windows NT 6.x
As your application is currently a 32-bit one, the console session it is using is not accessing the 64-bit locations. To fix that you could replace %__AppDir__%where.exe, with %SystemRoot%\SysNative\where.exe
It is probably worth mentioning that in the versions of windows-10 with OpenSSH part of the base OS, the location, %SYSTEMROOT%\System32\OpenSSH\, should exist in %PATH%, so you should be able to find your files directly using them:
%__AppDir__%where.exe ssh-keygen.exe
%__AppDir__%where.exe ssh-keyscan.exe
For %I In (ssh-keygen.exe) Do #Echo %~$PATH:I
For %I In (ssh-keyscan.exe) Do #Echo %~$PATH:I
I have found on the systems which have upgraded from an earlier version of Windows, that many of the default locations using C:\Windows were replicated, but using %SYSTEMROOT%/%SystemRoot% instead.
In that state, the Where command and For's %~$PATH: failed to locate some items which did exist and should have been found.
Removing the duplicated items, I removed those which were carried over, (those not using variables), although removing either format seems to have worked fine.
Both where and %~$PATH: were then functioning as intended.

Run program in subfolders

I'm trying to write a Windows batch script to run 2 programs through a bunch of folders. I'm not an expert at shell scripting but I try my best.
Here's what I'm trying to run through each folder...
The input for program1 is a .extension1 file which then produces a .extension2 file which then is run through program2 to generate what I need.
Before I run the script I cd into the folder. The programs are copied to the folder because they only work in the current working directory.
copy C:\program1 .
copy C:\program2 .
for %i in (*.extension1) do program1 "%i"
for %i in (*.extension2) do program2 "%i"
The data folder shown above contains hundreds of folders that I need to run the program in. I'd like to be able to do this in one big batch script.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir\one"
PUSHD "%sourcedir%"
FOR /r %%a IN (*.ext1) DO (
PUSHD "%%~dpa"
ECHO(c:\program1 "%%~nxa"
popd
)
popd
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
In all probability, this is all you would need - or at least, this is a framework.
Note that the routine will simply ECHO the required commands. This allows a harmless test (on a representative sub-tree) to ensure that the process should work on the entire tree.
Changing ECHO(c:\program1 to c:\program1 should execute the first program on each .ext1 file in the sub-tree. It would be unusual for a program to check that the file exists within the same directory as the executable - if it won't take a path, then "the current directory" would be assumed.
You don't say whether the program program1 produces a file called whatever.ext2 from whatever.ext1 or whether it produces somethingradicallydifferent.ext2. In all probability, the same name would be used.
If that is the case, then to run the second program, simply add after
ECHO(c:\program1 "%%~nxa"
ECHO(c:\program2 "%%~na.ext2"
Otherwise, simply repeat the entire block, changing ext1 to ext2
(I'll assume you can figure out that I've abbreviated the extensions)
If, on the off-chance the program(s) need to be in the same directory, then replace
ECHO(c:\program1 "%%~nxa"
with
echo n|C:\program1 . >nul 2>nul
ECHO(program1 "%%~nxa"
(and ditto for program 2, obviously). Here the n is echoed into the copy, so that the copy will only take place once. This could be improved but is probably only a theoretical requirement anyway since it's 99.9999% likely that executing c:\program? will work quite happily.

How would I run a batch program from another batch program within its own environment?

I need to run a batch file located in another folder that must be called from another batch file.
Whenever I do call this batch file from the first, let's call them Batch_A and Batch_B, respectively, the second tries to run from the directory of the first batch file.
Batch_A needs to call or start Batch_B, however Batch_B needs to run as if I were to manually double-click it myself.
This is what I currently have at the end of my first batch
start "A thing" "%output%\thing.bat" /b
Have you looked into push or pop.
Before calling the second batch file, enter the "push" command:
pushd %dynamicdirectory%
Call batchfileb.bat
popd
If Batch_B is designed/written to be always run from the direcory where it is located
you might also consider to modify Batch_B.bat
setlocal
cd /D %0\..
REM your original content
endlocal
In %0 the path to the batchfile is stored.
The trick is to assume %0 is a directory then to change one level lower
based on that diretory.
With /D also the drive letter is changed correctly.
The cd command doesn't care if %0 is really a directory.
In fact %d doesn't even have to exist (%0\dummy\..\.. would also work).
The setlocal command is to have the working directory beeing restored
when Batch_B.bat has finished.
I noticed that the endlocal command is not really necessary
in this context since it is applied imlicitely when Batch_B finishes.

Find a program and run it through command prompt

I want to be able to locate where the exe of a (third-party) program I remember from only its name. (say photoshop.exe) Is that possible?
Like you can call taskmrg.exe
try this to find:
dir /s c:\photoshop.exe
..and also to run:
for /f "delims=" %a in ('dir /b /a-d /s "c:\photoshop.exe"') do "%~fa"
Yes you can do that of course, but it involves searching for the file recursively in every folder of your hard drive partition(s).
Another way is to add the folder containing the .exe you want to execute in the PATH environment variable but it's not recommended to add every program you own to the PATH. (It's meant to remain quite small in size).
Here's the syntax of FIND command in dos.
http://www.computerhope.com/findhlp.htm
taskmgr.exe can be executed from any path at the command prompt, because its location falls within the directories listed in the %PATH% variable. You can potentially add any additional folders you would like to this variable to make any applications within follow the same behavior. Caveat: Some applications do not run properly unless started from within their home directory.
Editing the %PATH% variable via the GUI varies between versions of Windows, or you can edit it from the command prompt.

Batch ~dp0 doesn't work with admin rights?

I have a batch file which looks like this:
set OWNPATH = %~dp0
for /r %OWNPATH% %%F in (*.ocx) do ( echo %%F )
It correctly lists all OCX files in the same folder when I start it, but lists the OCX files in
C:\Windows\System32
when I right-click it and select "Run as administrator".
How can I fix that? The script generally needs admin rights.
Your set is setting %OWNPATH % (note the space between OWNPATH and the =). Therefore %OWNPATH% (with no space) is not defined, and for /r %OWNPATH% %%F ... gets expanded to for /r %%F, and the for loop ends up looking in the current directory (which is C:\Windows\System32 when run as administrator).
Get in the habit of doing your assignments like this to avoid that common mistake:
set "OWNPATH=%~dp0"

Resources