Last active
November 21, 2024 02:37
-
-
Save robertsinfosec/07a8bcb1d9e39680f0cb1886631053e9 to your computer and use it in GitHub Desktop.
For a Linux machine, attempts to see how much RAM is installed and what kind, and determine what the maximum number of sticks and amount of RAM the current machine can support. If you want to run this on-the-fly and trust this source, from your Linux machine you can run: `curl -L https://tinyurl.com/ram-upgrade-check/raw | bash`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to determine maximum supported RAM, current RAM configuration, | |
# and specifications for upgrading RAM to maximum capacity. | |
set -euo pipefail | |
# Define color codes | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
BLUE='\033[0;34m' | |
CYAN='\033[0;36m' | |
BOLD='\033[1m' | |
NC='\033[0m' # No Color | |
# Get FQDN of the current machine | |
FQDN=$(hostname -f) | |
# Get BIOS information | |
BIOS_MANUFACTURER=$(sudo dmidecode -s bios-vendor) | |
BIOS_VERSION=$(sudo dmidecode -s bios-version) | |
BIOS_RELEASE_DATE=$(sudo dmidecode -s bios-release-date) | |
SYSTEM_MANUFACTURER=$(sudo dmidecode -s system-manufacturer) | |
SYSTEM_PRODUCT_NAME=$(sudo dmidecode -s system-product-name) | |
SYSTEM_VERSION=$(sudo dmidecode -s system-version) | |
SYSTEM_SERIAL_NUMBER=$(sudo dmidecode -s system-serial-number) | |
SYSTEM_SKU=$(sudo dmidecode -s system-sku-number) | |
# Output system identification information | |
echo -e "${CYAN}FQDN.....................:${NC} $FQDN" | |
echo -e "${CYAN}BIOS Manufacturer........:${NC} $BIOS_MANUFACTURER" | |
echo -e "${CYAN}BIOS Version.............:${NC} $BIOS_VERSION" | |
echo -e "${CYAN}BIOS Release Date........:${NC} $BIOS_RELEASE_DATE" | |
echo -e "${CYAN}System Manufacturer......:${NC} $SYSTEM_MANUFACTURER" | |
echo -e "${CYAN}System Product Name......:${NC} $SYSTEM_PRODUCT_NAME" | |
echo -e "${CYAN}System Version...........:${NC} $SYSTEM_VERSION" | |
echo -e "${CYAN}System Serial Number.....:${NC} $SYSTEM_SERIAL_NUMBER" | |
echo -e "${CYAN}System SKU...............:${NC} $SYSTEM_SKU" | |
echo "" | |
echo -e "${GREEN}Starting RAM analysis...${NC}" | |
echo "" | |
# Function to check if a command exists | |
command_exists() { | |
command -v "$1" >/dev/null 2>&1 | |
} | |
# Ensure required commands are available | |
for cmd in dmidecode lscpu; do | |
if ! command_exists "$cmd"; then | |
echo -e "${RED}Error: Required command '$cmd' is not installed.${NC}" >&2 | |
exit 1 | |
fi | |
done | |
# Get detailed CPU information | |
CPU_MODEL=$(lscpu | grep -m1 "Model name" | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
CPU_VENDOR=$(lscpu | grep -m1 "Vendor ID" | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
CPU_FAMILY=$(lscpu | grep -m1 "CPU family" | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
CPU_MODEL_NUM=$(lscpu | grep -m1 "Model:" | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
# Get chipset information | |
CHIPSET=$(sudo dmidecode -t 2 2>/dev/null | grep -m1 "Product Name:" | awk -F: '{print $2}' | sed 's/^[ \t]*//' || echo "Unknown") | |
# Calculate total installed RAM | |
TOTAL_INSTALLED=$(free -b | grep "Mem:" | awk '{printf "%.0f\n", $2 / (1024*1024*1024)}') | |
echo -e "${CYAN}CPU Model................:${NC} $CPU_MODEL" | |
echo -e "${CYAN}Chipset..................:${NC} $CHIPSET" | |
echo -e "${CYAN}Total Installed RAM......:${NC} ${TOTAL_INSTALLED} GB" | |
# Get BIOS-reported maximum memory capacity | |
MAX_MEMORY=$(sudo dmidecode -t 16 | grep "Maximum Capacity" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
echo -e "${CYAN}BIOS Maximum RAM.........:${NC} $MAX_MEMORY" | |
# Convert BIOS max to GB for comparison | |
MAX_MEMORY_GB=$(echo "$MAX_MEMORY" | grep -o '[0-9]\+') | |
# Check if installed RAM exceeds BIOS-reported maximum | |
if [ "$TOTAL_INSTALLED" -gt "$MAX_MEMORY_GB" ]; then | |
echo -e "${YELLOW}Warning: Installed RAM (${TOTAL_INSTALLED} GB) exceeds BIOS-reported maximum (${MAX_MEMORY_GB} GB)${NC}" | |
echo -e "${YELLOW}This suggests the actual hardware supports more RAM than reported by BIOS${NC}" | |
fi | |
# Get CPU maximum memory support based on vendor | |
if [[ "$CPU_VENDOR" == *"Intel"* ]]; then | |
echo -e "${CYAN}CPU Memory Support.......:${NC} Check https://ark.intel.com/content/www/us/en/ark/products/ for exact specifications" | |
echo -e "${YELLOW}Intel ${CPU_FAMILY} generation CPUs typically support up to 128GB RAM${NC}" | |
elif [[ "$CPU_VENDOR" == *"AMD"* ]]; then | |
echo -e "${CYAN}CPU Memory Support.......:${NC} Check https://www.amd.com/en/products/ for exact specifications" | |
echo -e "${YELLOW}Modern AMD CPUs typically support 128GB+ RAM${NC}" | |
fi | |
# Initialize arrays for memory information | |
declare -a SLOT_LOCATIONS | |
declare -a SLOT_SIZES | |
declare -a SLOT_TYPES | |
declare -a SLOT_SPEEDS | |
declare -a SLOT_MANUFACTURERS | |
declare -a SLOT_PART_NUMBERS | |
declare -a SLOT_FORM_FACTORS | |
echo -e "\n${GREEN}Collecting memory slot information...${NC}" | |
# Read dmidecode output and process each Memory Device section | |
TOTAL_SLOTS=0 | |
while IFS= read -r line; do | |
if [[ $line =~ "Memory Device" ]]; then | |
# Read the block until an empty line | |
block="" | |
while IFS= read -r detail && [[ -n $detail ]]; do | |
block+="$detail"$'\n' | |
done | |
# Increment total slots | |
TOTAL_SLOTS=$((TOTAL_SLOTS + 1)) | |
# Skip empty slots | |
if [[ $block =~ "Size: No Module Installed" ]]; then | |
SLOT_LOCATIONS+=("Slot $TOTAL_SLOTS") | |
SLOT_SIZES+=("(Empty)") | |
SLOT_TYPES+=("(Empty)") | |
SLOT_SPEEDS+=("(Empty)") | |
SLOT_MANUFACTURERS+=("(Empty)") | |
SLOT_PART_NUMBERS+=("(Empty)") | |
SLOT_FORM_FACTORS+=("(Empty)") | |
continue | |
fi | |
# Extract information | |
SIZE=$(echo "$block" | grep "^[[:space:]]*Size:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
LOCATION=$(echo "$block" | grep "^[[:space:]]*Locator:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
TYPE=$(echo "$block" | grep "^[[:space:]]*Type:" | grep -v "Type Detail" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
SPEED=$(echo "$block" | grep "^[[:space:]]*Speed:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
MANUFACTURER=$(echo "$block" | grep "^[[:space:]]*Manufacturer:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
PART_NUMBER=$(echo "$block" | grep "^[[:space:]]*Part Number:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
FORM_FACTOR=$(echo "$block" | grep "^[[:space:]]*Form Factor:" | head -n1 | awk -F: '{print $2}' | tr -d '[:space:]') | |
# Add to arrays | |
SLOT_LOCATIONS+=("$LOCATION") | |
SLOT_SIZES+=("$SIZE") | |
SLOT_TYPES+=("$TYPE") | |
SLOT_SPEEDS+=("$SPEED") | |
SLOT_MANUFACTURERS+=("$MANUFACTURER") | |
SLOT_PART_NUMBERS+=("$PART_NUMBER") | |
SLOT_FORM_FACTORS+=("$FORM_FACTOR") | |
fi | |
done < <(sudo dmidecode -t 17) | |
# Function to infer the number of pins based on form factor and type | |
infer_pins() { | |
local form_factor=$1 | |
local type=$2 | |
case "$form_factor" in | |
"DIMM") | |
case "$type" in | |
"DDR3") echo "240" ;; | |
"DDR4") echo "288" ;; | |
"DDR5") echo "288" ;; | |
*) echo "Unknown" ;; | |
esac | |
;; | |
"SODIMM") | |
case "$type" in | |
"DDR3") echo "204" ;; | |
"DDR4") echo "260" ;; | |
"DDR5") echo "262" ;; | |
*) echo "Unknown" ;; | |
esac | |
;; | |
*) | |
echo "Unknown" | |
;; | |
esac | |
} | |
# Output current memory configuration | |
echo -e "\n${YELLOW}${BOLD}Current Memory Configuration:${NC}" | |
echo "----------------------------------------" | |
printf "${BOLD}%-10s %-10s %-10s %-15s %-15s %-20s %-10s${NC}\n" "Slot" "Size" "Type" "Speed" "Manufacturer" "Part Number" "Pins" | |
echo "---------------------------------------------------------------------------------------------" | |
for i in "${!SLOT_LOCATIONS[@]}"; do | |
PINS=$(infer_pins "${SLOT_FORM_FACTORS[$i]}" "${SLOT_TYPES[$i]}") | |
printf "%-10s %-10s %-10s %-15s %-15s %-20s %-10s\n" \ | |
"${SLOT_LOCATIONS[$i]}" \ | |
"${SLOT_SIZES[$i]}" \ | |
"${SLOT_TYPES[$i]}" \ | |
"${SLOT_SPEEDS[$i]}" \ | |
"${SLOT_MANUFACTURERS[$i]}" \ | |
"${SLOT_PART_NUMBERS[$i]}" \ | |
"$PINS" | |
done | |
# Get specifications from first populated slot | |
FIRST_SLOT_INFO=$(sudo dmidecode -t 17 | awk '/Memory Device$/,/^$/' | head -n 30) | |
FORM_FACTOR=$(echo "$FIRST_SLOT_INFO" | grep "^[[:space:]]*Form Factor:" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
VOLTAGE=$(echo "$FIRST_SLOT_INFO" | grep "^[[:space:]]*Configured Voltage:" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
if [ -z "$VOLTAGE" ] || [ "$VOLTAGE" == "Unknown" ]; then | |
VOLTAGE="1.2 V (typical for DDR4)" | |
fi | |
ECC_TYPE=$(sudo dmidecode -t 16 | grep "Error Correction Type:" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
if [ -z "$ECC_TYPE" ] || [ "$ECC_TYPE" == "None" ]; then | |
ECC="Non-ECC" | |
else | |
ECC="ECC" | |
fi | |
MEMORY_TYPE=$(echo "$FIRST_SLOT_INFO" | grep "^[[:space:]]*Type:" | grep -v "Type Detail" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
MEMORY_SPEED=$(echo "$FIRST_SLOT_INFO" | grep "^[[:space:]]*Speed:" | head -n1 | awk -F: '{print $2}' | sed 's/^[ \t]*//') | |
echo -e "\n${YELLOW}${BOLD}Recommended RAM Specifications to Maximize Memory:${NC}" | |
echo "---------------------------------------------------" | |
echo -e "${CYAN}Form Factor..............:${NC} $FORM_FACTOR" | |
echo -e "${CYAN}Pins.....................:${NC} $(infer_pins "$FORM_FACTOR" "$MEMORY_TYPE")" | |
echo -e "${CYAN}Memory Type..............:${NC} $MEMORY_TYPE" | |
echo -e "${CYAN}Memory Speed.............:${NC} $MEMORY_SPEED" | |
echo -e "${CYAN}Voltage..................:${NC} $VOLTAGE" | |
echo -e "${CYAN}Error Correction.........:${NC} $ECC" | |
echo -e "${CYAN}Total Slots..............:${NC} $TOTAL_SLOTS" | |
# Calculate maximum capacity per slot | |
MAX_CAPACITY_NUM=$(echo "$MAX_MEMORY" | grep -o '[0-9]\+') | |
MAX_CAPACITY_UNIT=$(echo "$MAX_MEMORY" | grep -o '[A-Za-z]\+') | |
if [ "$MAX_CAPACITY_UNIT" == "GB" ]; then | |
MAX_CAPACITY_MB=$((MAX_CAPACITY_NUM * 1024)) | |
elif [ "$MAX_CAPACITY_UNIT" == "MB" ]; then | |
MAX_CAPACITY_MB=$MAX_CAPACITY_NUM | |
else | |
MAX_CAPACITY_MB=0 | |
fi | |
MAX_PER_SLOT=$((MAX_CAPACITY_MB / TOTAL_SLOTS)) | |
echo -e "${CYAN}Maximum Capacity per Slot:${NC} $MAX_PER_SLOT MB" | |
# Output recommendation | |
echo "" | |
echo -e "${GREEN}To maximize your system's memory, you should install $TOTAL_SLOTS RAM module(s) with the following specifications:${NC}" | |
echo -e "- ${CYAN}Capacity per module....:${NC} ${MAX_PER_SLOT} MB" | |
echo -e "- ${CYAN}Type...................:${NC} $MEMORY_TYPE" | |
echo -e "- ${CYAN}Form Factor............:${NC} $FORM_FACTOR" | |
echo -e "- ${CYAN}Pins...................:${NC} $(infer_pins "$FORM_FACTOR" "$MEMORY_TYPE")" | |
echo -e "- ${CYAN}Memory Speed...........:${NC} $MEMORY_SPEED" | |
echo -e "- ${CYAN}Voltage................:${NC} $VOLTAGE" | |
echo -e "- ${CYAN}Error Correction.......:${NC} $ECC" | |
echo "" | |
echo -e "${YELLOW}* Note:${NC} The actual maximum memory capacity might be higher than reported by the BIOS. Consult your CPU and motherboard documentation for exact limits." | |
echo "" | |
echo -e "${GREEN}RAM analysis completed.${NC}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment