linux bash

Redis Session Scanner

Scan Redis sessions by emplid or find stale sessions (TTL > 8 hours), with an optional delete mode.

Scans all sess:* keys in Redis. Search by emplid to locate a specific user’s session, or use --stale to surface sessions with a TTL over 8 hours (or no expiry at all). Add --delete to remove matches. Shows a live scan counter and pulls username/osuid out of each matching session value.

#!/bin/bash

# Redis Session Scanner
# Usage:
#   ./find-redis-session.sh <emplid> [--delete]       Search by emplid
#   ./find-redis-session.sh --stale [--delete]        Find sessions with TTL > 8 hours

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

REDIS_HOST="<redis-host>"
REDIS_PORT="6379"
MAX_TTL=28800  # 8 hours in seconds

MODE="emplid"
DELETE=""
EMPLID=""

# Parse arguments
for arg in "$@"; do
  case "$arg" in
    --stale) MODE="stale" ;;
    --delete) DELETE="--delete" ;;
    *) EMPLID="$arg" ;;
  esac
done

if [ "$MODE" = "emplid" ] && [ -z "$EMPLID" ]; then
  echo "Usage:"
  echo "  $0 <emplid> [--delete]       Search by emplid"
  echo "  $0 --stale [--delete]        Find sessions with TTL > 8 hours"
  exit 1
fi

# Header
echo -e "${CYAN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║  Redis Session Scanner                           ║${NC}"
if [ "$MODE" = "stale" ]; then
echo -e "${CYAN}║  Filter: ${YELLOW}TTL > 8 hours${CYAN}                          ║${NC}"
else
echo -e "${CYAN}║  Searching for emplid: ${YELLOW}${EMPLID}${CYAN}                 ║${NC}"
fi
if [ "$DELETE" = "--delete" ]; then
echo -e "${CYAN}║  Mode: ${RED}DELETE${CYAN}                                     ║${NC}"
else
echo -e "${CYAN}║  Mode: ${GREEN}SEARCH ONLY${CYAN}                               ║${NC}"
fi
echo -e "${CYAN}╚══════════════════════════════════════════════════╝${NC}"
echo ""

STARTED=$(date +%s)

redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" --scan --pattern "sess:*" | {
SCANNED=0
FOUND=0

while read key; do
  SCANNED=$((SCANNED + 1))

  # Status update every 1000 keys (in-place)
  if [ $((SCANNED % 1000)) -eq 0 ]; then
    ELAPSED=$(( $(date +%s) - STARTED ))
    printf "\r  ${BLUE}⟳${NC} Scanned ${YELLOW}${SCANNED}${NC} sessions... (${ELAPSED}s elapsed, ${GREEN}${FOUND} found${NC})    "
  fi

  if [ "$MODE" = "stale" ]; then
    # Check TTL first (cheap operation)
    TTL=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" TTL "$key" 2>/dev/null)
    if [ "$TTL" -gt "$MAX_TTL" ] 2>/dev/null || [ "$TTL" -eq -1 ] 2>/dev/null; then
      FOUND=$((FOUND + 1))
      printf "\r                                                              \r"

      VALUE=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" GET "$key" 2>/dev/null)
      USERNAME=$(echo "$VALUE" | grep -oP '"username":"[^"]*"' | head -1)
      OSUID=$(echo "$VALUE" | grep -oP '"osuid":"[^"]*"' | head -1)

      if [ "$TTL" -eq -1 ] 2>/dev/null; then
        echo -e "  ${RED}✗ NO EXPIRY${NC}  ${YELLOW}${key}${NC}  ${CYAN}${OSUID} ${USERNAME}${NC}"
      else
        HOURS=$((TTL / 3600))
        MINS=$(( (TTL % 3600) / 60 ))
        echo -e "  ${YELLOW}⚠ TTL ${HOURS}h${MINS}m${NC}    ${YELLOW}${key}${NC}  ${CYAN}${OSUID} ${USERNAME}${NC}"
      fi

      if [ "$DELETE" = "--delete" ]; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" DEL "$key" > /dev/null 2>&1
        echo -e "              ${RED}✗ DELETED${NC}"
      fi
    fi

  else
    # Search by emplid
    VALUE=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" GET "$key" 2>/dev/null)
    if echo "$VALUE" | grep -q "$EMPLID"; then
      FOUND=$((FOUND + 1))
      printf "\r                                                              \r"
      echo ""
      echo -e "  ${GREEN}✓ MATCH${NC} ${YELLOW}${key}${NC}"

      USERNAME=$(echo "$VALUE" | grep -oP '"username":"[^"]*"' | head -1)
      OSUID=$(echo "$VALUE" | grep -oP '"osuid":"[^"]*"' | head -1)
      echo -e "    ${CYAN}${OSUID} ${USERNAME}${NC}"

      TTL=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" TTL "$key" 2>/dev/null)
      if [ "$TTL" -gt 0 ] 2>/dev/null; then
        HOURS=$((TTL / 3600))
        MINS=$(( (TTL % 3600) / 60 ))
        echo -e "    TTL: ${YELLOW}${HOURS}h ${MINS}m${NC} remaining"
      elif [ "$TTL" -eq -1 ] 2>/dev/null; then
        echo -e "    TTL: ${RED}no expiry set${NC}"
      fi

      if [ "$DELETE" = "--delete" ]; then
        redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" DEL "$key" > /dev/null 2>&1
        echo -e "    ${RED}✗ DELETED${NC}"
      fi
      echo ""
    fi
  fi
done

ELAPSED=$(( $(date +%s) - STARTED ))
printf "\r                                                              \r"
echo -e "${CYAN}──────────────────────────────────────────────────${NC}"
echo -e "  Done. Scanned ${YELLOW}${SCANNED}${NC} sessions in ${YELLOW}${ELAPSED}s${NC}. Found ${GREEN}${FOUND}${NC} matches."
echo ""
}