Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42568)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 42569)
@@ -1424,5 +1424,5 @@
   <interface
     name="IVirtualBox" extends="$unknown"
-    uuid="53789455-fad2-425a-94c8-eb6dc4ceaa05"
+    uuid="3b90eded-f061-432f-9e0f-4b53cc7b6fa0"
     wsmap="managed"
     >
@@ -1837,4 +1837,18 @@
       <param name="machine" type="IMachine" dir="return">
         <desc>Machine object, if found.</desc>
+      </param>
+    </method>
+
+    <method name="getMachinesByGroups">
+      <desc>
+        Gets all machine references which are in one of the specified groups.
+      </desc>
+      <param name="groups" type="wstring" dir="in" safearray="yes">
+        <desc>What groups to match. The usual group list rules apply, i.e.
+        passing an empty list will match VMs in the toplevel group, likewise
+        the empty string.</desc>
+      </param>
+      <param name="machines" type="IMachine" dir="return" safearray="yes">
+        <desc>All machines which matched.</desc>
       </param>
     </method>
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42568)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 42569)
@@ -673,10 +673,9 @@
 
     /**
-     * Checks if this machine is accessible, without attempting to load the
-     * config file.
-     *
-     * @note This method doesn't check this object's readiness. Intended to be
-     * used by ready Machine children (whose readiness is bound to the parent's
-     * one) or after doing addCaller() manually.
+     * Returns various information about this machine.
+     *
+     * @note This method doesn't lock this object or check its readiness.
+     * Intended to be used only after doing addCaller() manually and locking it
+     * for reading.
      */
     ChipsetType_T getChipsetType() const { return mHWData->mChipsetType; }
@@ -688,4 +687,6 @@
     void allowStateModification()           { mData->m_fAllowStateModification = true; }
     void disallowStateModification()        { mData->m_fAllowStateModification = false; }
+
+    const StringsList &getGroups() const { return mUserData->s.llGroups; }
 
     // callback handlers
Index: /trunk/src/VBox/Main/include/VirtualBoxImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 42568)
+++ /trunk/src/VBox/Main/include/VirtualBoxImpl.h	(revision 42569)
@@ -137,4 +137,5 @@
     STDMETHOD(RegisterMachine)(IMachine *aMachine);
     STDMETHOD(FindMachine)(IN_BSTR aNameOrId, IMachine **aMachine);
+    STDMETHOD(GetMachinesByGroups)(ComSafeArrayIn(IN_BSTR, aGroups), ComSafeArrayOut(IMachine *, aMachines));
     STDMETHOD(GetMachineStates)(ComSafeArrayIn(IMachine *, aMachines), ComSafeArrayOut(MachineState_T, aStates));
     STDMETHOD(CreateAppliance)(IAppliance **anAppliance);
Index: /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 42568)
+++ /trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp	(revision 42569)
@@ -985,11 +985,9 @@
         if (pMachine->isAccessible())
         {
-            SafeArray<BSTR> thisGroups;
-            HRESULT rc = pMachine->COMGETTER(Groups)(ComSafeArrayAsOutParam(thisGroups));
-            if (FAILED(rc))
-                continue;
-
-            for (size_t i = 0; i < thisGroups.size(); i++)
-                allGroups.push_back(thisGroups[i]);
+            const StringsList &thisGroups = pMachine->getGroups();
+            for (StringsList::const_iterator it2 = thisGroups.begin();
+                 it2 != thisGroups.end();
+                 ++it2)
+                allGroups.push_back(*it2);
         }
     }
@@ -1722,4 +1720,74 @@
 
     return rc;
+}
+
+STDMETHODIMP VirtualBox::GetMachinesByGroups(ComSafeArrayIn(IN_BSTR, aGroups), ComSafeArrayOut(IMachine *, aMachines))
+{
+    CheckComArgSafeArrayNotNull(aGroups);
+    CheckComArgOutSafeArrayPointerValid(aMachines);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    StringsList llGroups;
+    HRESULT rc = convertMachineGroups(ComSafeArrayInArg(aGroups), &llGroups);
+    if (FAILED(rc))
+        return rc;
+    /* we want to rely on sorted groups during compare, to save time */
+    llGroups.sort();
+
+    /* get copy of all machine references, to avoid holding the list lock */
+    MachinesOList::MyList allMachines;
+    {
+        AutoReadLock al(m->allMachines.getLockHandle() COMMA_LOCKVAL_SRC_POS);
+        allMachines = m->allMachines.getList();
+    }
+
+    com::SafeIfaceArray<IMachine> saMachines;
+    for (MachinesOList::MyList::const_iterator it = allMachines.begin();
+         it != allMachines.end();
+         ++it)
+    {
+        const ComObjPtr<Machine> &pMachine = *it;
+        AutoCaller autoMachineCaller(pMachine);
+        if (FAILED(autoMachineCaller.rc()))
+            continue;
+        AutoReadLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
+
+        if (pMachine->isAccessible())
+        {
+            const StringsList &thisGroups = pMachine->getGroups();
+            for (StringsList::const_iterator it2 = thisGroups.begin();
+                 it2 != thisGroups.end();
+                 ++it2)
+            {
+                const Utf8Str &group = *it2;
+                bool fAppended = false;
+                for (StringsList::const_iterator it3 = llGroups.begin();
+                     it3 != llGroups.end();
+                     ++it3)
+                {
+                    int order = it3->compare(group);
+                    if (order == 0)
+                    {
+                        saMachines.push_back(pMachine);
+                        fAppended = true;
+                        break;
+                    }
+                    else if (order > 0)
+                        break;
+                    else
+                        continue;
+                }
+                /* avoid duplicates and save time */
+                if (fAppended)
+                    break;
+            }
+        }
+    }
+
+    saMachines.detachTo(ComSafeArrayOutArg(aMachines));
+
+    return S_OK;
 }
 
