Index: src/test/groovy/ClosureTest.groovy
===================================================================
--- src/test/groovy/ClosureTest.groovy	(revision 10329)
+++ src/test/groovy/ClosureTest.groovy	(working copy)
@@ -121,6 +121,30 @@
         assert str == 'abcd' && sum == 6
     }
 
+    void testMapWithEntryIndex() {
+        def keyStr = ''
+        def valStr = ''
+        def sum = 0
+        ['a':'z','b':'y','c':'x','d':'w'].eachWithIndex { entry, index ->
+            keyStr += entry.key
+            valStr += entry.value
+            sum += index
+        }
+        assert keyStr == 'abcd' && valStr == 'zyxw' && sum == 6
+    }
+
+    void testMapWithKeyValueIndex() {
+        def keyStr = ''
+        def valStr = ''
+        def sum = 0
+        ['a':'z','b':'y','c':'x','d':'w'].eachWithIndex { k, v, index ->
+            keyStr += k
+            valStr += v
+            sum += index
+        }
+        assert keyStr == 'abcd' && valStr == 'zyxw' && sum == 6
+    }
+
     /**
     * Test access to Closure's properties
     * cf GROOVY-2089
Index: src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
===================================================================
--- src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java	(revision 10329)
+++ src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java	(working copy)
@@ -1059,6 +1059,26 @@
     }
 
     /**
+     * Allows a Map to be iterated through using a closure. If the
+     * closure takes two parameters then it will be passed the Map.Entry and
+     * the item's index (a counter starting at zero) otherwise if the closure
+     * takes three parameters then it will be passed the key, the value, and
+     * the index.
+     *
+     * @param self    the map over which we iterate
+     * @param closure a Closure to operate on each item
+     * @return the self Object
+     */
+    public static Object eachWithIndex(Map self, Closure closure) {
+        int counter = 0;
+        for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            callClosureForMapEntryAndCounter(closure, entry, counter++);
+        }
+        return self;
+    }
+
+    /**
      * Iterate over each element of the list in the reverse order.
      *
      * @param self    a List
@@ -1640,7 +1660,17 @@
         return closure.call(entry);
     }
 
+    protected static Object callClosureForMapEntryAndCounter(Closure closure, Map.Entry entry, int counter) {
+        if (closure.getMaximumNumberOfParameters() == 3) {
+            return closure.call(new Object[]{entry.getKey(), entry.getValue(),
+                Integer.valueOf(counter)});
+        } else if (closure.getMaximumNumberOfParameters() == 2) {
+            return closure.call(new Object[]{entry, Integer.valueOf(counter)});
+        }
+        return closure.call(entry);
+    }
 
+
     /**
      * Iterates through the given collection, passing in the initial value to
      * the closure along with the current iterated item then passing into the

