Here is the routine I use for this in my own version of the software update script:
:getfattr set %1= setlocal set "name=%~f2" set "name=%name:\=\\%" for /f "delims=" %%A in ('wmic datafile where "name='%name:'=\'%'" get %1 /format:list') do @^ for /f "delims=" %%B in ("%%A") do endlocal & set "%%B" & goto :eof echo>&2 getfattr failed endlocal goto :eof
It can get any file attribute supported by wmic datafile get . For example, here's how you can get the version of a file for installed Adobe Reader:
call :getfattr version "%ProgramFiles(x86)%\Adobe\Reader 11.0\Reader\AcroRd32.exe" echo "!version!"
After that, the environment variable version will contain the requested version string. If :getfattr does not work, version guaranteed to be canceled.
The trace of the test execution for this example looks like this (slow extension is already enabled, but this is not assumed: getfattr):
>call :getfattr version "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" >set version= >setlocal >set "name=C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" >set "name=C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe" >for /F "delims=" %A in ('wmic datafile where "name='C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe'" get version /format:list') do @for /F "delims=" %B in ("%A") do endlocal & set "%B" & goto :eof >endlocal & set "Version=11.0.18.21" & goto :eof >echo "!version!" "11.0.18.21"
As you can see, this is pretty straightforward and doesn't hurt too much. He, however, tiptoes through the minefield cmd and wmic gotchas.
Firstly, the name of the attribute you want to get is also the name used for the variable you want to get the result in ( version in the above test). Inside the routine, this is the name %1 , so set %1= clears it.
The file name that you transfer needs some pre-processing before it can be safely transferred to wmic , and this requires a shell variable, so setlocal is issued to avoid topping the caller’s variables.
set "name=%~f2" copies the name to the environment variable after deleting all surrounding double quotes and expanding it to the full path name. Double quotes surround the entire set argument to prevent grief caused by ampersands or parentheses in the path names.
wmic queries use SQL-type syntax, where string values are surrounded by single quotes ' , and \ is escape, which suppresses any special value for the next character. Since both of them are legal in Windows paths, all occurrences either need the \ prefix. set "name=%name:\=\\%" hides the built-in backslashes, and the constructor '%name:'=\'%' on the wmic command line avoids the built-in single quotes and adds the required surrounding.
cmd parser does not disable special processing between single quotes, and the name no longer contains any close double quotes, so embedded spaces, brackets, or ampersands can potentially disrupt the operation. To guard against this, the wmic argument of integer name= gets double quotes. There is no need for special processing for double quotes already inside the name, because double quotes are not allowed in Windows file names, so they cannot be.
The for command line containing the wmic command ends with the sequence @^ . ^ serves to append the next line as the payload of the external for command; @ prevents an echo in the execution trace, even if ECHO is enabled.
This echo cancellation occurs mainly because the internal for exists only to get rid of the false CR characters introduced by the cmd error converting wmic output from Unicode to ASCII (the same method used by @dbenham answer), and if it allowed an echo These CRs simply drown out the track with confusing rewriting. As a side benefit, the internal for will not perform its own payload if the line it passed from the external for contains only CR, a version-specific number that wmic insists on emitting. The internal for payload receives an echo if ECHO is enabled, so tracing still captures all the useful events.
This payload consists of three & -separable commands, which for will expand as a single command line before cmd receives the processing of individual commands. In particular, this means that set "%%B" expands to run endlocal , which puts the variable created by this set outside the scope of setlocal / endlocal and makes it available to the caller.
%%B will always expand in the format name = value due to the /format:list switch passed to wmic ; the name will be the same as specified in the verb get , and that is how the name you pass ends up picking the variable you are returning. The entire argument name = value for set quoted if the requested attribute contains special shell characters. It does: getfattr itself is safe, but you can use it! Delayed! expansion, not% premature increase%, wherever you use the variable that it returns to you.
& goto :eof on the same line breaks off from both for chains and returns to: getfattr caller, as soon as the internal one actually does something, just in case you pass in some strange name and wmic get produces more, than one non-empty line of output.
The last three lines are executed only if wmic does not display output at all, what happens when it fails.