Search code examples
windowsbatch-filecmdwmic

How to check if WMIC outputs an empty string or the requested original product key of Windows?


I try to use a wmic command to check for the Windows product key. I put a check to see if it is returning the Windows product key or an empty line. But the conditions IF "%%Z" == "" as well as IF [%%Z] EQU [] result always in execution of Echo Lose, i.e. key is not an empty string.

The following example is a simpler version to show the first part.

@ECHO OFF

set cmd=wmic path softwarelicensingservice get OA3xOriginalProductKey
for /f "tokens=1 skip=1" %%Z in ('%cmd% ^| findstr /r /v "^$"') do (set RESULT=%%Z)

IF "%%Z" == "" (Echo Key %RESULT%) Else (Echo Lose)
PAUSE

Solution

  • The string value assigned to a loop variable like Z cannot be referenced outside of the loop. The condition IF "%%Z" == "" compares always the fixed string "%Z" with the fixed string "" which are of course never equal. The condition IF [%%Z] EQU [] results first in the attempt to convert the fixed string [%Z] into a 32-bit signed integer value which fails already on first character [ and for that reason there is done next a string comparison of [%Z] with [] which are never equal too.

    Some facts to know before using the code below:

    There could be used the following batch code:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    set "RESULT="
    for /F "delims=" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH SoftwareLicensingService GET OA3xOriginalProductKey /VALUE 2^>nul') do for /F "tokens=1* delims==" %%J in ("%%I") do set "RESULT=%%K"
    if not defined RESULT echo Lose& goto EndBatch
    echo Key %RESULT%
    rem Other commands making use of environment variable RESULT.
    :EndBatch
    endlocal
    pause
    

    The usage of FINDSTR to filter out the empty lines is of no real help in case of no value output by WMIC for property OA3xOriginalProductKey because of the Unicode output of WMIC encoded with UTF-16 Little Endian with byte order mark (BOM) is processed wrong by the cmd.exe instance started in background with option /C and the specified command line as additional arguments on redirecting the output to FINDSTR with conversion to a single byte per character encoding.

    The environment variable RESULT is defined in this case with a single carriage return as string assigned to the environment variable.

    The workaround for this quirks of cmd.exe on processing the Unicode output of WMIC is using the option /VALUE to get output the name of property OA3xOriginalProductKey and its value on one line with an equal sign between and two empty lines above and also below the data line.

    All five captured lines are processed by FOR which usually ignores empty lines completely. But there is no empty line to process by FOR because of the bug of cmd.exe interpreting the UTF-16 encoded carriage return + line-feed (0D 00 0A 00) as carriage return + carriage return + line-feed (0D 0D 0A) resulting in the four empty lines are interpreted as line with a single carriage return and the line with OA3xOriginalProductKey= at beginning as line having also an extra carriage return at the end.

    For that reason each entire line with carriage return at end is assigned first to loop variable I.

    One more FOR loop is used to process the string assigned to the loop variable I which results in removing the erroneous carriage return from the string value before processing it.

    So for the four empty lines there is no string to process by the second FOR and so the four empty lines are indeed ignored.

    The second FOR loop splits up the only line with text data into two substrings by using the equal sign as string delimiter. The first substring OA3xOriginalProductKey is assigned to loop variable J and the second substring after the equal sign is the key which is assigned to next but one loop K if there is a key at all as otherwise K is not defined and %%K on command SET executed next is replaced by an empty string.

    The batch file defines with the first two lines the required execution environment completely and makes sure that the environment variable RESULT is by chance not already defined outside of the batch file with the third command line.

    The IF condition after the long command line with the two FOR and the SET commands checks first if the environment variable RESULT is defined now with a real key (and not with just carriage return) to determine which ECHO command to execute next.

    The long command line could be also:

    for /F "delims=" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH SoftwareLicensingService GET KeyManagementServiceMachine /VALUE 2^>nul') do for /F "tokens=2 delims==" %%J in ("%%I") do set "RESULT=%%J"
    

    In this case just the string after the OA3xOriginalProductKey= is assigned to specified loop variable J if there is a key output by WMIC at all. Otherwise there is nothing to assign to J by second FOR and for that reason the command SET is never executed at all resulting in RESULT still not existing in list of environment variables.

    To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.

    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • if /?
    • pause /?
    • rem /?
    • set /?
    • setlocal /?
    • wmic /?
    • wmic path /?
    • wmic path softwarelicensingservice /?
    • wmic path softwarelicensingservice get /?

    Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.