diff --git a/commands/core/drupal/batch.inc b/commands/core/drupal/batch.inc
index 1165926..4d3e34c 100644
--- a/commands/core/drupal/batch.inc
+++ b/commands/core/drupal/batch.inc
@@ -14,7 +14,7 @@
  *    The command to call to process the batch.
  *
  */
-function _drush_backend_batch_process($command = 'batch-process') {
+function _drush_backend_batch_process($command, $interactive) {
   global $user;
   $batch =& batch_get();
 
@@ -52,12 +52,16 @@ function _drush_backend_batch_process($command = 'batch-process') {
     $finished = FALSE;
 
     while (!$finished) {
+      $args = array();
+      $args[] = $batch['id'];
       if ($user->uid) {
-        $data = drush_backend_invoke($command, array($batch['id'], '-u', $user->uid));
+        $args[] = '-u';
+        $args[] = $user->uid;
       }
-      else {
-        $data = drush_backend_invoke($command, array($batch['id']));
+      if ($interactive) {
+        $args['#interactive'] = TRUE;
       }
+      $data = drush_backend_invoke($command, $args);
       $finished = drush_get_error() || !$data || ($data['context']['drush_batch_process_finished'] == TRUE);
     }
   }
@@ -111,7 +115,6 @@ function _drush_batch_worker() {
   $current_set =& _batch_current_set();
   $set_changed = TRUE;
 
-
   timer_start('batch_processing');
   if (empty($current_set['start'])) {
     $current_set['start'] = microtime(TRUE);
diff --git a/commands/pm/pm.drush.inc b/commands/pm/pm.drush.inc
index 65bfc97..76076d4 100644
--- a/commands/pm/pm.drush.inc
+++ b/commands/pm/pm.drush.inc
@@ -181,6 +181,13 @@ function pm_drush_command() {
     'description' => 'Notify of pending db updates.',
     'hidden' => TRUE
   );
+  $items['pm-updatestatus-batch-process'] = array(
+    'description' => 'Callback to perform update status batch operations.',
+    'hidden' => TRUE,
+    'arguments' => array(
+      'batch-id' => 'The batch id that will be processed',
+    ),
+  );
   $items['pm-releasenotes'] = array(
     'description' => 'Print release notes for given projects.',
     'arguments' => array(
@@ -1608,6 +1615,14 @@ function drush_pm_updatecode_postupdate() {
 }
 
 /**
+ * Command callback. Execute pm-updatestatus-batch-process.
+ */
+function drush_pm_updatestatus_batch_process($id) {
+  drush_include_engine('update_info', 'drupal', NULL, DRUSH_BASE_PATH . '/commands/pm/update_info');
+  drush_batch_command($id);
+}
+
+/**
  * Determine a candidate destination directory for a particular site path and
  * return it if it exists, optionally attempting to create the directory.
  */
diff --git a/commands/pm/update_info/drupal.inc b/commands/pm/update_info/drupal.inc
index bfb79fa..d4ae74e 100644
--- a/commands/pm/update_info/drupal.inc
+++ b/commands/pm/update_info/drupal.inc
@@ -42,28 +42,61 @@ function pm_update_last_check() {
  */
 function _pm_refresh() {
   drush_print(dt("Refreshing update status information ..."));
-  update_refresh(TRUE);
+  update_refresh();
   drush_print(dt("Done."));
 }
 
 /**
  * Get update information for all installed projects.
  *
+ * @see update_get_available().
+ * @see update_manual_status().
+ *
  * @return An array containing remote and local versions for all installed projects
  */
 function _pm_get_update_info($projects) {
-  // We force a refresh if the cache is not available.
-  if (!cache_get('update_available_releases', 'cache_update')) {
-    _pm_refresh();
+  // Force to invalidate some caches that are only cleared 
+  // when visiting update status report page. This allow to detect changes in 
+  // .info files.
+  _update_cache_clear('update_project_data');
+  _update_cache_clear('update_project_projects'); 
+
+  // From update_get_available(): Iterate all projects and create a fetch task
+  // for those we have no information or is obsolete.
+  module_load_include('inc', 'update', 'update.compare');
+  $available = _update_get_cached_available_releases();
+  $num_avail = count($available);
+  $projects = update_get_projects();
+  foreach ($projects as $key => $project) {
+    if (empty($available[$key])) {
+      update_create_fetch_task($project);
+      continue;
+    }
+    if ($project['info']['_info_file_ctime'] > $available[$key]['last_fetch']) {
+      $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
+    }
+    if (empty($available[$key]['releases'])) {
+      $available[$key]['fetch_status'] = UPDATE_FETCH_PENDING;
+    }
+    if (!empty($available[$key]['fetch_status']) && $available[$key]['fetch_status'] == UPDATE_FETCH_PENDING) {
+      update_create_fetch_task($project);
+    }
   }
 
-  $info = update_get_available(TRUE);
+  // Set a batch to process all pending tasks.
+  $batch = array(
+    'operations' => array(
+      array('_pm_update_fetch_data_batch', array()),
+    ),
+    'finished' => 'update_fetch_data_finished',
+    'file' => drupal_get_path('module', 'update') . '/update.fetch.inc',
+  );
+  batch_set($batch);
+  drush_backend_batch_process('pm-updatestatus-batch-process', TRUE);
 
-  // Force to invalidate some update_status caches that are only cleared
-  // when visiting update status report page.
-  _update_cache_clear('update_project_data');
-  _update_cache_clear('update_project_projects'); 
-  $data = update_calculate_project_data($info);
+  // Calculate update status data.
+  $available = _update_get_cached_available_releases();
+  $data = update_calculate_project_data($available);
   foreach ($data as $project_name => $project) {
     // Discard custom projects.
     if ($project['status'] == UPDATE_UNKNOWN) {
@@ -105,3 +138,50 @@ function pm_get_project_info($projects) {
   }
   return $data;
 }
+
+/**
+ * Process a step in the batch for fetching available update data.
+ *
+ * This is an adaptation of update_fetch_data_batch() to fit drush log.
+ */
+function _pm_update_fetch_data_batch(&$context) {
+  $queue = DrupalQueue::get('update_fetch_tasks');
+  if (empty($context['sandbox']['max'])) {
+    $context['finished'] = 0;
+    $context['sandbox']['max'] = $queue->numberOfItems();
+    $context['sandbox']['progress'] = 0;
+    $context['results']['updated'] = 0;
+    $context['results']['failures'] = 0;
+    $context['results']['processed'] = 0;
+  }
+
+  // Grab another item from the fetch queue.
+  for ($i = 0; $i < 5; $i++) {
+    if ($item = $queue->claimItem()) {
+      if (_update_process_fetch_task($item->data)) {
+        $context['results']['updated']++;
+        drush_log(dt('Checked available update data for !title.', array('!title' => $item->data['info']['name'])), 'ok');
+      }
+      else {
+        drush_log(dt('Failed to check available update data for !title.', array('!title' => $item->data['info']['name'])), 'error');
+        $context['results']['failures']++;
+      }
+      $context['sandbox']['progress']++;
+      $context['results']['processed']++;
+      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+      $queue->deleteItem($item);
+    }
+    else {
+      // If the queue is currently empty, we're done. It's possible that
+      // another thread might have added new fetch tasks while we were
+      // processing this batch. In that case, the usual 'finished' math could
+      // get confused, since we'd end up processing more tasks that we thought
+      // we had when we started and initialized 'max' with numberOfItems(). By
+      // forcing 'finished' to be exactly 1 here, we ensure that batch
+      // processing is terminated.
+      $context['finished'] = 1;
+      return;
+    }
+  }
+}
+
diff --git a/includes/batch.inc b/includes/batch.inc
index f0fd8d9..1bb19f0 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -48,9 +48,9 @@
  *   use their own command.
  *
  */
-function drush_backend_batch_process($command = 'batch-process') {
+function drush_backend_batch_process($command = 'batch-process', $interactive = FALSE) {
   drush_include_engine('drupal', 'batch', drush_drupal_major_version());
-  _drush_backend_batch_process($command);
+  _drush_backend_batch_process($command, $interactive);
 }
 
 /**
