diff --git a/includes/output.inc b/includes/output.inc
index f036e34..18d37c4 100644
--- a/includes/output.inc
+++ b/includes/output.inc
@@ -103,6 +103,9 @@ function drush_format($input, $label = NULL, $format = NULL) {
     case 'json':
       $output = drush_json_encode($input);
       break;
+    case 'properties':
+      $output = drush_format_properties($input);
+      break;
     case 'print_r':
     default:
       if (is_string($input)) {
@@ -394,5 +397,90 @@ function drush_json_decode($var) {
 }
 
 /**
+ * Fold input structure into array of dot separated key path = value
+ *
+ * Having output like this gives users the possibility to grep the output
+ * and still see the context.
+ *
+ * Output looks like
+ *
+ * node.bundles.page.label = Basic page
+ * node.bundles.page.admin.path = admin/structure/types/manage/%node_type
+ *
+ * @staticvar array $object_hash_list
+ *   Prevent object property recursion
+ * @param array $input
+ *   (sub)tree to process
+ * @param type $recurse
+ *   Prevent recursion
+ * @return type array
+ *   Array of key => value (x.y.z => string)
+ */
+function drush_format_properties(array $input, $recurse = FALSE) {
+  // We need to prevent recursive object parsing
+  static $object_hash_list;
+  if (!$recurse) {
+    // Reset hash
+    $object_hash_list = array();
+  }
+
+  if ($recurse == FALSE && !is_array($input)) {
+    return $input;
+  }
+  $keyed_results = array();
+  foreach ($input as $key => $value) {
+    if (is_array($value) || _drush_visit_object(&$object_hash_list, $value)) {
+      $temp = drush_format_properties((array) $value, TRUE);
+      foreach ($temp as $sub => $sub_value) {
+        $keyed_results["$key.$sub"] = $sub_value;
+      }
+    }
+    else {
+      $keyed_results["$key"] = $value;
+    }
+  }
+  if (!$recurse) {
+    drush_log("Format properties: Objects encountered: " . count($object_hash_list));
+    // We're done
+    $text = '';
+    foreach ($keyed_results as $key => $value) {
+      $text .= "$key = $value\n";
+    }
+    return $text;
+  }
+  return $keyed_results;
+}
+
+/**
+ * Helper to prevent recursion on objects
+ *
+ * @see drush_format_properties().
+ *
+ * @param type $cache
+ *   Reference array
+ * @param type $value
+ *   A value of any kind
+ * @return boolean
+ *   The current $value is not an object or not visited yet
+ */
+function _drush_visit_object(&$object_hash_list, $value) {
+  if (!is_array($object_hash_list)) {
+    $object_hash_list = array();
+  }
+  if (is_object($value)) {
+    $hash = spl_object_hash($value);
+    if (isset($object_hash_list[$hash])) {
+      return FALSE;
+    }
+    $object_hash_list[$hash] = $hash;
+    return TRUE;
+  }
+  else if (is_array($value)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
  * @} End of "defgroup outputfunctions".
  */
