[Batch] Script to obtain and check the REAL PHYSICAL RAM installed . Hi guys Some days ago I started thinking to realize a little app to Patch the Kernel in x86 Win 7 for PC with more than 4 GB RAM. The only scripting language that I know fairly well and that i thought it could be "simple" for a thing like that is Batch, so i started to search for what I needed, first of all for some check to make, possibly, a "Foolproof" mini-patch. One of them it's the check for "THE REAL" RAM installed on the MoBo, to exit if PC doesn't have at least 4 GB installed... ...well... easy, I thought... Windows is showing it to us (Blue Arrow) just near the RAM that is really available (Green one)... ...hmmmm... easy ? ...well, yes... and no... Yes, if you, after Googling a bit for an already made script, and you wanna use Powershell, C#, or VBscript... No, not at all, if you wanna just use a nice and light .CMD file ... now i know why... While WMIC store as a single value for the O.S. available RAM (With the WRONG name 'TotalPhysicalMemory', BTW...) there's not a single value fo REAL RAM, but only the value of the RAM stored into each single slot of the MoBo. I realized, then, that I had a bad idea to do some math calc in CMD, cause I found that it cannot handle numbers greater than " 2GB - 1 byte " if you wanna use them with further operations... so you cannot add 'SLOT1 + SLOT2' if result is 2GB or more, and if you do 'SLOT1 / 1048576' (for 2, 4 or more GB RAM) cause you think you'll have it in MB, you'll always have 2047 as a result, cause the max used value is 2147483647 (2 GB - 1 Byte).[That's why I used MBT=1048575, so the result it's 2048...] While realizing how much poor my knowledge was, and after dozens of "Try & Fail", in fight with syntax punctuation, I finally had the idea to 'cheat' a bit, and forcedly divide by 10, removing the last char... ( I felt, for a moment, like a Brain that defeated a Math Coprocessor... hehehe...) As i need to obtain those values using WMIC in a FOR loop, i've been able to handle the problem pretty easily when i was only obtaining a single value through WMIC get, like it is into the first 'FOR'... On the contrary, working with multiple inputs (like in the second 'FOR'...) I had to do a little bit different approach, and a longer fight (lost) with the right syntax so that I could use " :~0,-n% " inside the FOR LOOP... One of my "Try & Fail" was pretty absurd for me (even if I was trying it anyway...), cause I really didn't know that I could use, inside a FOR Loop, a 'DO Command & CALL :section' pointing to another section of the script... Well... it worked, after some more adjustment, so here it is ... : Code: @echo off color 1e setlocal enabledelayedexpansion SET /A MBT=1024*1024-1 SET /A MBT1=MBT/10 :phys for /f "tokens=2 delims==" %%A in ('wmic computersystem get TotalPhysicalMemory /format:list') do SET MEMPHY=%%A SET MEMPHY=%MEMPHY:~0,-2% SET /A MEMPHYMB=MEMPHY/MBT1 echo. set m :slot for /f "tokens=2 delims==" %%B in ('wmic memorychip get Capacity /format:list') do ( SET MEMSLO=%%B & CALL :calco ) GOTO :rport :calco SET MEMSLO=%MEMSLO:~0,-3% SET /A MEMSLOMB=MEMSLO/MBT1 SET /A MEMTOTIN=MEMTOTIN+MEMSLOMB echo. set m echo. ----------------------------------- GOTO :eof :rport echo. ----------------------------------- set m echo. echo. Press any key to show your Installed / Available RAM. pause >nul echo. echo. ===================================== echo. O.S. Available RAM is : %MEMPHYMB% MB. echo. ===================================== echo. echo. ===================================== echo. REAL Installed RAM is : %MEMTOTIN% MB. echo. ===================================== echo. endlocal & SET MEMTOT=%MEMTOTIN% & SET MEMPHYS=%MEMPHYMB% IF %MEMTOT% GEQ 3080 ( msg %USERNAME% /W I'll start patching your Kernel, so that you'll be able to use all of your RAM !! ) ELSE ( msg %USERNAME% /W You have less than 4 GB RAM so this Patch is useless for You... Click OK and Exit ! ) set m pause >nul pause The red lines are there just for check, to have a personal output and see if the script was doing what i thought and to have the variable progresses for each step. The green line could instead be a nice trick, using SETLOCAL/ENDLOCAL to release all the variables of a certain section, but, with the rest of the line, saving one or more variables from wiping to reuse them later...(We'll see the effect with last'set') I also colored a couple of part in blue, cause i had to play "out-of-the-rules" that i thought should be right, to have the ' :~0,-n% ' Parameter working... Just like I said, I had to remove the last one char from the variable obtained from 'WMIC get' to simulate a division by 10, so I thought the right syntax shuld have been : ' :~0,-1% ', but it didn't worked, so, after some tries, i put a -2 into the first one... bingo !... hhhmmm... no... the second one wasn't working anyway... WTH ?!? I had to put a -3 in the Capacity shrinking value to have a single char removed from it... I checked so many times that I can't count them, using WMITools all of those value are simple numbers, so no strange char at the end, and creating the output of the 'do SET' into a text file there are no further chars at the end (only the CARRIAGE RETURN), so, even if the CR was the problem, I could understand why I had to use a -2 ... BUT... WHY -3 for the other one ?!? Is there anyone among you that could please enlighten me about it and help me enhance my knowledge ? Even if for lots of you there's nothing new here, and even if it's a kind of script that cannot be used so often ( First of all because doing it in VBScript or Powershell is surely easier...LOL ) , I thought that it could anyway be an interesting thing for 'middle-aged' and 'middle-skilled' scripters (Just like me...), so i decided to post it here at MDL... This part of my script has been a huge fight in few moments for me, cause i really couldn't realize WHY certain rules were not right like i thought and like i remembered them (my last script 'totally home-made' was...maybe...20-25 years ago...), but i surely had fun in doing it, and now that this one is working, i'm sure i'll finish the whole script pretty quick. CU All Guys Clay EDIT : Here it is the updated script after Compo's lessons... Code: @echo off color 1e SETLOCAL ENABLEEXTENSIONS SET /A MBT=1024*1024-1 SET /A MBT1=MBT/10 :phys for /f "tokens=2 delims==" %%A in ('wmic computersystem get TotalPhysicalMemory /VALUE') DO CALL :phystot %%A GOTO :slot :phystot SET MEMPHY=%1 SET/A MEMPHYMB=%MEMPHY:~0,-1%/MBT1 GOTO :eof :slot for /f "tokens=2 delims==" %%A in ('wmic memorychip get Capacity /VALUE') DO CALL :slotot %%A GOTO :rport :slotot SET MEMSLO=%1 SET/A MEMSLOMB=%MEMSLO:~0,-1%/MBT1 SET/A MEMTOTIN=MEMTOTIN+MEMSLOMB GOTO :eof :rport echo. echo. ...Here to you the amount of your Installed / Available RAM. ping -n 2 127.0.0.1 >NUL echo. echo. ===================================== echo. O.S. Available RAM is : %MEMPHYMB% MB. echo. ===================================== echo. echo. ===================================== echo. REAL Installed RAM is : %MEMTOTIN% MB. echo. ===================================== echo. ping -n 4 127.0.0.1 >NUL rem endlocal & SET MEMTOT=%MEMTOTIN% & SET MEMPHYS=%MEMPHYMB% IF %MEMTOTIN% GTR 3072 ( GOTO :plus4g ) ELSE ( GOTO :noptch ) :plus4g SET NFO1=- Test Message - You surely have more SET NFO1=%NFO1% than 3 GB RAM !! (will close in 5 seconds) GOTO :quest :noptch SET NFO1=- Test Message - You surely have less SET NFO1=%NFO1% than 4 GB RAM !! (will close in 5 seconds) GOTO :quest :quest MSG %USERNAME% /TIME:5 /W %NFO1% ping -n 2 127.0.0.1 >NUL
That seems like a lot of work to get the Total of RAM, how does this work for you? Code: @ECHO OFF SETLOCAL ENABLEEXTENSIONS FOR /F "TOKENS=2 DELIMS==" %%A IN ( 'WMIC MemPhysical GET MaxCapacity /VALUE^|FINDSTR ..*') DO CALL :INTOGIG %%A ECHO=TOTAL RAM IS %ALLRAM% GB >NUL PING -n 6 127.0.0.1 GOTO :EOF :INTOGIG SET/A ALLRAM=%1/1048576 Bear in mind when using SET with /A that only integers are output
Yep... lots of work... and you know why ?... cause EVERYTIME in WMI there's the word "MemPhysical" (or similar, with 'Physical' word in it) it's NEVER the REAL mean of Physical... LOL I think that the MCI value you used is the MAX SUPPORTED RAM that you can install... on MY PC i'm just Full... Max 8 GB ... installed 8 GB, so it looks like i was receiving the right answer... Then i checked the script in a VM with 2,25 GB and the script it's giving me 256 GB... MaxCapacity is already giving a value in KB , so there's no need to get mad with it.. the problem is when the value is in Byte... BTW... yep, i already knew that SET/A will give me only integer, what i didn't know was that it was limited to 2GB - 1 byte, cause i thought it was '4GB - 1 byte'... Anyway, that value is useless, and it's a pity, cause it's stored in KB, that was easier to manage in calculation... I also tried to use tha value that i found and i tried to modify your script for it, but i'm always receiving the same error that I well know when it's finding 2GB or more RAM in a single SLOT... (but maybe you already know that error). Could you please (just to be sure) tell me if I did something wrong while adating your script to the different query ? Code: @ECHO OFF SETLOCAL ENABLEEXTENSIONS FOR /F "TOKENS=2 DELIMS==" %%A IN ( 'WMIC memorychip GET Capacity /VALUE^|FINDSTR ..*') DO CALL :INTOMEG %%A ECHO=TOTAL RAM IS %TOTRAM% MB >NUL PING -n 6 127.0.0.1 GOTO :EOF :INTOMEG SET/A ALLRAM=%1/1024 SET/A TOTRAM=TOTRAM+ALLRAM On my PC i receive 0 as a result... 4x2GB = 4 errors On the VM with 2304 MB RAM i receive 256 MB as a result... error on the first 2 GB "slot". Anyway, thanks a lot for your script... I'm pretty sure that if I knew you before, I could have had less headache with this script... (...but I didn't enjoy so much in finding a solution by myself... ) CU Clay
I'm not so sure that you are correct, My Motherboard has 4 DIMM slots each supporting 4GB totalling 16GB maximum. I have 2 DIMMS empty and 1 stick of 2GB capacity in each of the other two. My MaxCapacity is returning 4194304 which is correct. Yes the fact is that you cannot use a number of that size with SET/A. You best option if you wished to still use the same method is to use a vbscript. If you still prefer to run a batch file you could probably create and run the vbs from it and output the result to your batch file in the same way as you do now. Example.cmd: Code: @ECHO OFF SETLOCAL ENABLEEXTENSIONS (SET TMP_=%TEMP%\_$.VBS) >"%TMP_%" FINDSTR/E 'VBS "%~f0" FOR /F %%A IN ('CSCRIPT //NOLOGO "%TMP_%"') DO (SET RAMTOT=%%A) DEL "%TMP_%" IF %RAMTOT% GTR 3072 (GOTO PATCHIT) ECHO=You do not have more than 3 GB RAM so this Patch is useless for you...^ Press any key to Exit. PAUSE>NUL GOTO :EOF :PATCHIT (SET NFO=I'll start patching your Kernel,) (SET NFO=%NFO% so that you'll be able to use all of your RAM !!) MSG %USERNAME% /W %NFO% PAUSE GOTO :EOF REM =========================================================================== Set obj = GetObject("winmgmts:").InstancesOf("Win32_PhysicalMemory") 'VBS i = 1 'VBS For Each obj2 In obj 'VBS memTmp1 = obj2.capacity / 1048576 'VBS TotalRam = TotalRam + memTmp1 'VBS i = i +1 'VBS Next 'VBS WScript.echo TotalRam 'VBS You can obviously edit the text etc. as you wish. Please make sure that you do not remove the blank line at the bottom of the script
Yep... I'm sure you're right... Looking better at them with WMITools Object Browser I saw that memorychip is a sub-class of MemPhysical, so the value that you told me is surely right. When I saw that value in my VM, I did the error to not "double-check" in WMITool both VM and my PC and (I really don't know why...) as into the VMPlayer VM that value is 256 GB and do not change if you change the Virtual RAM assigned to the VM, i assumed that it was something like a MaxSupportedInstalledRAM. I also re-checked my MoBo website and i saw that a 1 year old BIOS has updated my MoBo and i could install 16 GB RAM too and that's why my manual was still reporting 8 GB as the Max... So, even checking my real PC, i would have thought that the obtained value wasn't my REAL Installed RAM... And i surely would never try to remove some RAM to check... LOL Thanks for your advice, but as i already said in my OP, i already found a ready vbscript for it... maybe it's been just a point of principle, but i told to me that i should be able to do it only with Batch.. BTW... still talking about 'SET'... Are you maybe able to understand and explain to me why this ABSURD behaviour for the ' :~0,n% ' Parameter ?!? Thx again for your help Clay EDIT : I was already writing my post when you added the script example... LOL My limited skill is allowing me to understand it, but i surely would never been able to write it by myself... The use of 'FINDSTR/E' in that way is amazing . Is there any real difference versus the 'classic' way that i use (if needed...) ? : Code: SET TMP_="%~dp0MY.VBS" echo Set obj = GetObject("winmgmts:").InstancesOf("Win32_PhysicalMemory")>%TMP_% echo For Each obj2 In obj>>%TMP_% ...and so on... I'm still pretty sure that i'll go for a cmd script with no vbs (VBscripting is one of the first thing that i disable, so i'd like to have it working even in a PC that has VBS disable too...) , but surely your VBS is welcome... The VBScript is (more or less...) what i already found... yours is not using ' & strComputer & "\root\cimv2" ' but i think that they are the default values used if nothing is specified, so there shouldn't be the need for them... ...juust a question (sorry to bother you with another one...) ... what's the use of that counter ( i = 1 ) ?!? For...Next is not enough to realize that Loop ? Am I wrong ? CU Clay
The reason for your blue colored problems is that the output from WMIC has a nasty hidden character at the end of it. Try this one liner directly in a console window to see what I mean: Code: FOR /F "TOKENS=2 DELIMS==" %A IN ('WMIC memorychip GET Capacity /VALUE^|FINDSTR ..*') DO @ECHO [%A] The hidden character causes all sorts of problems which is why in my example I remove it as if by magic by sending it as a parameter with the call function. The biggest problem with writing your vbs line by line with echo is that there are often occasions where characters need echoing which are problems to cmd; (they would need escaping). Finally yes, I was a little lazy after playing with some stuff in the vbscript and could have left out both of the count related lines, i=
LOL... WTH of output is that ?? Code: ]2147483648 ]2147483648 ]2147483648 ]2147483648 So, after all your teaching I think that my code will be changed on something like that : (this is just the code i wrote down to see a good output using your 'DO CALL' trick... thx again, dude...) Code: @echo off FOR /F "TOKENS=2 DELIMS==" %%A IN ('WMIC memorychip GET Capacity /VALUE') DO CALL :INTRO %%A echo. FOR /F "TOKENS=2 DELIMS==" %%A IN ('wmic computersystem get TotalPhysicalMemory /VALUE') DO CALL :INTRO2 %%A echo. pause :INTRO echo. ECHO [%1] SET SLO=%1 SET/A SLO=%SLO:~0,-1%/104857 echo -%SLO%- .MB. SET/A SLO1=SLO1+SLO GOTO :eof :INTRO2 echo. ECHO [%1] SET SLO2=%1 SET/A SLO2=%SLO2:~0,-1%/104857 echo. echo -%SLO2%- .MB. Available. echo. echo -%SLO1%- .MB. Installed. (...and the ':~0,-1%' is working now like it should be... DAMN M$... they cannot even handle an output from their own stuff... ) Let's see on the next teaching lesson... CU Clay
Just a quick update on the example code you posted in your last message. There was an error in it, you needed a GOTO :EOF before your subroutines began, (otherwise the script would continue and run the subroutines again as part of the linear read of the file). The other thing I''ll mention, (personal preference only), is that you leave the subroutines when you no longer need to be in them, once the values have been created you can echo the information within the main body of the script. Code: @ECHO OFF SETLOCAL FOR /F "TOKENS=2 DELIMS==" %%A IN ( 'WMIC MemoryChip GET Capacity /VALUE') DO CALL :BANKS %%A ECHO= ECHO=-%SLO1%- .MB. Installed FOR /F "TOKENS=2 DELIMS==" %%A IN ( 'WMIC ComputerSystem GET TotalPhysicalMemory /VALUE') DO ( CALL :TOTAL %%A ) ECHO= ECHO=-%SLO2%- .MB. Available. ECHO= PAUSE GOTO :EOF :BANKS SET SLO=%1 SET/A SLO=%SLO:~,-1%/104857 SET/A SLO1+=SLO GOTO :EOF :TOTAL SET SLO2=%1 SET/A SLO2=%SLO2:~,-1%/104857
Yep, I agree with you... it was just too fast in modern PC to let us see that my :INTRO subroutine was reapeted after the pause before exit... But it was also a fast example that I made to be sure that using that trick the '~0,-1' was working and i didn't "double-check" if the Loop was already completed or not... hehehe... i'm lazy too (... and you can easily see, in the updatad script that i added in the OP, that i didn't made the same error... ) About your "personal preference", I think that it's surely the best thing to do when working with 'CALL :subroutine' even if it's usually hard, for me, to mantain the whole 'body of the script' intact, while moving all subroutine at the end of the script (personal preference...too), but, apart from that, I totally agree that a subroutine has always to start with a :caption and end with a GOTO, to be sure that you're not going to fall into an endless Loop... Just to make a corrected example of what i mean, based on my 'wrong-but-too-fast-to-be-visible' previous script... : Code: @echo off FOR /F "TOKENS=2 DELIMS==" %%A IN ('WMIC memorychip GET Capacity /VALUE') DO CALL :INTRO %%A echo. FOR /F "TOKENS=2 DELIMS==" %%A IN ('wmic computersystem get TotalPhysicalMemory /VALUE') DO CALL :INTRO2 %%A echo. GOTO :show :INTRO echo. SET SLO=%1 SET/A SLO=%SLO:~0,-1%/104857 SET/A SLO1=SLO1+SLO GOTO :eof :INTRO2 echo. SET SLO2=%1 SET/A SLO2=%SLO2:~0,-1%/104857 GOTO :eof :show echo. echo -%SLO2%- .MB. Available. echo. echo -%SLO1%- .MB. Installed. echo. pause I often use this kind of 'construction' for subroutine that I have to use for a single Loop, maybe, so that it's easier to check them in debug moments, writing them near the CALL for them, without having to scroll down the page if you're doing a large script... On the contrary, when I use subroutines that could be CALLed for more times during the execution, i'm used to put all of them at the End of the script, cause in that case too, it's easier to go to check-control one of them starting from any part of the script. Again looking at my updated script in the OP, you can see that i also use quite often some 'useless' caption, that i anyway think that could be a better 'self-explaining' way to see how the script is going on without using those boring REM lines, if, just like me, you're used to continue to work to a script maybe some months after your last edit of it... ...as we both already said... they're a lot of 'personal preference' and most of them won't fit for other ppl... I hoe that what ppl is writing here, in this kind of sections of MDL forum, could be useful for more ppl than just me. CU Later, guys Clay