Find All Joomla and Wordpress Installations on your Server
- 06/06/2020 8:01 PM
This Script is a compliation of our j.sh and w.sh scripts. It will search any hosting server for all installations of Joomla and Wordpress. It will then output the version, site and status of each installation. If you choose to use the email portion of the script you will have a CSV file (easy to use in Excel) sorted by version and site sent to your email
This script makes fast work of tracking down old Joomal and Wordpress installations. It could easily be expanded to email the site owner a notification that they need to update their CMS.
Script (save as jw.sh or similar in /root/scripts)
#!/bin/bash
#########################################################
# #
# #
# Find Joomla and Wordpress Script #
# (Combined j.sh and w.sh) #
# 8Dweb LLC #
# 04-14-2016 #
# #
#########################################################
echo ""
echo ""
echo -e "\e[32m\e[1m|====================================================|"
echo "| |"
echo "| //Find Joomla & Wordpress Script Initializing// |"
echo "| |"
echo -e "|====================================================|\e[0m"
# The LAST version Joomla 1.5.x (Currently unused in Script)
LASTSUB15=26
# The LAST version Joomla 2.5.x (Currently unused in Script)
LASTSUB25=28
# The LAST version Joomla 3.4.x
# We Treat 3.4.latest as OK until further notice (04-09-2016 mjs)
LASTSUB34=8
# Current Joomla Version - 3.6.x
LATESTJOOM=3.6
# Current Joomla Version 3 SubVersion 3.5.x
CURSUB3=2
# Declare Variables for Script
LATESTWP=4.5
# Three Inputs are allowed to the Script
# Added mjs (04-12-2016) - Code to allow BASEPATH; OUTFILE and EMAIL to be entered by user
echo ""
echo ""
echo "Please Enter the base path for websites. " ;
echo -e "Leave blank for default path \e[36m\e[1m/chroot/home\e[0m:" ;
read BASEPATHINPUT
if [[ -d "$BASEPATHINPUT" ]] ; then
echo -e "\e[36m\e[1m$BASEPATHINPUT \e[0mseems to be a " ;
echo "legitimate directory on this server." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
BASEPATH=$BASEPATHINPUT ;
else
# default base path of the websites on YOUR server
# Edit Line 58 If you want to set a different default base path
echo -e "Your directory entry \e[31m\e[1m$BASEPATHINPUT is empty or invalid.\e[0m" ;
echo -e "Now using default \e[36m\e[1m/chroot/home\e[0m" ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
BASEPATH="/chroot/home/" ;
fi
# Obtain filenames for sorting and CSV output
# Obtain Joomla Output File
echo ""
echo ""
echo "Please Enter the filename for Joomla output from this script." ;
echo -e "Leave Blank for default filename \e[36m\e[1m>>joomla<<\e[0m to be used:" ;
read JPOUTFILEINPUT
if [[ "$JOUTFILEINPUT" != "" ]] ; then
echo "File \"$JOUTFILEINPUT\" will be used by this script." ;
echo "If you used "joomla" a sorted CSV will be emailed to you." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
JOUTFILE=$JOUTFILEINPUT ;
else
echo "No output file specified." ;
echo -e "Using default \e[36m\e[1mjoomla\e[0m filename." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
JOUTFILE="joomla" ;
fi
# Obtain Wordpress Output file
echo ""
echo ""
echo "Please Enter the filename for Wordpress output from this script." ;
echo -e "Leave Blank for default filename \e[36m\e[1m>>wordpress<<\e[0m to be used:" ;
read WOUTFILEINPUT
if [[ "$WOUTFILEINPUT" != "" ]] ; then
echo "File \"$WOUTFILEINPUT\" will be used by this script." ;
echo "If you used "wordpress" a sorted CSV will be emailed to you." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
WOUTFILE=$WOUTFILEINPUT ;
else
echo "No output file specified." ;
echo -e "Using default \e[36m\e[1mwordpress\e[0m filename." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
WOUTFILE="wordpress" ;
fi
# Obtain Email Address to which CSV can be sent
echo ""
echo ""
# Added mjs (04-12-2016) - Getmail Function - called by while loop...
getemail() {
echo "Please Enter a valid Email Address:" ;
echo "Example: joe@somedomain.com" ;
echo -e "Type \e[36m\e[1mNO\e[0m to bypass..." ;
read EMAIL
}
# Added mjs (04-12-2016) - While Loop checks for SIMPLE validation of email (i.e. jo@domain.com)
# Thanks to Stackoverflow.com for REGEX Ideas for simple email validation
# The regex is not perfect, but works for admins because we are supposed to be more intelligent....
mailregex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"
# While Loop to make sure a good email address is entered
while :; do
getemail
#echo $EMAIL
if [[ $EMAIL == "NO" ]] ; then
echo "" ;
echo "" ;
echo "You have chosen to NOT" ;
echo "enter an Email address." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
break ;
elif [[ $EMAIL =~ $mailregex ]] ; then
echo ""
echo ""
echo -e "Email address \e[36m\e[1m>> $EMAIL <<\e[0m seems valid. " ;
echo -e "\e[32m\e[1mProceeding....\e[0m" ;
break ;
else
echo "" ;
echo "" ;
echo -e "Email address \e[31m\e[1m>> $EMAIL << is INVALID.\e[0m" ;
echo "Please try again!" ;
fi
done
# First If statement checks to see if output filename was supplied when script was run
# Special checking for file named joomla so extra processing can occur
# for sorting and mailing of results as CSV file
# Cleanup any old files - remember you can place this in any folder so you need to
# Change the /root/scripts/ to what meets your requirements...
if [ -f /root/scripts/joomla ] && [ -f /root/scripts/wordpress ] ; then
echo "" ;
echo "" ;
echo "Cleaing up old output files..." ;
echo " -Removing File\: /root/scripts/joomla..." ;
echo " -Removing File\: /root/scripts/wordpress..." ;
echo " -Removing File\: /root/scripts/combined.sorted.csv..." ;
# If you run from another directory please change rm statement
# These files are created on a stock run-through so should be deleted
# automatically each time. Removal of files from previous runs
# Handled Here
rm -f /root/scripts/joomla /root/scripts/wordpress /root/scripts/combined.sorted.csv ;
echo "Finished Cleaning up old files..." ;
echo -e "\e[32m\e[1mProceeding...\e[0m" ;
fi
if [[ "$JOUTFILE" != "" ]] && [[ "$WOUTFILE" != "" ]]; then
# empty CSV file
echo -n "" > $JOUTFILE ;
echo -n "" > $WOUTFILE ;
fi
# Add Counter Option for easy "line numbers" later...
# Counter also is checked so that first line(s) of output are correct.
# Set Counter to One (not zero)
COUNTER=1
echo ""
echo ""
echo "Searching for Joomla Installs" ;
echo -e "\e[35m\e[1mPlease Wait...\e[0m" ;
echo ""
echo ""
# Primary If statment that recurses and finds all current Joomla Installs on Server
# Updated by MJS from original so that Drupal, Wordpress and certain Joomla folders are excluded
# This script **DOES** find joomla installs above webroots and secondary or backup installations
# We are checking for "components" folder. Since many templates and Plugins have this folder
# We need to eliminate them to speed and tighten search to legitimate Joomla installations.
for L in `find ${BASEPATH} -type d -name 'components' ! -wholename '**/app/*' ! -wholename '**/administrator/components' ! -wholename '**/administrator/*/components' ! -wholename '**/templates/*' ! -wholename '**/pagekit/*' ! -wholename '**/images/*' ! -wholename '**/media/*' ! -wholename '**/sites/*' ! -wholename '**/globalreleases/*' ! -wholename '**/wp-content/*' ! -wholename '**/concrete/*' ! -wholename '**/typo3/*' ! -wholename '**/plugins/*' ! -wholename '**/libraries/*' | grep -v '/tmp/'` ; do
# Get the base directory name for the Joomla installation
D=`dirname $L` ;
# Now that we have the correct directory for this Joomla install
# Check to see which version by testing for directory and existence of version.php
# For Joomla 1.5.x and 1.6 (We do not care about 1.x version of Joomla)
F=$D/libraries/joomla/version.php ;
# For Joomla 2.5.x and 3.x.x
F2=$D/libraries/cms/version/version.php ;
# Extract the Site from full directory... (testing)
# Works for /chroot/home - cut -d"/" -f5 may need adjusting if
# other directory depths occur (possibly script this...)
SITE=$( echo $D | cut -d"/" -f5) ;
#echo $SITE ;
# Set/Reset Variables that display findings later in script
ISOK=0 ; # ISOK holds value of whether version is Up-to-date or not
SHOWNEWEST="" ; # SHOWNEWEST holds value of latest Joomla Version (needs further work)
IMPORTANCE=0 ; # IMPORTANCE used previously - needs updating (mjs)
##BEGIN MAIN IF BLOCK
# Nested If that checks for existence of version.php
# And then Assigns F to path plus filename
# Updated mjs (04-09-2016) - F is for Joomla 1.5, 1.6, 1.7 - F2 is for Joomla 2.5 up
if [[ -e "$F" || -e "$F2" ]] ; then
##BEGIN IF BLOCK SET F VARIABLE
if [[ -e "$F" ]] ; then
F=$F ;
elif [[ -e "$F2" ]] ; then
F=$F2 ;
fi
##END IF BLOCK SET F VARIABLE
##BEGIN IF BLOCK TEST FOR RELEASE AND SUB VARIABLES
# Changed mjs (04-09-2016) - Added code to parse for const RELEASE for Joomla 3.5 and up (PHP7 compatible)
# For Joomla 1.5 through 3.4.x
if [[ `grep '$RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ]] ; then
VERSION=`grep '$RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
SUBVERSION=`grep '$DEV_LEVEL' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
# For Joomla 3.5 and up
elif [[ `grep 'const RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ]] ; then
VERSION=`grep 'const RELEASE' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
SUBVERSION=`grep 'const DEV_LEVEL' $F | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
fi
##END IF BLOCK TEST FOR RELEASE AND SUB VARIABLES
##BEGIN IF BLOCK TEST VERSION and SUBVERSION AND DECIDE ACTION Found in F (version.php)
# Rewritten mjs (04-09-2016) - Original code complex and wonky
# We want all versions under 3.4.8 Marked, Sorted and a Warning Given
echo "Version is: ${VERSION}" ;
if [ "${VERSION}" == "" ] ; then
ISOK="NOTJOOMLA" ;
echo "Site is Not Joomla! " ;
elif [ "${VERSION}" \< "2.5" ] ; then
#Version is 1.5.xx
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="EOL-1.5.xx-ARE-U-FREAKIN-NUTS?" ;
ISOK=0 ;
elif [ "${VERSION}" \< "3.0" ] ; then
# version is 2.5.xx
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="EOL-2.5.xx-UPGrade-CRITICAL" ;
ISOK=0 ;
elif [ "${VERSION}" \< "3.4" ] ; then
# version is 3.x.x but lower than 3.4
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="EOL-3.x.x-UPGrade-IMPORTANT" ;
ISOK=0 ;
elif [ "${VERSION}" == '3.4' ] && [ "${SUBVERSION}" \< "${LASTSUB34}" ] ; then
# version is 3.4 but is not latest 3.4.8 (as of 04-11-2016)
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="3.4.x-UPDate-IMPORTANT" ;
ISOK=0 ;
elif [ "${VERSION}.${SUBVERSION}" == '3.4.8' ] ; then
# version is 3.4.8 Special IMPORTANCE as of 04-11-2016
# 3.4.8 is not EOL So OK - Consider Upgrading to 3.5.x
# If you want users on 3.5.x release change SHOWNEWEST and IMPORTANCE here
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
# Important to Keep CURSUB3 variable updated in this script
IMPORTANCE="3.4.8-UPGradeE-TO-3.5.${CURSUB3}-AVAIL" ;
ISOK=0 ;
elif [ "${VERSION}" == '3.5' ] && [ "${SUBVERSION}" \< "${CURSUB3}" ] ; then
# version is 3.5 but lower than Latest
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="3.5.x-UPDate-TO-3.5.${CURSUB3}-AVAIL" ;
ISOK=0 ;
# Changed mjs (04-11-2016) - If Latest Version set ISOK=1
# rewrite status output for better SORT options later
# Also Added Output file logic (was missing in original)
# Output file is setup as CSV with Headers
else
ISOK=1 ;
SHOWNEWEST="${LATESTJOOM}.${CURSUB3}" ;
IMPORTANCE="OK" ;
# Echo out to Screen
# If This is the first time through lool then output header text to screen
if [ "${COUNTER}" == "1" ] ; then
echo "" ;
echo -e "\e[32m\e[1m*************************************" ;
echo "* Joomla Installations Found *" ;
echo -e "*VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*\e[0m" ;
echo "" ;
fi
#Echo Joomla Information to Screen
echo -e "$COUNTER \e[31m\e[1m$VERSION.$SUBVERSION\e[0m found in $SITE Latest=$SHOWNEWEST Status=$IMPORTANCE" ;
# Output to File if one is supplied when the script is run
if [[ "$JOUTFILE" != "" ]] ; then
echo $VERSION.$SUBVERSION,$SITE,$SHOWNEWEST,$IMPORTANCE >> $JOUTFILE ;
# Increase Counter (Screen Output only)
fi
fi
##END IF BLOCK TEST VERSION AND SUBVERSION AND DECIDE ACTION
fi ;
##END JOOMLA MAIN IF BLOCK
##BEGIN IF BLOCK ISOK is TRUE - Writes Out-of-Date Joomla Info to Screen & JOUTFILE
if [ "${ISOK}" == "NOTJOOMLA" ] ; then
echo
elif [[ $ISOK -eq 0 ]] ; then
#If This is the first time through Loop then Output Header to Screen
if [ "${COUNTER}" == "1" ] ; then
echo "" ;
echo -e "\e[32m\e[1m*************************************" ;
echo "* Joomla Installations Found *" ;
echo -e "*VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*\e[0m" ;
echo "" ;
fi
# Echo Joomla Information Out to Screen
echo -e "$COUNTER \e[31m\e[1m$VERSION.$SUBVERSION\e[0m found in $SITE Latest=$SHOWNEWEST Status=$IMPORTANCE" ;
# Output to File if one is supplied when the script is run
if [[ "$JOUTFILE" != "" ]] ; then
# write CSV file
echo $VERSION.$SUBVERSION,$SITE,$SHOWNEWEST,$IMPORTANCE >> $JOUTFILE ;
fi
fi
##END IF BLOCK ISOK is FALSE
# Reset Variables for Next Loop
IMPORTANCE=""
# Increase Counter
((COUNTER++))
done
##END JOOMLA BLOCK
echo ""
echo ""
echo "Now Searching for WordPress Installs" ;
echo -e "\e[35m\e[1mPlease Wait...\e[0m" ;
echo ""
echo ""
# Wordpress - Unlike Joomla stores version information
# In the same file across versions (Joomal get your act together!)
# Primary For Loop to setup and Display Information
# Reset Variables
COUNTER=1
IMPORTANCE=""
VERSION=""
ISOK=0
#Wordpress For Loop
for L in `find ${BASEPATH} -type d -name 'wp-includes'` ; do
DIR=`dirname $L` ;
FILE=$DIR/wp-includes/version.php
# This version is a bit quicker but leaves the ' ' around version
#VERSION=`grep 'wp_version =' $FILE |cut -d"=" -f2` ;
# This version is slower but produces clean version (i.e 4.5)
VERSION=`grep '\$wp_version =' $FILE | sed -r "s/^.*=\s*'(.*)'.*$/\1/g"` ;
# Test echo
#echo "Directory=$DIR and File=$FILE and version=$VERSION" ;
# Extract the Site from full directory... (testing)
# Works for /chroot/home - cut -d"/" -f5 may need adjusting if
# other directory depths occur (possibly script this...)
SITE=$( echo $DIR | cut -d"/" -f5) ;
#echo $SITE ;
# Set/Reset Variables that display findings later in script
ISOK=0 ; # ISOK holds value of whether version is Up-to-date or not
SHOWNEWEST="" ; # SHOWNEWEST holds value of latest WP version
IMPORTANCE=0 ; # IMPORTANCE for quick visual reference
##MAIN WORDPRESS IF BLOCK
# Tests for all versions under latest (4.5 as of 04-14-2016)
if [ "${VERSION}" \< "${LATESTWP}" ] ; then
ISOK=0 ;
SHOWNEWEST="${LATESTWP}" ; #redundant but leaving since it works
IMPORTANCE="WP-UPGRADE-REQUIRED" ;
# If WP install is the latest write out information to screen and OUTFILE
else
ISOK=1 ;
SHOWNEWEST="LATESTWP" ;
IMPORTANCE="OK" ;
# Echo out to Screen
# If This is the first time through lool then output header text to screen
if [ "${COUNTER}" == "1" ] ; then
echo "" ;
echo -e "\e[32m\e[1m*************************************" ;
echo "* WORDPRESS Installations Found *" ;
echo -e "*VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*\e[0m" ;
echo "" ;
fi
#Echo WORDPRESS Information to Screen
echo -e "$COUNTER \e[31m\e[1m$VERSION\e[0m found in $SITE Latest=$SHOWNEWEST Status=$IMPORTANCE" ;
# Output to File if one is supplied when the script is run
if [[ "$WOUTFILE" != "" ]] ; then
echo $VERSION,$SITE,$SHOWNEWEST,$IMPORTANCE >> $WOUTFILE ;
fi
fi
##END WORDPRESS MAIN IF BLOCK
##BEGIN IF BLOCK ISOK is FALSE - Writes Out-of-Date Joomla Info to Screen & OUTFILE
if [[ $ISOK -eq 0 ]] ; then
#If This is the first time through Loop then Output Header to Screen
if [ "${COUNTER}" == "1" ] ; then
echo "" ;
echo -e "\e[32m\e[1m*************************************" ;
echo "* Wordpress Installations Found *" ;
echo -e "*VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*\e[0m" ;
echo "" ;
fi
# Echo Joomla Information Out to Screen
echo -e "$COUNTER \e[31m\e[1m$VERSION\e[0m found in $SITE Latest=$SHOWNEWEST Status=$IMPORTANCE" ;
# Output to File if one is supplied when the script is run
if [[ "$WOUTFILE" != "" ]] ; then
# write CSV file
echo $VERSION,$SITE,$SHOWNEWEST,$IMPORTANCE >> $WOUTFILE ;
fi
fi
##END IF BLOCK ISOK is FALSE
# Reset Variables for Next Loop
IMPORTANCE=""
# Increase Counter
((COUNTER++))
done
##End Wordpress Block
# Sorting Routine to Make Output file easier to read/use
# Take JOUTFILE and WOUTFILE and add .sorted.csv for easy Excel / Spreadsheet manipulation
# Check if JOUTFILE and WOUTFILE are available (remember it was added at beginning)
if [[ "$JOUTFILE" != "" ]] && [[ "$WOUTFILE" != "" ]] ; then
# Echo Headers for CSV/EXCEL
echo "Joomla Installations" >> /root/scripts/combined.sorted.csv ;
echo Version,Site,Latest,Status >> /root/scripts/combined.sorted.csv ;
#Sort on 1st(Version) and 2nd (directory listing) Column and write out to *.sorted.csv
sort -k1 -k2 $JOUTFILE >> /root/scripts/combined.sorted.csv ;
echo " , , , " >> /root/scripts/combined.sorted.csv ;
echo "WordPress Installations" >> /root/scripts/combined.sorted.csv ;
echo Version,Site,Latest,Status >> /root/scripts/combined.sorted.csv ;
sort -k1 -k2 $WOUTFILE >> /root/scripts/combined.sorted.csv ;
fi
# If output file is named joomla then email joomla.sorted.csv file using mutt (must be installed)
if [ -f "/root/scripts/combined.sorted.csv" ] ; then
##BEGIN MAIL ROUTINE IF BLOCK
# Check to see if user set EMAIL to NO - if so then do not send email...
if [[ $EMAIL == "NO" ]] ; then
echo "" ;
echo "" ;
echo -e "\e[33m\e[1mNo Email will be sent...\e[0m" ;
else
echo "" ;
echo "" ;
echo -e "\e[32m\e[1mEmailing Sorted CSV File to \e[36m\e[1m>>$EMAIL<<\e[0m" ;
echo "Joomla and Wordpress Version Listing from CP1." | mutt -s "Joomla and Wordpress Version List" $EMAIL -a /root/scripts/combined.sorted.csv ;
fi
##END MAIL ROUTINE IF BLOCK
fi
echo ""
echo ""
echo -e "\e[31m\e[1m**********************************************************************"
echo -e "\e[31m\e[1m* //Find Joomla and Wordpress Installs SCRIPT FINISHED PROCESSING// *"
echo -e "\e[31m\e[1m**********************************************************************\e[0m"
# End of Script - Exit Properly...
exit 0 ;