Checking for XP via the registry using this script in batch.
@echo off
pushd %~dp0
for /f "usebackq tokens=*" %%A in ("%~dp0pxhosts.txt") do (
reg query "\\%%A\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL && set OS=XP || set OS=NEWER
echo %os%
pause
)
in pxhost I have the list of pc's to check for xp and then do something, or not. However I cant get the above to work. The variable is never set and it just echos back "windows_NT". If, however, I take the for loop out and run the reg query without the variable:-
reg query "\\xp-4c54fa50d0da\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL && set OS=XP || set OS=NEWER
the echo works and reports "XP", or "newer" if I change "5.1" to "5.7" for test purposes.
What's going on? Thanks.
thanks for answers but now I have more problems
From here I can now echo the right responses but the calling doesn't work at all. I have an XP, win 7 32 and win 10 64 in test in the text file pxhosts. XP is first in the list and gets ignored even when it is echo'd back correctly. something is stopping the calling from happening. Really driving me mental this lol.
I am trying to write a remote permissions script that applies to either XP filr system or 32 or 64 (newer windows). The total code is below:-
@echo off
setlocal enabledelayedexpansion
for /f "usebackq tokens=*" %%A in ("%~dp0pxhosts.txt") do (
reg query "\\%%A\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL && set pctype=XP || set pctype=NEWER
cls
echo !pctype!
pause
if !pctype! == !XP! ( call :XP !%%A!)
reg query "\\%%A\HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set arc=32 || set arc=64
cls
echo !arc!
pause
if !arc! == !64! ( call :64 !%%A!)
if !arc! == !32! ( call :32 !%%A!)
)
:32
echo 32 okay
pause
icacls "\\%1\C$\ProgramData\folderFoo" /T /C /grant(:r) "Domain Users":(OI)(CI)(F) /inheritance:e >> "%~dp0%1.txt" 2>&1
pause
rem return from a subroutine
exit /B
:64
echo 64 okay
pause
icacls "\\%1\C$\Program Files (x86)\Folderfoo" /T /C /grant(:r) "Domain Users":(OI)(CI)(F) /inheritance:e >> "%~dp0%1.txt" 2>&1
pause
rem return from a subroutine
exit /B
:XP
echo xp okay
pause
CACLS "\\%1\C$\Documents and Settings\All Users\Application Data\Folderfoo" /E /T /C /G "Domain Users":F >> "%~dp0%1.txt" 2>&1
pause
rem return from a subroutine
exit /B
new edit 201216
for /f "usebackq tokens=*" %%A in ("%~dp0pxhosts.txt") do (
reg query "\\%%A\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL
IF %ERRORLEVEL%==0 set pctype=XP
IF %ERRORLEVEL%==1 set pctype=NO
reg query "\\%%A\HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL
IF %ERRORLEVEL%==0 set arc=32
IF %ERRORLEVEL%==1 set arc=64
IF !pctype!==XP (call :xp %%A)
IF !pctype!==NO IF !arc!==32 (call :32 %%A)
IF !arc!==64 (call :64 %%A)
)
This is now picking up the 64 or 32 using reg query, however because an XP machine will always be a 32 bit machine it keeps running the code for newer windows PC with 32 bit as well. My subroutines for XP are dealing with docuemnts and settings folder, newer 32 machines just the user folder format.
I need to run a subroutine on XP machines, 32 bit newer machines and 64 bit machines. At the moment xp code runs on 32 bit machines and vice versa because they share 32 bit architecture.
I have tried above to eradicate the problem by only running 32 bit routine if the pc is newer with a 32 bit file structure by way of variables (2nd line of IF's). Thanks :)
If the thingy works without the for-loop and the variable is not set within a for-loop consider a search for something like Batch variable not set in for-loop
and boom there will be a plenty of questions like yours.
Answer is the same for all:
Use Delayed Expansion!
To use that, add the line setlocal EnableDelayedExpansion
to the beginning of the batch-file and whereever you need a variable in a closed set of parenthesis like a for-loop or an if-condition change %myVar%
to !myVar!
.
Example to verify:
@echo off
setlocal EnableDelayedExpansion
set foo=foo
if 1==1 (
set foo=bar
echo Not delayed: %foo%
echo Delayed: !foo!
) ELSE (
echo If you land here something went heavily wrong...
)
Reasoning:
In batch closed sets of parenthesis are calculated when the beginning is reached. In the above example that means that when the program reaches if 1==1
it knows the value of foo
as "foo" eventhough I changed it seemingly before.
An alternative is to use
call echo %%myVar%%
In your example however you would not even need that variable... In the same positions where you set the value of OS
you could as well simply echo it:
... && set OS=XP || set OS=NEWER
-> ... && echo XP || echo NEWER
You only and really only need exclamation marks when accessing a variable that got set within the loop! You made two major mistakes I spotted so far:
1) For-Loop variables are set in the loops header and with that are an exception from this rule: %%A
is the correct way of accessing it and not !%%A!
2) If you want to make a string comparison like if varValue == thisString
you should NOT surround the string to check with exclamation marks:
if !arc!==64
should do the trick here!
Else the comparison would look like if 64==!64!
which is not the desired behaviour I guess.
Read your questions edit closer again:
Something is stopping the calling from happening
Exactly the problem with the if described above in point 2 :)
After a short search and playing around a bit with the results I came up with this (Windows 7+ required on executing machine; tested with Windows 10 Pro):
@echo off
setlocal EnableDelayedExpansion
for /f "usebackq tokens=*" %%A in ("%~dp0pxhosts.txt") do (
for /f "tokens=2 delims=:" %%B in ('systeminfo /s "%%~A" ^| findstr /i "Systemtype"') do (
call :removeLeadingSpaces "%%~B" type
echo !type!
)
for /f "tokens=2 delims=:" %%C in ('systeminfo /s "%%~A" ^| findstr /i "Operatingsystemname"') do (
call :removeLeadingSpaces "%%~C" osName
echo !osName!
)
)
pause
Goto:eof
:removeLeadingSpaces
for /f "tokens=* delims= " %%f in ("%~1") do set %2=%%f
Explanation:
Reads the computernames from the file as it already does. Takes the second part from the output of the command systeminfo /s <computername>
queried for the specific strings "Systemtype" and "Operatingsystemname". The ^
is there to escape the piping symbol |
. It then sends the string to a subfunction that truncates the leading spaces and sets them to the specified variable.
NOTE: The strings used to query may vary for a different language setting! Those above are freely translated from my German OS! To check how they are for your language setting go ahead and open a commandprompt and type systeminfo
and hit Enter Now look for the ones you need.
Systemtype outputs the processor architecture and OSname the name of the operating system (who would have thought that ey?). If you have found what you need change the strings from my example to your needs.
From where it says echo !type!
and echo !osName!
do whatever you want with those variables. Any questions left? Feel free to ask!
Your problem (I think) is here:
reg query "\\%%A\HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set arc=32 || set arc=64
IF ERRORLEVEL==0 set arc=32
IF ERRORLEVEL==1 set arc=64
When using the way of processing the outcome of the find directly using && echo positive result || echo negative result
the errorlevel will always reside at 0! So you got two ways of handling this:
&& set arc=32 || set arc=64
so the errorlevel is set accordingly to the outcome of the command as it is already done at the check for XPYou can test this on your own in the commandline with the queries from your question:
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL
echo %ERRORLEVEL%
This should echo 1 if you do not have an XP-computer (what I hope for you ;) ). This is because find
could not find the string specified -> falsey value.
Now reset the errorlevel:
set ERRORLEVEL=0
And try this one:
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL && echo should be 0 || echo should be 1
Would be the version without direct errorlevel handling but with acting according to the direct result of the find
command.
Now do echo %ERRORLEVEL%
You will notice that it is 0 eventhough the above command should have returned a falsey value.
In the end it was one lethal space too much... ONE SPACE screwing up parts of the script.
Base script:
@echo off
setlocal EnableDelayedExpansion
pushd %~dp0
for /f "usebackq tokens=*" %%A in ("%~dp0pxhosts.txt") do (
reg query "\\%%A\HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" | find /i "5.1" > NUL
IF !ERRORLEVEL!==0 set pctype=XP
IF !ERRORLEVEL!==1 set pctype=NOXP
CLS
reg query "\\%%A\HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL
IF !ERRORLEVEL!==0 set arc=fs1
IF !ERRORLEVEL!==1 set arc=fs2
CLS
IF !pctype!==XP (call :XPFS %%A)
IF !pctype!==NOXP IF !arc!==fs1 (call :type1 %%A)
IF !arc!==fs2 (call :type2 %%A)
)
Goto :eof
:XPFS
REM Do things for XP computer
Goto :eof
:type1
REM Do things for 32-bit computer
Goto :eof
:type2
REM Do things for 64-bit computer
Goto :eof