Reputation: 125
::Set the command to cmd
set cmd="wmic useraccount where name='%username%' get sid"
::Set the output to variable User
set "User="
for /f "skip=1 delims=" %%i in ('%cmd%') do if not defined User set "User=%%i"
::Output the variable
echo %User%
::This part doesn't work
::Change registry key, using variable as placeholder
reg add "HKEY_USERS\%User%\example" /v exampleKey /d "1" /t REG_DWORD /f
pause >nul
I thought it would work, but apparently I'm doing something wrong. I get:
ERROR: The parameter is incorrect.
Upvotes: 1
Views: 973
Reputation: 49086
I don't know why first assigning the command to execute by FOR to an environment variable enclosed in double quotes and then reference the value of that environment variable with immediate expansion.
It makes a huge difference where the first double quote is placed on assigning a string to an environment variable as it can be read for example on How to set environment variables with spaces?
It would be better to specify the WMIC command line directly and escape the equal sign with caret character ^
and use additionally the option /VALUE
to get SID=...
output on a line.
::Set the output to variable UserSID
set "UserSID="
for /F "usebackq tokens=2 delims==" %%I in (`%SystemRoot%\System32\wbem\wmic.exe UserAccount where name^='%USERNAME%' GET SID /VALUE`) do set "UserSID=%%I"
::Output the variable
echo UserSID=%UserSID%
::Change registry key, using variable as placeholder.
%SystemRoot%\System32\reg.exe add "HKEY_USERS\%UserSID%\example" /V exampleKey /D 1 /T REG_DWORD /F
The command WMIC outputs always in Unicode which means with 2 bytes per character using UTF-16 Little Endian encoding with Byte Order Mark (BOM).
For example the output of the command
wmic useraccount where name='%username%' get sid
redirected into a file is
000h: FF FE 53 00 49 00 44 00 20 00 20 00 20 00 20 00 ; ÿþS.I.D. . . . .
010h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
020h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
030h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
040h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
050h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
060h: 0D 00 0A 00 53 00 2D 00 31 00 2D 00 35 00 2D 00 ; ....S.-.1.-.5.-.
070h: 32 00 31 00 2D 00 31 00 39 00 35 00 37 00 39 00 ; 2.1.-.1.9.5.7.9.
080h: 39 00 34 00 34 00 38 00 38 00 2D 00 36 00 38 00 ; 9.4.4.8.8.-.6.8.
090h: 38 00 37 00 38 00 39 00 38 00 34 00 35 00 2D 00 ; 8.7.8.9.8.4.5.-.
0a0h: 31 00 38 00 30 00 31 00 36 00 37 00 34 00 35 00 ; 1.8.0.1.6.7.4.5.
0b0h: 33 00 31 00 2D 00 31 00 30 00 30 00 33 00 20 00 ; 3.1.-.1.0.0.3. .
0c0h: 20 00 0D 00 0A 00 0D 00 0A 00 ; .........
which is displayed in a command prompt window as:
SID············································•¶
S-1-5-21-1957994488-688789845-1801674531-1003··•¶
•¶
Note: The character ·
is used here and below as placeholder for a space character, •
represents a carriage return and ¶
represents a line-feed to make the whitespace characters visible.
Command FOR processes captured output with one byte per character. So it should process:
000h: 53 49 44 20 20 20 20 20 20 20 20 20 20 20 20 20 ; SID
010h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
020h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0D ; .
030h: 0A 53 2D 31 2D 35 2D 32 31 2D 31 39 35 37 39 39 ; .S-1-5-21-195799
040h: 34 34 38 38 2D 36 38 38 37 38 39 38 34 35 2D 31 ; 4488-688789845-1
050h: 38 30 31 36 37 34 35 33 31 2D 31 30 30 33 20 20 ; 801674531-1003
060h: 0D 0A 0D 0A ; ....
That text would be output into command prompt window exactly like the Unicode text.
But FOR does not make a good job on converting Unicode to ASCII/ANSI/OEM. The result is that FOR processes:
000h: 53 49 44 20 20 20 20 20 20 20 20 20 20 20 20 20 ; SID
010h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
020h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 0D ; .
030h: 0D 0A 53 2D 31 2D 35 2D 32 31 2D 31 39 35 37 39 ; ..S-1-5-21-19579
040h: 39 34 34 38 38 2D 36 38 38 37 38 39 38 34 35 2D ; 94488-688789845-
050h: 31 38 30 31 36 37 34 35 33 31 2D 31 30 30 33 20 ; 1801674531-1003
060h: 20 0D 0D 0A ; ...
This text printed to command output window would be:
SID············································••¶
S-1-5-21-1957994488-688789845-1801674531-1003··••¶
So instead of having two data lines terminated with carriage return and line-feed and one empty line also terminated with carriage return and line-feed, the result is two data lines with being terminated with two carriage returns and a line-feed. This might not be what FOR really parses internally, but what can be seen on using just "delims="
and as command echo %%i
with output redirected into a file.
The wrong conversion of 0D 00 0A 00
to 0D 0D 0A
instead of 0D 0A
is a big problem because of causing weird parsing of the last two lines output by WMIC.
There are two interpretations possible and it depends on version of Windows what happens:
The last line with data is interpreted as data line with an additional carriage return at end not being discarded on assigning the complete line to the loop variable and next to the environment variable.
This happens here on Windows XP.
The environment variable User
has assigned after the FOR loop with "skip=1 delims="
the string: S-1-5-21-1957994488-688789845-1801674531-1003··•
The last line with data is interpreted as data line being first assigned to loop variable and next to environment variable.
Then FOR processes one more line containing just a carriage return which is also assigned to loop variable and which would be also assigned to the environment variable.
This happens here on Windows Vista and later versions of Windows.
The IF condition if not defined User
prevents overwriting value of environment variable User
having already the SID assigned by just a carriage return.
The environment variable User
has assigned after the FOR loop with "skip=1 delims="
the string: S-1-5-21-1957994488-688789845-1801674531-1003··
So it should be clear now why the reg add
command line fails although the output of environment variable User
not making the whitespace characters visible looks right. The environment variable contains either two spaces or two spaces and a carriage return at end after the SID string.
Now let us look on output of the command line
%SystemRoot%\System32\wbem\wmic.exe UserAccount where name='%USERNAME%' GET SID /VALUE
by redirecting the output into a file and looking on it with a hex viewer/editor
000h: FF FE 0D 00 0A 00 0D 00 0A 00 53 00 49 00 44 00 ; ÿþ........S.I.D.
010h: 3D 00 53 00 2D 00 31 00 2D 00 35 00 2D 00 32 00 ; =.S.-.1.-.5.-.2.
020h: 31 00 2D 00 31 00 39 00 35 00 37 00 39 00 39 00 ; 1.-.1.9.5.7.9.9.
030h: 34 00 34 00 38 00 38 00 2D 00 36 00 38 00 38 00 ; 4.4.8.8.-.6.8.8.
040h: 37 00 38 00 39 00 38 00 34 00 35 00 2D 00 31 00 ; 7.8.9.8.4.5.-.1.
050h: 38 00 30 00 31 00 36 00 37 00 34 00 35 00 33 00 ; 8.0.1.6.7.4.5.3.
060h: 31 00 2D 00 31 00 30 00 30 00 33 00 0D 00 0A 00 ; 1.-.1.0.0.3.....
070h: 0D 00 0A 00 0D 00 0A 00 ; ........
and also printing into console window
•¶
•¶
SID=S-1-5-21-1957994488-688789845-1801674531-1003•¶
•¶
•¶
There are no spaces anymore. The name of the value and its current value are printed on one line with an equal sign between. Two really empty lines are output additionally by WMIC above and below on using option /VALUE
with that value query.
Of course the command FOR does again the conversion from Unicode to ASCII/ANSI/OEM not correct which could be again a problem. But this time the FOR options are different in comparison to code in question.
"usebackq tokens=2 delims=="
means that the equal sign is a delimiter character to split up the line into multiple strings (tokens) and only the second string (token) is of interest for further processing. Empty lines are always skipped by command FOR. But the command set "UserSID=%%I"
is also not executed if FOR fails to determine a none empty SECOND string from the parsed line. For that reason only third line with SID=...
is resulting in execution of SET command, and end of WMIC output being misinterpreted as line having only a carriage return is ignored like an empty line because no string after an equal sign can be found here by FOR.
The different WMIC output with different FOR parsing results in environment variable UserSID
having assigned the value:
S-1-5-21-1957994488-688789845-1801674531-1003
There are no whitespaces at end of the environment variable value.
And now the reg add
command line works of course as there are no trailing whitespaces anymore.
See also the answers on the questions How to correct variable overwriting misbehavior when parsing output and cmd is somehow writing chinese text as output on how to get Unicode output of WMIC correct converted to ASCII/ANSI/OEM if it is not possible to change output format of WMIC and use a different data parsing by command FOR to workaround the line ending conversion bug of FOR.
Upvotes: 1
Reputation: 38579
If there was a good reason to write to that key instead of the mapped HKCU key then I'd do it like this:
@Echo Off
For /F "Skip=1 Delims=" %%A In (
'"WMIC UserAccount Where (Name='%UserName%') Get SID"') Do For %%B In (%%A
) Do Reg Add "HKU\%%B\Example" /V ExampleKey /T Reg_DWord /D 1 /F>Nul
Upvotes: 0