Find All Joomla and Wordpress Installations on your Server


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 ;




Comments

Please login to comment