Search code examples
batch-filehttp-redirectwmic

Generating an overview of RAM in a list of computers by using wmic and modifying output file


I have become responsible for a couple of dozen PC's, that I need to check for internal hard- and software. Our CMDB system isn't up to date, therefore I need to find out what we actually have. I have spent several hours trying to figure a way to make a batch script that is easy to use and generates easy to read output. I wanted to get started with the physical memory/RAM.

I found the wmic command, and was able to specify it to get only the information I need and use a text file and FOR loop to cycle through a list of SNs and output the RAM of each computer into a text file:

IF EXIST output.txt DEL /Q output.txt >NUL
FOR /F "tokens=*" %%i IN (input.txt) DO (
wmic /node:%%i memorychip get capacity >> output.txt
)
EXIT /B

This only works when the PC's are online.

So far, so good.

To also see the serial number of the computer, to - for example - use Excel to warp the text file into a table, I added an ECHO line:

IF EXIST output.txt DEL /Q output.txt >NUL
FOR /F "tokens=*" %%i IN (input.txt) DO (
@Echo Serialnumber %%i >> output.txt
wmic /node:%%i memorychip get capacity >> output.txt
)
EXIT /B

But all the wmic output lines got weird spaces between each character and cramped into one line, whereas before they were nicely split into as many lines as there were different "words" Why does this happen?

If I manually remove all " " characters from the output file, it transforms back into what i would expect: Everything back to neat lines

I hoped I could directly remove the "space" characters from the wmic function's output, but I couldn't. For example, I found this trick to get the output of wmic into variables, which I though I could then manipulate:

SETLOCAL ENABLEDELAYEDEXPANSION
@echo off
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`wmic /node:2CMFFY1 memorychip get capacity`) DO (
SET var!count!=%%F
SET /a count=!count!+1
)
ECHO %var1%
ECHO %var2%
ECHO %var3%
ECHO %var4%
ECHO %var5%
ENDLOCAL

This piece of code neatly creates separate lines if I add a serial number manually

But I can't get it to be filled with the serial numbers from the input.txt file. If I try this code, it still prints the serial number lines, but apparently skips the second FOR loop:

SETLOCAL ENABLEDELAYEDEXPANSION
IF EXIST output.txt DEL /Q output.txt >NUL
FOR /F "tokens=*" %%i IN (input.txt) DO (
@Echo Serialnumber %%i >> output.txt
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`wmic /node:%%i memorychip get capacity`) DO (
  SET var!count!=%%F
  SET /a count=!count!+1
)
ECHO %var1% 
ECHO %var2%
ECHO %var3%
ECHO %var4%
ECHO %var5%
)
ENDLOCAL
EXIT /B

If I look at what is actually happening, it seems that in some cases, the second FOR does get the correct serial number passed into the wmic command, but it still doesn't work, I only get the lines of the first ECHO.

I found another forum's thread about WMIC posting unicode outcomes, which can't be interpreted correctly, and some attempts to solve this. I tried integrating this into my code, but it doesn't work 100%, it now adds extra "Echo is ON" lines to the results.

IF EXIST output.txt DEL /Q output.txt >NUL
FOR /F "tokens=*" %%i IN (input.txt) DO (
ECHO Serialnumber %%i>>output.txt
FOR /F "tokens=*" %%j IN ('wmic /node:%%i memorychip get capacity') DO @echo %%j>>output.txt 2>&1
)

If I could get to write the WMIC outcome to separate variables, there might be a way to integrate this line of code to remove the spaces:

set str=%str: =%

A final step would be, to reduce the RAM space in bytes to a more readable GB number. I have seen some things that might achieve that, I only need to get the strings into variables to manipulate them.

But as I said, I'm an utter noob, with only a decade-old knowledge of some visual basic and C++ and some HTML/JAVA/CSS programming. There's probably a simple solution to this problem...

Any help would be immensely appreciated! Also, if anyone can recommend a website or a book that takes you through cmd/batch scripting step by step with general explanation of syntax structure, information how variables work, etc, that would also be immensely helpful :)


Solution

  • This script collects multiple values from different WMIC calls, where each data source is handled in a subroutine. To illustrate, total memory size and BIOS serial number are collected. The nodelist file contains hostnames which in OP's case happen to be identical to the host's serial number (if I have understood this right).
    WMIC output often has a trailing control character. To get rid of it, a temporary file is used:

    @echo off
    REM 8:12:49 PM Saturday 18/11/2017
    REM get serial number and memory size for all hosts in a hostname list file
    REM output is in CSV format
    
    REM 1:43:58 PM Tuesday 21/11/2017
    REM added: check if host is online, using ping
    
    setlocal EnableDelayedExpansion
    
    set nodelist=nodelist.txt
    REM needs write permissions for next 2 paths
    set out=output.txt
    set temppath=%TEMP%
    
    echo node,serial,memsize> %out%
    for /F "delims=" %%N in (%nodelist%) do (
       set "node=%%N"
       set "node=!node: =!"
       set "memsize=" & set "getserial="
    
       CALL :checkonline !node!
       if defined OK CALL :getmem !node!
       if defined OK CALL :getserial !node!
       REM ... and so on
    ) & echo !node!,!serial!,!memsize!>> %out%
    type %out%
    goto :EOF
    
    
    :checkonline
       set "OK="
       if "%~1"=="" goto :EOF
       ping -4 -w 200 -n 2 %~1 | find "TTL" 2>&1 >nul && set "OK=1"
    goto :EOF
    
    
    :getmem
       set "OK="
       set "out1=%temppath%\%RANDOM%.tmp"
       WMIC /Node:%~1 /output:%out1% ComputerSystem get TotalPhysicalMemory /value 2>&1 >nul|| goto :EOF
       for /F "tokens=1,2 delims==" %%A in ('find "=" ^< %out1%') do @set memsize=%%B
    
       rem memsize is in bytes now
       rem calc size in MB, need to truncate by 1000, cannot use SET /A
       set "memsize=!memsize:~0,-3!"
       rem div by 1048 (1024 * 1,024) in 2 steps
       set /A memsize *= 42
       set /A memsize /= 44016
       rem assume Windows itself is using 132 MB
       set /A memsize += 132 
    
       set "OK=1"
       del %out1%
     goto :EOF
    
    :getserial
       set "OK="
       set "out1=%temppath%\%RANDOM%.tmp"
       WMIC /Node:%1 /output:%out1% Bios get SerialNumber /value 2>&1 >nul || goto :EOF
       for /F "tokens=1,2 delims==" %%A in ('find "=" ^< %out1%') do @set serial=%%B
    
       set "OK=1"
       del %out1%
     goto :EOF
    

    edit:
    I've added a quick check if the node is online, using a ping. The host needs to have an IPv4 IP address (not IPv6) to keep it simple. Additionally, each WMIC call returns a success flag (OK). If one call fails no other is attempted on this host. Lastly, now the node name can contain a trailing space without disturbing the process.