Why can the wmic data from a text file not be processed because of some weird character coding problem? - batch-file

I've been working on a little script that determines which disk is usable in our specific system. There has to be basically less than 1 TB of space on the disk in order to be considered as usable.
This is the complete code:
#echo off
chcp 65001>nul
setlocal enabledelayedexpansion
wmic logicaldisk get caption,freespace>c:\cmd\1\getDiskInfo.txt
for /f "tokens=1,2 eol=C" %%I in (C:\cmd\1\getDiskInfo.txt) do (
set diskCaption=%%I
set diskFreeSpace=%%J
set captionFreeSpace=!diskCaption! !diskFreeSpace!
for /f "tokens=1,2 delims= " %%X in ("!captionFreeSpace!") do (
if [%%Y] neq [] set usedDisks=%%X %%Y
for /f "tokens=1,2 delims= " %%A in ("!usedDisks!") do (
set freeSpaceFirstChar=%%B
set /a freeSpaceFirstChar=!freeSpaceFirstChar:~0,1!
if !freeSpaceFirstChar! gtr 1 set usableDisk=%%A
)
)
)
echo %usableDisk%
pause
But the output I get for %usableDisk% is always ECHO is off. which means that %usableDisk% does not even exist. I've done a little investigation and from my understanding it's because of a character coding related problem. I've copied the content of getDiskInfo.txt to another .txt file, and the batch file managed to give me the right output with that text file created by me.
The contents of getDiskInfo.txt and the other text file was both:
Caption FreeSpace
A:
B: 1098552672256
C: 40824201216
D:
E: 1042498560000
F: 40222941184
The output of the original script created file was ECHO is off.. The output with the text file created by me was F: which is the correct output because we can't use the system drive C:.
So I tried echo END OF FILE>>getDiskInfo.txt and it added the line 久⁄䙏䘠䱉൅ to the script created file, but the same command added END OF FILE to my text file. I'm completely lost on this one.
Do you have any suggestions or probable solutions?

