Hello, in a multi-site drupal installation I have uploaded during the time hundred of modules, often just to realize they do not work the way I wanted and therefore they are disabled.

My question is, how can I quickly find which modules are not used by any site so I can physically remove them ?
Is there a drush command that do that?

Comments

lucascaro’s picture

drush pm-list | grep -v "Enabled"
will filter out enabled modules from the list

HylkeVDS’s picture

That will only list the modules for your "default" site and not for all sites in a multi-site setup.
I've also not found a nice way to get a per-module overview for all sites.

jamesfk’s picture

Did you ever find a solution for this?

I have a similar big cleanup job to do on a massive multi-site installation, and this would be very handy!

If not I'll post how I approached it once done :)

HylkeVDS’s picture

No, I just ended up doing a pm-list for each site, and pasting it into a spreadsheet. Far from ideal.

noelbush’s picture

This is hacky and imperfect, but if you run it from the root of your drupal installation, it should produce a list of module directories that you can safely remove. Ideally you could just pipe it to svn or whatever (e.g., "list-unused-modules.sh | xargs svn del"). That said, I did have trouble when I zapped them all at one go -- some module was inappropriately depending on the existence of another one, so I removed a few at a time until I narrowed it down.

list-unused-modules.sh:

#!/bin/bash
DB_PASSWORD=YOUR_MYSQL_ROOT_PASSWORD_HERE
for s in `ls -1 | egrep -v "^all$"`
do
    find $s -name settings.php
done | \
xargs egrep -h "^\\\$db_url" | \
sed -e "s/^\$db_url *= *'[a-z]\+:\/\/[^:]\+:[^@]\+@[^\/]\+\/\([^']\+\)';/\\1/g" | sort | uniq > /tmp/drupal_dbs
echo "show databases;" | mysql -u root --password=$DB_PASSWORD | sort | uniq > /tmp/db_list
for d in `comm -12 /tmp/db_list /tmp/drupal_dbs`
do
    echo "SELECT filename FROM $d.system WHERE type='module' AND filename LIKE 'sites/all/modules/%' AND status = 1;" | mysql -u root --password=$DB_PASSWORD
done | \
sed -e 's/sites\/all\/modules\/\([A-Za-z0-9_]\+\)\/.\+/\1/g' | \
sort | uniq > /tmp/modules_in_use
find all/modules -name '*.module' | sed -e 's/all\/modules\/\([A-Za-z0-9_]\+\)\/.\+/\1/g' | sort | uniq > /tmp/all_modules
diff --suppress-common-lines /tmp/all_modules /tmp/modules_in_use | egrep "^<" | sed -e 's/^< //g' | sed -e 's/^/all\/modules\//g'
rm /tmp/drupal_dbs /tmp/db_list /tmp/all_modules /tmp/modules_in_use

Note where you need to insert your mysql root password.

Ugly, I know, but gets the job done.

areynolds’s picture

Something like this should work:

drush pm-list --no-core --status=disabled --pipe | drush pm-uninstall

but for some reason that doesn't do the trick. The below, however, will give you a list of disabled modules.

drush pm-list --status=disabled

If someone knows what I'm doing wrong on the first command, please let me know ;)

--Alec

Tandem

areynolds’s picture

Oh, this fixes my command:

drush pm-uninstall `drush pm-list --pipe --no-core --status=disabled`

Thanks to the drush wizards.

--Alec

Tandem

lmeurs’s picture

I was looking for a similar solution and could not find anything that could be used on a Windows workstation, so I wrote a small Drush command that checks if a site uses a certain module. It only works module-by-module and reports sites that use a given module.

To use the Drush command:

  1. Create a folder named is_module_used in your Drush command folder (on my W7 workstation the location is USERNAME/.drush);
  2. In this folder, create a file named is_module_used.drush.inc and copy + paste the script underneath;
  3. Open your prompt window, navigate to the root directory of your multisite install, and execute the following command:
    drush @sites is-module-used -y --pm=NAME_OF_YOUR_MODULE.

The script now iterates through all sites and checks per site in the database in the system table 1) if a record for the module exists and 2) if the value of schema_version is not -1. This way site names wil be output if they use the module (module is enabled or needs to be uninstalled). If no site names appear, the module is unused and can be safely removed.

/**
 * @file
 *  Drush command to check if a module is used by any site.
 */

/**
 * Implements hook_drush_command().
 */
function is_module_used_drush_command() {
  $items = array();
  $items['is-module-used'] = array(
    'callback' => 'is_module_used',
    'description' => dt('Check if a module is used by any site.'),
    'options' => array(
      'pm' => 'The name of the module you are looking for.',
    ),
  );
  return $items;
}

/**
 * Check in the system table if the site uses the given module: if a record for 
 * the module exists and if the value of schema_version is not -1.
 */
function is_module_used() {
  $pm = drush_get_option('pm');

  if (!$pm) {
    drush_print('Option pm not defined.');
    return;
  }

  $modules = db_query("SELECT status, filename FROM {system} WHERE type = 'module' AND name = :name AND schema_version <> -1 ORDER BY filename", array(':name' => $pm));

  foreach ($modules as $module) {
    $status = $module->status == 1 ? 'ENABLED' : 'WAITING FOR UNINSTALL';
    drush_print($status . ' (' . $module->filename . ')');
  }
}

Laurens Meurs
wiedes.nl

cilefen’s picture

@lmeurs Thank you for posting this.

nicholasthompson’s picture

This lists all modules (NOT packages) which are not installed across all the sites in a multisite:

drush -y @sites pm-list --no-core --status='not installed' --pipe | sort | uniq -c | grep -E '^[[:space:]]+6'

Change the '6' at the end to however many sites you're running.

the challenge now is to to find entire packages which are not enabled ;-)

rineez’s picture

but sorry I haven't tried this in a multi-site environment.
https://www.drupal.org/project/unused_modules

Have a good day! ;)