;;FUNCTION Memory()
;;
;;AUTHOR Glenn Barnas
;;
;;ACTION Returns the amount of Available Physical RAM in a local or remote system
;;
;;SYNTAX Memory([system])
;;
;;VERSION 4.0
;;
;;DATE v1.0 - 2004/02/04
;;
;;DATE REVISED v2.0 - 2005/02/25 - updated to allow larger memory sizes (x86)
;; v3.0 - 2007/10/05 - rewrite to support x64 systems, tighten code
;; v4.0 - 2013/11/02 - rewrite to detect large memory blocks on post-Vista platforms
;;
;;PARAMETERS System - OPTIONAL - name of system to query. Default is local system
;;
;;REMARKS Returns Physical RAM size available to the O/S using registry memory allocation map
;; Returns @ERROR on registry read failure, or 13 / "Data is Invalid" if reg is empty
;; DOES NOT return physical hardware ram value! Some systems allocate RAM to BIOS cache
;; or video adapters and this memory is not reported. This can be adjusted for using
;; the second example below.
;;
;;RETURNS Integer - Available Physical RAM (in Megabytes)
;;
;;DEPENDENCIES None
;;
;;TESTED WITH WinXP, Vista, Win7, Win8
;; Windows Server 2000, 2003, 2008, 2012
;; Tested with up to 16G of RAM
;;
;;EXAMPLES $RAM = Memory('ThatPC') ; Get the available RAM from a remote computer
;;
;; ; Adjust for BIOS/Video ram to estimate total physical RAM by using the smallest
;; ; deployed DIMM module as an increment. Use "1024" for full GB increments.
;; ; If the GB flag is used, this method must be adjusted to define MSize in GB values
;; ; (e.g. 0.5 instead of 512).
;; $MSize = 512 ; Size of smallest RAM module (DIMM)
;;
;; $Mem = Memory() ; get reported memory
;; $Ma = $Mem / $MSize ; determine number of modules installed
;;
;; ; If a fractional module is detected, add another full module
;; ; this accounts for a fractional module used for BIOS cache or video RAM
;; If $Mem Mod $MSize $Ma = $Ma + 1 EndIf
;;
;; ; $Mem now holds a value based more closely on installer rather than available RAM
;; $Mem = $Ma * $MSize ; Memory is #_modules * Mod_Size
;;
;;
;
Function Memory(Optional $_System, Optional $_fGB)
Dim $_MemMap ; Physical Memory Map
Dim $_Start, $_End, $_Step ; for/next start & step increment
Dim $_Sum ; running sum of memory from map
Dim $_Idx ; temporary index var
Dim $_iMem ; Memory region size index
Dim $_Error ; Error placeholder
; Insure $_System has "\\System\" format if it is specified
If $_System <> ''
$_System = '\\' + Join(Split($_System, '\'), '', 3) + '\'
EndIf
; Get the memory value from the registry
$_Idx = $_System + 'HKLM\hardware\resourcemap\system resources\physical memory'
$_MemMap = ReadValue($_Idx, '.Translated')
; Check for invalid read and Return
If Len($_MemMap) = 0 Or @ERROR
$Memory = 0 ; return 0 Mbytes
$_Error = IIf(@ERROR, @ERROR, 13) ; Return "Data is Invalid" if no error but data is blank
Exit $_Error
EndIf
; determine system's O/S type based on architecture
$_Idx = $_System + 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
If ReadValue($_Idx, 'PROCESSOR_ARCHITECTURE') = 'AMD64'
$_Step = 40 ; Define the step size based on the O/S Architecture
$_Start = 33 ; Offset where memory descriptor blocks start
$_Sum = 0.0 ; no unreported base memory to account for
$_iMem = 10 ; Memory size index
Else
$_Step = 32 ; Define the step size based on the O/S Architecture
$_Start = 41 ; Offset where memory descriptor blocks start
$_Sum = 737280.0 ; account for base memory not identified in memory map - x86 only
$_iMem = 2 ; Memory size index
EndIf
$_End = Len($_MemMap) - 8
For $_Idx = $_Start to $_End Step $_Step
$_Block = SubStr($_MemMap, $_Idx, $_Step)
If SubStr($_Block, $_iMem, 1) > 3
$_Sum = $_Sum + CDbl(Val('&' + SubStr($_Block, $_Step - 1, 2))) * 4294967296.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 3, 2))) * 16777216.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 5, 2))) * 65536.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 7, 2))) * 256.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 9, 2)))
Else
$_Sum = $_Sum + CDbl(Val('&' + SubStr($_Block, $_Step - 1, 2))) * 16777216.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 3, 2))) * 65536.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 5, 2))) * 256.0
+ CDbl(Val('&' + SubStr($_Block, $_Step - 7, 2)))
EndIf
Next
; Sum is in Bytes - return the total as megabytes
$Memory = CInt($_Sum / 1048576)
Exit 0
EndFunction