There are multiple problems to solve for this task to get the drive letter of a (local) hard disk drive with less than one TiB (1 099 511 627 776 bytes) free space which is not the system drive.
1. Character encoding of WMIC output
WMIC outputs data always with character encoding UTF-16 Little Endian with byte order mark abbreviated as UTF-16LE+BOM.
So the data output
Caption FreeSpace
A:
B: 1098552672256
C: 40824201216
D:
E: 1042498560000
F: 40222941184
is as byte stream with byte offset left to : and ASCII representation right to ;:
0000h: FF FE 43 00 61 00 70 00 74 00 69 00 6F 00 6E 00 ; ÿþC.a.p.t.i.o.n.
0010h: 20 00 20 00 46 00 72 00 65 00 65 00 53 00 70 00 ; . .F.r.e.e.S.p.
0020h: 61 00 63 00 65 00 20 00 20 00 20 00 20 00 20 00 ; a.c.e. . . . . .
0030h: 20 00 0D 00 0A 00 41 00 3A 00 20 00 20 00 20 00 ; .....A.:. . . .
0040h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0050h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0060h: 20 00 20 00 20 00 0D 00 0A 00 42 00 3A 00 20 00 ; . . .....B.:. .
0070h: 20 00 20 00 20 00 20 00 20 00 20 00 31 00 30 00 ; . . . . . .1.0.
0080h: 39 00 38 00 35 00 35 00 32 00 36 00 37 00 32 00 ; 9.8.5.5.2.6.7.2.
0090h: 32 00 35 00 36 00 20 00 20 00 0D 00 0A 00 43 00 ; 2.5.6. . .....C.
00a0h: 3A 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; :. . . . . . . .
00b0h: 34 00 30 00 38 00 32 00 34 00 32 00 30 00 31 00 ; 4.0.8.2.4.2.0.1.
00c0h: 32 00 31 00 36 00 20 00 20 00 20 00 20 00 0D 00 ; 2.1.6. . . . ...
00d0h: 0A 00 44 00 3A 00 20 00 20 00 20 00 20 00 20 00 ; ..D.:. . . . . .
00e0h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
00f0h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0100h: 20 00 0D 00 0A 00 45 00 3A 00 20 00 20 00 20 00 ; .....E.:. . . .
0110h: 20 00 20 00 20 00 20 00 31 00 30 00 34 00 32 00 ; . . . .1.0.4.2.
0120h: 34 00 39 00 38 00 35 00 36 00 30 00 30 00 30 00 ; 4.9.8.5.6.0.0.0.
0130h: 30 00 20 00 20 00 0D 00 0A 00 46 00 3A 00 20 00 ; 0. . .....F.:. .
0140h: 20 00 20 00 20 00 20 00 20 00 20 00 34 00 30 00 ; . . . . . .4.0.
0150h: 32 00 32 00 32 00 39 00 34 00 31 00 31 00 38 00 ; 2.2.2.9.4.1.1.8.
0160h: 34 00 20 00 20 00 20 00 20 00 0D 00 0A 00 ; 4. . . . .....
But Windows command processor expects a one byte per character encoding using the code page as output on running in an opened command prompt window the command chcp. The code page depends on which country is configured for the account used to run the command process processing the batch file.
The command line chcp 65001>nul to change to Unicode encoding UTF-8 is of no help here.
Processing UTF-16LE encoded output with FOR directly cause troubles as documented on Stack Overflow multiple times, see for example How to correct variable overwriting misbehavior when parsing output?
A solution would be to redirect the output of WMIC into a temporary file, output this temporary file to handle STDOUT (standard output) of a command process started in background with %ComSpec% /c using the command TYPE with capturing this output by the command process executing the batch file, process this ASCII output line by line, and finally delete the temporary file.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET Caption,FreeSpace >"%TEMP%\%~n0.tmp"
if not exist "%TEMP%\%~n0.tmp" goto EndBatch
for /F "skip=1 tokens=1,2" %%I in ('type "%TEMP%\%~n0.tmp"') do echo %%I %%J
del "%TEMP%\%~n0.tmp"
:EndBatch
endlocal
In this case FOR processes the ASCII byte stream:
000h: 43 61 70 74 69 6F 6E 20 20 46 72 65 65 53 70 61 ; Caption FreeSpa
010h: 63 65 20 20 20 20 20 20 0D 0A 41 3A 20 20 20 20 ; ce ..A:
020h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
030h: 20 20 0D 0A 42 3A 20 20 20 20 20 20 20 31 30 39 ; ..B: 109
040h: 38 35 35 32 36 37 32 32 35 36 20 20 0D 0A 43 3A ; 8552672256 ..C:
050h: 20 20 20 20 20 20 20 34 30 38 32 34 32 30 31 32 ; 408242012
060h: 31 36 20 20 20 20 0D 0A 44 3A 20 20 20 20 20 20 ; 16 ..D:
070h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
080h: 0D 0A 45 3A 20 20 20 20 20 20 20 31 30 34 32 34 ; ..E: 10424
090h: 39 38 35 36 30 30 30 30 20 20 0D 0A 46 3A 20 20 ; 98560000 ..F:
0a0h: 20 20 20 20 20 34 30 32 32 32 39 34 31 31 38 34 ; 40222941184
0b0h: 20 20 20 20 0D 0A ; ..
But it is in general always better to avoid the usage of a temporary file as there is never the guarantee that the temporary file can be created at all during the execution of the batch file.
2. System drive is not always C:
Windows is installed by default on drive C: and so the system drive is C:. But Windows can be installed also to a different drive in which case the system drive is not C:. Any code depending on default data instead of using the appropriate data is a not good written code.
There is predefined the Windows environment variable SystemDrive with the drive letter and the colon of the drive on which active Windows is installed. The environment variable SystemRoot contains the path to the Windows directory which contains the directory System32 with all executables from the Windows Commands list which are not internal commands of cmd.exe.
All those system environment variables can be seen with their values on opening a command prompt window and running set system. Running just set outputs all environment variables with their values defined for the current user account.
3. Integer value range is limited to 32-bit signed integer
The Windows command processor cmd.exe uses always only 32-bit signed integer on evaluation of an arithmetic expression with set /A and for comparing integer values with command IF on using the operators EQU, NEQ, LSS, LEQ, GTR, GEQ.
Therefore the integer value range is −2147483648 to 2147483647. So maximum is one byte less than 2 GiB. The value is 1099511627776 requires 64-bit integer value range not supported by cmd.exe.
BTW: if [%%Y] neq [] is never a good comparison because of [ and ] have no special meaning for Windows command processor and neq results here first in the approach to convert the left string into a 32-bit signed integer value which fails because of [ is an invalid character for an integer value and therefore running next a string comparison with condition being true if the string comparison returns not 0, i.e. the compared strings are not equal. Better would be if not "%%Y" == "" which runs directly and more safely a string comparison on not equal strings. See Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files for details on how command IF executes a string comparison.
Solution to get drives with less than one TiB free space
It is a good idea to read the documentation of a class of which properties are accessed using the Windows Management Instrumentation Command-line utility. This is here the Win32_LogicalDisk class.
There is in addition to FreeSpace of type uint64 and DeviceID of type string instead of Caption perhaps also useful the property DriveType of type uint32 to filter out drives of wrong type in addition to drives with too much free space and the system drive by using a where clause on wmic execution.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "UsableDrive="
for /F "skip=1 tokens=1,2" %%I in ('""%SystemRoot%\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace^<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace 2>nul"') do (
echo Drive %%I has %%J free bytes.
if not defined UsableDrive set "UsableDrive=%%I"
)
if defined UsableDrive echo Selected drive %UsableDrive%
endlocal
Important to know here is that FOR starts in background with %ComSpec% /c one more command process with the command line specified within ' appended as additional arguments. For that reason the command line with WMIC must fulfill the Windows command processor requirements described by help output on running cmd /? in a command prompt window on being in total three times parsed.
The first parsing is done by cmd.exe processing the batch file before executing command FOR.
The second parsing is done by cmd.exe instance on starting it in background by the cmd.exe instance processing the batch file with the following command line on Windows installed to C:\Windows.
C:\Windows\System32\cmd.exe /c ""C:\WINDOWS\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace^<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace 2>nul"
The third parsing is done by the background command process before executing wmic.exe. The operator < in where clause must be interpreted as literal character and not as redirection operator which is the reason why < is escaped with ^ to run wmic.exe finally with:
"C:\Windows\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace
WMIC filters out with DriveType=3 all network drives, floppy disk drives, CD and DVD drives and other removable drives, RAM disks, etc. Hard disks connected to the computer using an external USB port or an eSATA port are not filtered out because of those drives have also value 3 for the drive type. Windows cannot determine if a hard disk is mounted inside the casing of the computer or outside. So a local hard disk is any hard disk connected to the computer, internal and external hard disks.
The system drive is filtered out with second condition DeviceID!='%SystemDrive%'.
The last condition FreeSpace<1099511627776 results in ignoring all drives with 1 TiB or more free space.
So the list is reduced already to those drives which fulfill all three conditions.
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.
cmd /?
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
type /?
wmic /?
wmic logicaldisk /?
wmic logicaldisk get /?
See also the Microsoft article about Using command redirection operators for an explanation of > and 2>nul.

If I understand your requirements correctly, the following, much shorter, single line batch-file, should output only the usable drives, i.e. which, are not your system drive, and have less than 1 TB of free disk space.
#(For /F "Tokens=1-2" %%G In ('""%__AppDir__%wbem\WMIC.exe" LogicalDisk Where (DeviceID !='%SystemDrive%' And FreeSpace ^<'1000000000000') Get DeviceID,FreeSpace 2>NUL|"%__AppDir%find.exe" ":""')Do #Set "_= %%H"&SetLocal EnableDelayedExpansion&Echo %%G !_:~-14!&EndLocal)&Pause
As you did not explain in your question, what you were doing with the data retrieved, I have simply printed them to the console window in a similar format to your original getDiskInfo.txt, (I even right aligned the bytes column just for fun!).

Related

How to remove new lines in batch file?

I'm working on batch file and export to text file. Seem all of them is ok, but when i open text file, many new lines break. So, i want to remove of them.
#echo OFF
setlocal EnableDelayedExpansion
(
systeminfo |findstr /c:"Host Name" /c:"OS Name" /c:"OS Version" /c:"Original Install Date" /c:"System Manufacturer" /c:"System Model" /c:"System Type" /c:"Total Physical Memory"
wmic bios get serialnumber /Format:list | more | findstr .
wmic cpu get name /Format:list | more | findstr .
echo=%userdomain%\%username%
)> %ComputerName%.txt
The result text file is ok, but still many new lines break, i want to remove of them
Host Name: PGV-PF165HNN
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.18363 N/A Build 18363
Original Install Date: 7/22/2019, 6:28:01 PM
System Manufacturer: LENOVO
System Model: 20JM0009US
System Type: x64-based PC
BIOS Version: LENOVO N1QET87W (1.62 ), 2/27/2020
Total Physical Memory: 8,072 MB
SerialNumber=PF165HNN
Name=Intel(R) Core(TM) i5-6300U CPU # 2.40GHz
WINDOM1\brian.lee
The OS language dependent output of %SystemRoot%\System32\systeminfo.exe is character encoded in ASCII/ANSI/OEM which means one byte per character using the code page as displayed on running in a command prompt window chcp. The code page depends on the country (region) configured for the account used to run the batch file. The code page does not really matter as long as the data of interest do not contain characters with a code value greater 127 (non-ASCII character).
The output of systeminfo filtered by findstr is in binary with hexadecimal offset in file left to colon, hexadecimal values of the bytes, and their ASCII representation after the semicolon:
0000h: 48 6F 73 74 20 4E 61 6D 65 3A 20 20 20 20 20 20 ; Host Name:
0010h: 20 20 20 20 20 20 20 20 20 20 20 50 47 56 2D 50 ; PGV-P
0020h: 46 31 36 35 48 4E 4E 0D 0A 4F 53 20 4E 61 6D 65 ; F165HNN..OS Name
0030h: 3A 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; :
0040h: 20 20 20 20 4D 69 63 72 6F 73 6F 66 74 20 57 69 ; Microsoft Wi
0050h: 6E 64 6F 77 73 20 31 30 20 50 72 6F 0D 0A 4F 53 ; ndows 10 Pro..OS
0060h: 20 56 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 ; Version:
0070h: 20 20 20 20 20 20 20 20 20 31 30 2E 30 2E 31 38 ; 10.0.18
0080h: 33 36 33 20 4E 2F 41 20 42 75 69 6C 64 20 31 38 ; 363 N/A Build 18
0090h: 33 36 33 0D 0A 4F 72 69 67 69 6E 61 6C 20 49 6E ; 363..Original In
00a0h: 73 74 61 6C 6C 20 44 61 74 65 3A 20 20 20 20 20 ; stall Date:
00b0h: 37 2F 32 32 2F 32 30 31 39 2C 20 36 3A 32 38 3A ; 7/22/2019, 6:28:
00c0h: 30 31 20 50 4D 0D 0A 53 79 73 74 65 6D 20 4D 61 ; 01 PM..System Ma
00d0h: 6E 75 66 61 63 74 75 72 65 72 3A 20 20 20 20 20 ; nufacturer:
00e0h: 20 20 4C 45 4E 4F 56 4F 0D 0A 53 79 73 74 65 6D ; LENOVO..System
00f0h: 20 4D 6F 64 65 6C 3A 20 20 20 20 20 20 20 20 20 ; Model:
0100h: 20 20 20 20 20 32 30 4A 4D 30 30 30 39 55 53 0D ; 20JM0009US.
0110h: 0A 53 79 73 74 65 6D 20 54 79 70 65 3A 20 20 20 ; .System Type:
0120h: 20 20 20 20 20 20 20 20 20 20 20 20 78 36 34 2D ; x64-
0130h: 62 61 73 65 64 20 50 43 0D 0A 42 49 4F 53 20 56 ; based PC..BIOS V
0140h: 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 20 20 ; ersion:
0150h: 20 20 20 20 20 4C 45 4E 4F 56 4F 20 4E 31 51 45 ; LENOVO N1QE
0160h: 54 38 37 57 20 28 31 2E 36 32 20 29 2C 20 32 2F ; T87W (1.62 ), 2/
0170h: 32 37 2F 32 30 32 30 0D 0A 54 6F 74 61 6C 20 50 ; 27/2020..Total P
0180h: 68 79 73 69 63 61 6C 20 4D 65 6D 6F 72 79 3A 20 ; hysical Memory:
0190h: 20 20 20 20 38 2C 30 37 32 20 4D 42 0D 0A ; 8,072 MB..
The output of %SystemRoot%\System32\wbem\wmic.exe is always Unicode encoded using UTF-16 Little Endian encoding with byte order mark (BOM). So the output by the two used wmic command lines is with two bytes per character.
The command line wmic bios get serialnumber /Format:list produces in binary the output:
0000h: FF FE 0D 00 0A 00 0D 00 0A 00 53 00 65 00 72 00 ; ÿþ........S.e.r.
0010h: 69 00 61 00 6C 00 4E 00 75 00 6D 00 62 00 65 00 ; i.a.l.N.u.m.b.e.
0020h: 72 00 3D 00 50 00 46 00 31 00 36 00 35 00 48 00 ; r.=.P.F.1.6.5.H.
0030h: 4E 00 4E 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; N.N.............
The first two bytes FF FE is the byte order mark for UTF-16 Little Endian. Each ASCII character is encoded with two bytes (16 bits) with high byte having value 0. The newline characters are carriage return (0D 00) and line-feed (0A 00). There are two empty lines output first, then the line with the data of interest, and finally once again two empty lines.
The command line wmic cpu get name produces in binary the output:
0000h: FF FE 0D 00 0A 00 0D 00 0A 00 4E 00 61 00 6D 00 ; ÿþ........N.a.m.
0010h: 65 00 3D 00 49 00 6E 00 74 00 65 00 6C 00 28 00 ; e.=.I.n.t.e.l.(.
0020h: 52 00 29 00 20 00 43 00 6F 00 72 00 65 00 28 00 ; R.). .C.o.r.e.(.
0030h: 54 00 4D 00 29 00 20 00 69 00 35 00 2D 00 36 00 ; T.M.). .i.5.-.6.
0040h: 33 00 30 00 30 00 55 00 20 00 43 00 50 00 55 00 ; 3.0.0.U. .C.P.U.
0050h: 20 00 40 00 20 00 32 00 2E 00 34 00 30 00 47 00 ; .#. .2...4.0.G.
0060h: 48 00 7A 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; H.z.............
The Unicode output is redirected by cmd.exe processing the batch file to more which outputs the lines now with one byte per character. But Windows command processor has a bug on interpreting UTF-16 LE encoded lines as it can be seen on using the following command line:
wmic bios get serialnumber /Format:list | more >output.txt
The file output.txt contains the binary bytes:
0000h: 0D 0D 0A 0D 0D 0A 53 65 72 69 61 6C 4E 75 6D 62 ; ......SerialNumb
0010h: 65 72 3D 50 46 31 36 35 48 4E 4E 0D 0D 0A 0D 0D ; er=PF165HNN.....
0020h: 0A 0D 0D 0A 0D 0A 0D 0A ; ........
Each Unicode encoded carriage return + line-feed (0D 00 0A 00) becomes ASCII encoded carriage return + carriage return + line-feed (0D 0D 0A).
That is the real problem here. The additional carriage return results on using regular expression search string . to match all lines with at least one character that also the empty lines are matched by this regular expression search string on output converted not correct from Unicode to ASCII.
It depends on used text editor how the not valid sequence of newline characters are interpreted. Most text editors interpret the carriage return without line-feed as line termination, but findstr does not do that.
One solution is explicitly searching for the line which contains the data of interest.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE | %SystemRoot%\System32\findstr.exe /L /C:SerialNumber
%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE | %SystemRoot%\System32\findstr.exe /L /C:Name
echo %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal
The data written into file %ComputerName%.txt is completely encoded in ASCII with everywhere used just 0D 0A as line termination.
Some additional information about small changes on code:
The command more is omitted as not really necessary. The not correct conversion from Unicode to ASCII is done by Windows command processor cmd.exe.
Delayed environment variable expansion is not enabled by this batch file as not needed at all.
All executables are specified with well-known full qualified file name. So cmd.exe has not to search for the executables using the values of the environment variables PATHEXT and PATH.
WMIC option /Format:list is replaced by option /VALUE which results in same output.
FINDSTR is run with option /L to explicitly instruct findstr to run a literal search although that is the default on using option /C:.
An even better batch file code would be:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number: %%J
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name: %%J
echo Domain\User Name: %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal
The additional data determined with WMIC and output with ECHO are written into the text file in same format as the output of systeminfo.
Attention: The last echo command line is not safe in case of value of environment variable USERDOMAIN or of environment variable USERNAME contains ) or &. 100% safe would be:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number: %%J
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name: %%J
) >"%ComputerName%.txt"
setlocal EnableDelayedExpansion
echo Domain\User Name: !USERDOMAIN!\!USERNAME!>>"%ComputerName%.txt"
endlocal
endlocal
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 /?
endlocal /?
findstr /?
for /?
if /?
setlocal /?
systeminfo /?
wmic /?
wmic bios /?
wmic bios get /?
wmic cpu /?
wmic cpu get /?
can you try this:
create a sysi.vbs file with the following code and run this way:
cscript //nologo sysi.vbs
adjust as you needs.
sysi.vbs:
'---------------------------------------------
Set dtmConvertedDate = CreateObject("WbemScripting.SWbemDateTime")
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery ("Select * from Win32_OperatingSystem")
' Create a new WshNetwork object to access network properties.
Wscript.Echo "*** from WScript.Network ***************"
Set WshNetwork = WScript.CreateObject("WScript.Network")
Wscript.Echo "Computer name : " & WshNetwork.ComputerName
Wscript.Echo "Domain : " & WshNetwork.UserDomain
Wscript.Echo "User name : " & WshNetwork.UserName
Wscript.Echo "*** from Win32_OperatingSystem **************"
For Each objOperatingSystem in colOperatingSystems
Wscript.Echo "OS Caption: " & objOperatingSystem.Caption
Wscript.Echo "OS Version: " & objOperatingSystem.Version
dtmConvertedDate.Value = objOperatingSystem.InstallDate
dtmInstallDate = dtmConvertedDate.GetVarDate
Wscript.Echo "OS Install Date: " & dtmInstallDate
Wscript.Echo "OS Serial Number: " & objOperatingSystem.SerialNumber
Next
Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem",,48)
Wscript.Echo "*** from Win32_ComputerSystem **********"
For Each objItem in colItems
Wscript.Echo "Manufacturer: " & objItem.Manufacturer
Wscript.Echo "Model: " & objItem.Model
Wscript.Echo "SystemType: " & objItem.SystemType
Wscript.Echo "TotalPhysicalMemory: " & objItem.TotalPhysicalMemory
Next
Wscript.Echo "*** from Win32_Processor **********"
Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor",,48)
For Each objItem in colItems
Wscript.Echo "Proc Name: " & objItem.Name
Wscript.Echo "CurrentClockSpeed: " & objItem.CurrentClockSpeed
Wscript.Echo "ErrorDescription: " & objItem.ErrorDescription
Wscript.Echo "DeviceID: " & objItem.DeviceID
Wscript.Echo "Manufacturer: " & objItem.Manufacturer
Wscript.Echo "MaxClockSpeed: " & objItem.MaxClockSpeed
Next
Wscript.Echo "*** from Win32_BIOS ******* "
Set colBIOS = objWMIService.ExecQuery("Select * from Win32_BIOS")
Set dtmRelDateRaw = CreateObject("WbemScripting.SWbemDateTime")
For each objBIOS in colBIOS
Wscript.Echo "BIOS Name: " & objBIOS.Name
Wscript.Echo "BIOS Manufacturer: " & objBIOS.Manufacturer
Wscript.Echo "Primary BIOS: " & objBIOS.PrimaryBIOS
dtmRelDateRaw.Value = objBIOS.ReleaseDate
dtmRelDate = dtmRelDateRaw.GetVarDate
Wscript.Echo "Release Date: " & objBIOS.ReleaseDate
Wscript.Echo "Release Date: " & dtmRelDate
Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
Wscript.Echo "Status: " & objBIOS.Status
Wscript.Echo "Version: " & objBIOS.Version
Next
Just an alternative way without using DisableDelayedExpansion:
#echo off && setlocal EnableDelayedExpansion
set "_usrd=Domain\User Name: !USERDOMAIN!\!USERNAME!" && set "_bios=Bios Serial Number: -x" && set "_CPUs=CPU Name: -y"
set "_wmic=%SystemRoot%\System32\wbem\wmic.exe" && pushd "%SystemRoot%\System32" && >"%temp%\%ComputerName%.txt" 2>nul (
systeminfo.exe | findstr "Host.Name OS.Name OS.Version Original.Install.Date System.Manufacturer System.Model System.Type Total.Physical.Memory"
for /f skip^=1^tokens^=* %%i in ('!_wmic! bios get serialnumber^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_bios:-x= %%~i!" <nul & echo\
for /f skip^=1^tokens^=* %%j in ('!_wmic! cpu get name^|findstr "[0-9] [aZ]"')do ^< nul call set /p "'=!_CPUs:-y= %%~j!" <nul & echo\
echo\!_usrd! ) && type "%temp%\%ComputerName%.txt" && popd && endlocal && goto :EOF
Outputs:
Host Name: LAME_SLUG
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.18363 N/A Build 18363
Original Install Date: 3/27/2020, 11:17:06 PM
System Manufacturer: LENOVO
System Model: 80YH
System Type: x64-based PC
BIOS Version: LENOVO 4WCN46WW, 12/30/2019
Total Physical Memory: 16,259 MB
Bios Serial Number: PE03A187
CPU Name: Intel(R) Core(TM) i7-7500U CPU # 2.70GHz
Domain\User Name: LAME_SLUG\ecker

problem with batch file, always empty result

as you can see guys I'm trying to send Email with an attachment.
everything working fine until we come to the message body content.
the body contains the hard drives partitions caption.
as you can see from the command
for /f "skip=1 delims=" %%x in ('wmic logicaldisk get caption') do set mm=%%x
but it always arrive empty.
what could be the problem ?
#ECHO OFF
REM https://stackoverflow.com/questions/28605803/can-not-send-mail-using-smtp-gmail-com-port-587-from-vbs-script/28606754#28606754
Title Sending E-Mail with Gmail Less Secure Applications using Powershell and Batch
SET GmailAccount="user#gmail.com"
SET GmailPassword="password"
SET Attachment="d:\test\myFile.txt"
REM We write our Powershell script
for /f "skip=1 delims=" %%x in ('wmic logicaldisk get caption') do set mm=%%x
CALL :WritePS
REM We execute our Powershell script .PS1 by passing arguments from the command line or a batch file
Powershell -ExecutionPolicy bypass -noprofile -file "%PSScript%" "%GmailAccount%" "%GmailPassword%" "%Attachment%"
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
pause
EXIT
REM -----------------------------------------------------------------------------------------------------
:WritePS
SET PSScript=%temp%\temp_SendeMail.ps1
> "%PSScript%" (
ECHO $Username = $args[0]
ECHO $EmailPassword = $args[1]
ECHO $Attachment= $args[2]
ECHO $EmailTo = "tomytraget#gmail.com"
ECHO $EmailFrom = $Username
ECHO $Subject = "Paths"
ECHO $Body= "%mm%"
ECHO $SMTPServer = "smtp.gmail.com"
ECHO $SMTPMessage = New-Object System.Net.Mail.MailMessage($EmailFrom, $EmailTo, $Subject, $Body^)
ECHO $Attachment = New-Object System.Net.Mail.Attachment($Attachment^)
ECHO $SMTPMessage.Attachments.Add($Attachment^)
ECHO $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587^)
ECHO $SMTPClient.EnableSsl = $true
ECHO $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($Username, $EmailPassword^)
ECHO $SMTPClient.Send($SMTPMessage^)
)
Exit /B
REM -----------------------------------------------------------------------------------------------------
As I mentioned in the comment section, your existing method would only result in a variable value consisting of the last drive letter output from the command. You would need to join those results into a single string value.
To retrieve the information you require, there's no real need to use wmic in your batch-file.
For example:
Set "mm=Mounted drive letters"
For /F "Delims=\" %%G In ('%__AppDir__%mountvol.exe^|%__AppDir__%find.exe ":\"')Do For %%H In (%%G)Do Call Set "mm=%%mm%% %%H"
If you really do want to use wmic, you can retrieve your information without having to worry about the Unicode output, mentioned in the comments and the other answer.
If you're using windows-vista/windows-server-2003, or above, perhaps this will work better for you:
Set "mm=Mounted drive letters"
For /F EOL^=DTokens^=2Delims^=^" %%G In ('%__AppDir__%wbem\WMIC.exe Path Win32_MountPoint')Do Call Set "mm=%%mm%% %%G"
Otherwise, you could still use wmic with Win32_LogicalDisk…
Set "mm=Mounted drive letters"
For /F Delims^=: %%G In ('"%__AppDir__%wbem\WMIC.exe LogicalDisk Get DeviceID 2>NUL|%__AppDir__%find.exe ":""')Do Call Set "mm=%%mm%% %%G:"
However, as already mentioned in the comments, it probably makes more sense just to retrieve the information you need as part of your powershell script:
For PowerShell versions 1.0 and 2.0
$Body = ( Get-WMIObject -Class Win32_LogicalDisk | Select-Object -ExpandProperty DeviceID ) -Join ' '
To do that from your existing batch-file, you need to delete your for /f line, and replace ECHO $Body= "%mm%", escaping the pipe character and the closing parenthesis, e.g.:
ECHO $Body = ( Get-WMIObject -Class Win32_LogicalDisk ^| Select-Object -ExpandProperty DeviceID ^) -Join ' '
Or for PowerShell version 3.0 and above.
$Body = ( Get-CIMInstance -ClassName Win32_LogicalDisk | Select-Object -ExpandProperty DeviceID ) -Join ' '
…and to do that from your existing batch-file, once again, remove your for /f line, and instead of ECHO $Body= "%mm%", use:
ECHO $Body = ( Get-CIMInstance -ClassName Win32_LogicalDisk ^| Select-Object -ExpandProperty DeviceID ^) -Join ' '
It was unclear from your question whether you were specifically looking for local disks, as you mentioned hard drives.
If you're only looking for local disks, you could still use Win32_LogicalDisk, and filter by DriveType, (3 → Local Disk).
Using wmic from your batch-file
Set "mm=Mounted drive letters"
For /F Delims^=: %%G In ('"%__AppDir__%wbem\WMIC.exe LogicalDisk Where (DriveType=3) Get DeviceID 2>NUL|%__AppDir__%find.exe ":""')Do Call Set "mm=%%mm%% %%G:"
Directly in powershell-1.0 and powershell-2.0:
$Body = ( Get-WMIObject -Class Win32_LogicalDisk -Filter "DriveType = '3'" | Select-Object -ExpandProperty DeviceID ) -Join ' '
To do that from your existing batch-file, delete your for /f line, and replace ECHO $Body= "%mm%" with:
ECHO $Body = ( Get-WMIObject -Class Win32_LogicalDisk -Filter "DriveType = '3'" ^| Select-Object -ExpandProperty DeviceID ^) -Join ' '
Or directly in powershell-3.0 and above.
$Body = ( Get-CIMInstance -ClassName Win32_LogicalDisk -Filter "DriveType = '3'" | Select-Object -ExpandProperty DeviceID ) -Join ' '
…and once again from your batch-file, remove your for /f line, and replace ECHO $Body= "%mm%" with:
ECHO $Body = ( Get-CIMInstance -ClassName Win32_LogicalDisk -Filter "DriveType = '3'" ^| Select-Object -ExpandProperty DeviceID ^) -Join ' '
The command wmic logicaldisk get caption outputs on my Windows PC:
Caption
C:
D:
E:
F:
R:
This is a Unicode output which is UTF-16 Little Endian encoded with byte order mark (BOM) and not ASCII/ANSI/OEM encoded as expected by Windows command processor cmd.exe containing internal command FOR.
The output data is in binary:
0000h: FF FE 43 00 61 00 70 00 74 00 69 00 6F 00 6E 00 ; ÿþC.a.p.t.i.o.n.
0010h: 20 00 20 00 0D 00 0A 00 43 00 3A 00 20 00 20 00 ; . .....C.:. . .
0020h: 20 00 20 00 20 00 20 00 20 00 0D 00 0A 00 44 00 ; . . . . .....D.
0030h: 3A 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; :. . . . . . . .
0040h: 0D 00 0A 00 45 00 3A 00 20 00 20 00 20 00 20 00 ; ....E.:. . . . .
0050h: 20 00 20 00 20 00 0D 00 0A 00 46 00 3A 00 20 00 ; . . .....F.:. .
0060h: 20 00 20 00 20 00 20 00 20 00 20 00 0D 00 0A 00 ; . . . . . .....
0070h: 52 00 3A 00 20 00 20 00 20 00 20 00 20 00 20 00 ; R.:. . . . . . .
0080h: 20 00 0D 00 0A 00 ; .....
Data representation format: hexadecimal file offset: data bytes with hexadecimal values ; ASCII representation using code page Windows-1252.
The command FOR expects the text to process character encoded with one byte per character and not UTF-16 LE encoded. So it expects the data as:
0000h: 43 61 70 74 69 6F 6E 20 20 0D 0A 43 3A 20 20 20 ; Caption ..C:
0010h: 20 20 20 20 0D 0A 44 3A 20 20 20 20 20 20 20 0D ; ..D: .
0020h: 0A 45 3A 20 20 20 20 20 20 20 0D 0A 46 3A 20 20 ; .E: ..F:
0030h: 20 20 20 20 20 0D 0A 52 3A 20 20 20 20 20 20 20 ; ..R:
0040h: 0D 0A ; ..
The captured text with wrong character encoding is not correct processed by FOR.
It is unclear what should be assigned to environment variable mm from such an output. If the drive letter without colon of last drive should be assigned to mm, I recommend to use following command line:
for /F "tokens=2 delims=:=" %%I in ('%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET Caption /VALUE') do set "mm=%%I"
The additional option /VALUE changes the output to:
Caption=C:
Caption=D:
Caption=E:
Caption=F:
Caption=R:
The binary data for this output is:
0000h: FF FE 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ÿþ........C.a.p.
0010h: 74 00 69 00 6F 00 6E 00 3D 00 43 00 3A 00 0D 00 ; t.i.o.n.=.C.:...
0020h: 0A 00 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ..........C.a.p.
0030h: 74 00 69 00 6F 00 6E 00 3D 00 44 00 3A 00 0D 00 ; t.i.o.n.=.D.:...
0040h: 0A 00 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ..........C.a.p.
0050h: 74 00 69 00 6F 00 6E 00 3D 00 45 00 3A 00 0D 00 ; t.i.o.n.=.E.:...
0060h: 0A 00 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ..........C.a.p.
0070h: 74 00 69 00 6F 00 6E 00 3D 00 46 00 3A 00 0D 00 ; t.i.o.n.=.F.:...
0080h: 0A 00 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ..........C.a.p.
0090h: 74 00 69 00 6F 00 6E 00 3D 00 52 00 3A 00 0D 00 ; t.i.o.n.=.R.:...
00a0h: 0A 00 0D 00 0A 00 0D 00 0A 00 ; ..........
FOR splits up each non-empty line into substrings using equal sign and colon as delimiters because of option delims=:=. Therefore the last data line is split up into the substrings Caption and R.
The option tokens=2 informs command FOR that the second substring should be assigned to the specified loop variable I which is for all lines with data the drive letter. The command SET is executed only if the line has at least two substrings after splitting the line up and so there is something assigned to the loop variable I.
This solution works even on FOR interpreting the last two empty lines of Unicode output wrong as 0D 0D 0A (carriage return, carriage return, line-feed). The single carriage return is in this case the first and only substring. There is no second substring. So the wrong interpreted empty lines do not result with tokens=2 in running command SET with assigning nothing to it as the carriage return assigned to loop variable I is ignored by command SET which would result in undefinition of the environment variable mm.
This command line assigns the volume name (drive label) up to first space of the last drive with a volume name to environment variable mm (awful variable name).
for /F eol^= %%I in ('%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET VolumeName ^| %SystemRoot%\System32\findstr.exe /R /V /C:"^ *$" /C:"^VolumeName *$"') do set "mm=%%I"
Note: NTFS drives can have a space in volume name. So the string assigned to environment variable mm is not correct on last drive having a space in its volume name.
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 /?
findstr /?
for /?
set /?
wmic /?
wmic logicaldisk /?
wmic logicaldisk get /?
See also the Microsoft documentation for Win32_LogicalDisk class.

Display text from .txt file generated by reg export

I’m writing a script which should read the content of a file generated by reg export command to know Outlook data file path. Obviously I wanto to format the text to make a file without useless information like the first line “Windows Registry Editor Version 5.00” or the word “=dword:” in the generated file.
In for cycle I use echo to check if it’s working. Actually I have to change part of a line before recreate a .txt file with Outlook data file path.
My script works with any .txt file, but when it tries to read the file generated by reg export it shows nothing. This is the syntax of export command:
reg export HKCU\Software\Microsoft\Office\15.0\Outlook\Search export.txt
Here it is the script code:
#echo off
cls
FOR /F "usebackq tokens=* delims=" %%G IN (export.txt) DO #echo %%G
pause
Thanks for your help.
Scorpion77
A file created using reg export is unicode (UTF-16 BOM), see the (truncated) hexdump.exe output:
reg export HKCU\Environment export.txt
hexdump -C export.txt
000000 ff fe 57 00 69 00 6e 00 64 00 6f 00 77 00 73 00 ..W.i.n.d.o.w.s.
000010 20 00 52 00 65 00 67 00 69 00 73 00 74 00 72 00 .R.e.g.i.s.t.r.
000020 79 00 20 00 45 00 64 00 69 00 74 00 6f 00 72 00 y. .E.d.i.t.o.r.
000030 20 00 56 00 65 00 72 00 73 00 69 00 6f 00 6e 00 .V.e.r.s.i.o.n.
000040 20 00 35 00 2e 00 30 00 30 00 0d 00 0a 00 0d 00 .5...0.0.......
…
Files in unicode format cannot be read by the FOR command which expects ASCII. To convert the file format use the TYPE command as follows:
FOR /F "usebackq tokens=* delims=" %%G IN (`type export.txt`) DO #echo(%%G

h264 inside AVI, MP4 and "Raw" h264 streams. Different format of NAL units (or ffmpeg bug)

TL;DR: I want to read raw h264 streams from AVI/MP4 files, even broken/incomplete.
Almost every document about h264 tells me that it consists of NAL packets. Okay. Almost everywhere told to me that the packet should start with a signature like 00 00 01 or 00 00 00 01. For example, https://stackoverflow.com/a/18638298/8167678, https://stackoverflow.com/a/17625537/8167678
The format of H.264 is that it’s made up of NAL Units, each starting
with a start prefix of three bytes with the values 0x00, 0x00, 0x01
and each unit has a different type depending on the value of the 4th
byte right after these 3 starting bytes. One NAL Unit IS NOT one frame
in the video, each frame is made up of a number of NAL Units.
Okay.
I downloaded random_youtube_video.mp4 and strip out one frame from it:
ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.avi
And got:
Red part - this is part of AVI container, other - actual data.
As you can see, here I have 00 00 24 A9 instead of 00 00 00 01
This AVI file plays perfectly
I do same for mp4 container:
As you can see, here exact same bytes.
This MP4 file plays perfectly
I try to strip out raw data:
ffmpeg -i pic.avi -c copy pic.h264
This file can't play in VLC or even ffmpeg, which produced this file, can't parse it:
I downloaded mp4 stream analyzer and got:
MP4Box tells me:
Cannot find H264 start code
Error importing pic.h264: BitStream Not Compliant
It very hard to learn internals of h264, when nothing works.
So, I have questions:
What actual data inside mp4?
What I must read to decode that data (I mean different annex-es)
How to read stream and get decoded image (even with ffmpeg) from this "broken" raw stream?
UPDATE:
It seems bug in ffmpeg:
When I do double conversion:
ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.mp4
ffmpeg pic.mp4 -c copy pic.h264
But when I convert file directly:
ffmpeg -ss 10 -i random_youtube_video.mp4 -frames 1 -c copy pic.h264
I have NALs signatures and one extra NAL unit. Other bytes are same (selected).
This is bug?
UPDATE
Not, this is not bug, U must use option -bsf h264_mp4toannexb to save stream as "Annex B" format (with prefixes)
"I want to read raw h264 streams from AVI files, even broken/incomplete."
"Almost everywhere told to me that the packet should start with a signature like : 00 00 01 or 00 00 00 01"
"...As you can see, here I have 00 00 24 A9 instead of 00 00 00 01"
Your H264 is in AVCC format which means it uses data sizes (instead of data start codes). It is only Annex-B that will have your mentioned signature as start code.
You seek frames, not by looking for start codes, but instead you just do skipping by frame sizes to reach the final correct offset of a (requested) frame...
AVI processing :
Read size (four) bytes (32-bit integer, Little Endian).
Extract the next following bytes up to size amount.
This is your H.264 frame (in AVCC format), decode the bytes to view image.
To convert into Annex-B, try replacing first 4 bytes of H.264 frame bytes with 00 00 00 01.
Consider your shown AVI bytes (see first picture) :
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 4C 49 53 54 BA 24 00 00 6D 6F 76 69 ....LISTº$..movi
30 30 64 63 AD 24 00 00 00 00 24 A9 65 88 84 27 00dc.$....$©eˆ„'
C7 11 FE B3 C7 83 08 00 08 2A 7B 6E 59 B5 71 E1 Ç.þ³Çƒ...*{nYµqá
E3 9C 0E 73 E7 10 50 00 18 E9 25 F7 AA 7D 9C 30 ãœ.sç.P..é%÷ª}œ0
E6 2F 0F 20 00 3A 64 AA CA 5E 4F CA FF AE 20 04 æ/. .:dªÊ^OÊÿ® .
07 81 40 00 48 00 0A 28 71 21 84 48 06 18 90 0C ..#.H..(q!„H....
31 14 57 9E 7A CD 63 A0 E0 9B 96 69 C5 18 AE F2 1.WžzÍc à›–iÅ.®ò
E6 07 02 29 01 20 10 70 A1 0F 8C BC 73 F0 78 FA æ..). .p¡.Œ¼sðxú
9E 1D E1 C2 BF 8C 62 CE CE AC 14 5A A4 E1 45 44 ž.á¿ŒbÎά.Z¤áED
38 38 85 DB 12 57 3E F6 E0 FB AE 03 04 21 62 8D 88…Û.W>öàû®..!b.
F6 F1 1E 37 1C A2 FF 75 1C F1 02 66 0C 92 07 06 öñ.7.¢ÿu.ñ.f.’..
15 7C 90 15 6F 7D FC BD 13 1E 2B 0C 14 3C 0C 00 .|..o}ü½..+..<..
B0 EA 6F 53 B4 98 D7 80 7A 68 3E 34 69 20 D2 FA °êoS´˜×€zh>4i Òú
F0 91 FC 75 C6 00 01 18 C0 00 3B 9A C5 E2 7D BF ð‘üuÆ...À.;šÅâ}¿
Some explanation :
Ignore leading multiple 00 bytes.
4C 49 53 54 D6 3C 00 00 6D 6F 76 69 including 30 30 64 63 = AVI "List" header.
AD 24 00 00 == decimal 9389 is AVI's own size of H264 item (must read in Little Endian).
Notice that the AVI bytes include...
- a note of item's total size (AD 24 00 00... or reverse for Little Endian : 00 00 24 AD)
- followed by item data (00 00 24 A9 65 88 84 27 ... etc ... C5 E2 7D BF).
This size includes both the 4 bytes of the AVI's"size" entry + expected bytes length of the item's own bytes. Can be written simply as:
AVI_Item_Size = ( 4 + item_H264_Frame.length );
H.264 video frame bytes in AVI :
Next follows the item data, which is the H.264 video frame. By sheer coincidence of formats/bytes layout, it too holds a 4-byte entry for data's size (since your H264 is in AVCC format, if it was Annex-B then you would be seeing start code bytes here instead of size bytes).
Unlike AVI bytes, these H264 size bytes are written in Big Endian format.
00 00 24 A9 = size of bytes for this video frame (instead of start code : 00 00 00 01).
65 88 84 27 C7 11 FE B3 C7 = H.264 keyframe (always begins X5, where the X value is based on other settings).
Remember after four size bytes (or even start codes) if followed by...
byte X5 = keyframe (IDR), example byte 65.
byte X1 = P or B frame, example byte 41.
byte X6 = SEI (Supplemental Enhancement Information).
byte X7 = SPS (Sequence Parameter Set).
byte X8 = PPS (Picture Parameter Set).
bytes 00 00 00 X9 = Access unit delimiter.
You can find the H.264 if you search for exact same bytes within AVI file. See third picture, these are your H.264 bytes (they are cut & pasted into the AVI container).
Sometimes a frame is sliced into different NAL units. So if you extract a key frame and it only shows 1/2 or 1/3 instead of full image, just grab next one or two NAL and re-try the decode.

How do I use a variable within some parameter using Batch?

::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.
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
Explanation why code in question fails and this one works
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.
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

Resources