diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplica.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplica.java
index 2382b597a5a8959b454d5de4169a71fedd1b4ebc..0eddef3c95b61327117f2ef06dfa5423230d64f6 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplica.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplica.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.cina.client.util.cli;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.List;
 
 import ch.systemsx.cisd.args4j.Option;
 import ch.systemsx.cisd.cina.client.util.v1.ICinaUtilities;
@@ -37,11 +38,24 @@ public class CommandGetReplica extends
         @Option(name = "o", longName = "output", usage = "Path for output")
         private String output = "";
 
+        public String tryBundleMetadataOwnerIdentifier()
+        {
+            String replicaId = getArguments().get(0);
+            if (replicaId.length() > 0)
+            {
+                return replicaId.toUpperCase();
+            }
+            return null;
+        }
+
         public ArrayList<String> getReplicaIdentifiers()
         {
             ArrayList<String> replicaIds = new ArrayList<String>();
-            for (String replicaId : getArguments())
+            List<String> args = getArguments();
+            int size = args.size();
+            for (int i = 1; i < size; ++i)
             {
+                String replicaId = args.get(i);
                 if (replicaId.length() > 0)
                 {
                     replicaIds.add(replicaId.toUpperCase());
@@ -58,7 +72,12 @@ public class CommandGetReplica extends
         @Override
         public boolean isComplete()
         {
-            if (getArguments().size() < 1)
+            if (getArguments().size() < 2)
+            {
+                return false;
+            }
+
+            if (null == tryBundleMetadataOwnerIdentifier())
             {
                 return false;
             }
@@ -92,11 +111,15 @@ public class CommandGetReplica extends
             File outputDir = getOutputDir();
             outputDir.mkdirs();
 
+            // Grid Id must be non-null & non-empty -- otherwise, we wouldn't be here
+            String gridIdentifier = arguments.tryBundleMetadataOwnerIdentifier();
+
             // Find all datasets connected to this sample
-            for (String sampleCode : arguments.getReplicaIdentifiers())
+            for (String sampleIdentifier : arguments.getReplicaIdentifiers())
             {
                 ReplicaDownloader downloader =
-                        new ReplicaDownloader(component, sampleCode, outputDir);
+                        new ReplicaDownloader(component, gridIdentifier, sampleIdentifier,
+                                outputDir);
                 downloader.download();
             }
             return ResultCode.OK;
@@ -136,6 +159,6 @@ public class CommandGetReplica extends
     @Override
     protected String getRequiredArgumentsString()
     {
-        return "<replica identifier> [<replica identifier> ...]";
+        return "<grid identifier> <replica identifier> [<replica identifier> ...]";
     }
 }
diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/ReplicaDownloader.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/ReplicaDownloader.java
index 070044cee82dacc781e3cb9520a1b9d04f01afd7..cecc2db4c352af991c8665eeb804acf05fde9ee1 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/ReplicaDownloader.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/cli/ReplicaDownloader.java
@@ -17,15 +17,24 @@
 package ch.systemsx.cisd.cina.client.util.cli;
 
 import java.io.File;
+import java.util.Collections;
 import java.util.List;
 
 import ch.systemsx.cisd.cina.client.util.v1.ICinaUtilities;
 import ch.systemsx.cisd.cina.shared.constants.BundleStructureConstants;
 import ch.systemsx.cisd.cina.shared.constants.CinaConstants;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.dss.client.api.v1.FileInfoDssDownloader;
 import ch.systemsx.cisd.openbis.dss.client.api.v1.IDataSetDss;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.FileInfoDssDTO;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClause;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClauseAttribute;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
 
 /**
  * Utility class for downloading replicas.
@@ -36,14 +45,18 @@ class ReplicaDownloader
 {
     private final ICinaUtilities component;
 
-    private final String replicaCode;
+    private final SampleIdentifier replicaIdentifier;
+
+    private final SampleIdentifier gridIdentifier;
 
     private final File outputDir;
 
-    ReplicaDownloader(ICinaUtilities component, String code, File outputDir)
+    ReplicaDownloader(ICinaUtilities component, String bundleIdentifier, String replicaIdentifier,
+            File outputDir)
     {
         this.component = component;
-        this.replicaCode = code;
+        this.replicaIdentifier = SampleIdentifierFactory.parse(replicaIdentifier);
+        this.gridIdentifier = SampleIdentifierFactory.parse(bundleIdentifier);
         this.outputDir = outputDir;
     }
 
@@ -78,10 +91,24 @@ class ReplicaDownloader
         }
     }
 
+    /**
+     * Retrieve the raw data and current metadata for the replica sample as well as the current
+     * metadata for the parent grid of the replica.
+     */
     protected void download()
     {
-        // Find all datasets connected to this sample
-        List<DataSet> dataSets = component.listDataSetsForSampleCode(replicaCode);
+        // Get the replica and parent grid samples.
+        Sample replicaSample = searchForSample(replicaIdentifier);
+        downloadReplica(replicaSample);
+
+        Sample gridSample = searchForSample(gridIdentifier);
+        downloadGrid(gridSample);
+    }
+
+    private void downloadReplica(Sample replicaSample)
+    {
+        // Find all datasets connected to the replica sample
+        List<DataSet> dataSets = component.listDataSets(Collections.singletonList(replicaSample));
 
         DataSet mostRecentMetadata = null;
 
@@ -96,15 +123,7 @@ class ReplicaDownloader
 
             if (typeCode.equals(CinaConstants.METADATA_DATA_SET_TYPE_CODE))
             {
-                if (null == mostRecentMetadata)
-                {
-                    mostRecentMetadata = dataSet;
-                } else if (mostRecentMetadata.getRegistrationDate().compareTo(
-                        dataSet.getRegistrationDate()) < 0)
-                {
-                    // This element is newer than the current value
-                    mostRecentMetadata = dataSet;
-                }
+                mostRecentMetadata = compareReturningMoreRecent(mostRecentMetadata, dataSet);
             }
         }
 
@@ -115,12 +134,74 @@ class ReplicaDownloader
         }
     }
 
-    private void downloadDataSet(DataSet dataSet, String subfolderName)
+    private void downloadGrid(Sample parentGridSample)
+    {
+        // Find all datasets connected to the grid sample
+        List<DataSet> dataSets =
+                component.listDataSets(Collections.singletonList(parentGridSample));
+
+        DataSet mostRecentMetadata = null;
+
+        for (DataSet dataSet : dataSets)
+        {
+            String typeCode = dataSet.getDataSetTypeCode();
+            if (typeCode.equals(CinaConstants.METADATA_DATA_SET_TYPE_CODE))
+            {
+                mostRecentMetadata = compareReturningMoreRecent(mostRecentMetadata, dataSet);
+            }
+        }
+
+        // Download the most recent metadata data set
+        if (null != mostRecentMetadata)
+        {
+            downloadDataSet(mostRecentMetadata, null);
+        }
+    }
+
+    private DataSet compareReturningMoreRecent(DataSet mostRecentReplicaMetadata, DataSet dataSet)
+    {
+        if (null == mostRecentReplicaMetadata)
+        {
+            return dataSet;
+        } else if (mostRecentReplicaMetadata.getRegistrationDate().compareTo(
+                dataSet.getRegistrationDate()) < 0)
+        {
+            // This element is newer than the current value
+            return dataSet;
+        }
+        return mostRecentReplicaMetadata;
+    }
+
+    private Sample searchForSample(SampleIdentifier identifier)
+    {
+        // Get the sample
+        // Find the sample that matches the given code (there should only be 1)
+        SearchCriteria searchCriteria = new SearchCriteria();
+        searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE,
+                identifier.getSampleCode()));
+        List<Sample> samples = component.searchForSamples(searchCriteria);
+        if (samples.size() < 1)
+        {
+            throw new UserFailureException("No sample with specified code.");
+        }
+
+        // There should only be 1
+        if (samples.size() > 1)
+        {
+            throw new EnvironmentFailureException(
+                    "Found multiple matching samples -- this should not happen. Please contact administrator to resolve this problem.");
+        }
+        return samples.get(0);
+    }
+
+    private void downloadDataSet(DataSet dataSet, String subfolderNameOrNull)
     {
         IDataSetDss dataSetDss = component.getDataSet(dataSet.getCode());
         FileInfoDssDTO[] fileInfos = dataSetDss.listFiles("/original/", true);
 
-        File targetDir = new File(outputDir, subfolderName);
+        File targetDir =
+                (subfolderNameOrNull != null) ? new File(outputDir, subfolderNameOrNull)
+                        : outputDir;
         FileInfoDssDownloader downloader =
                 new FileInfoDssDownloader(dataSetDss, fileInfos, targetDir, new DownloaderListener(
                         targetDir));
diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/ICinaUtilities.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/ICinaUtilities.java
index 4c3f406bd31c747ebba307e7bcf2f6a3fbf32604..c9fd6f29e6ab8f0433afa0acab9d11d5a86dde47 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/ICinaUtilities.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/ICinaUtilities.java
@@ -80,15 +80,14 @@ public interface ICinaUtilities
     /**
      * Return a list of data sets for the sample specified by code.
      * 
-     * @param sampleCode The code of the sample we are interested in. It is assumed that the code is
-     *            unique.
+     * @param samples The samples we want to retrieve data sets for
      * @return The data sets connected to the sample
      * @throws IllegalStateException Thrown if the user has not yet been authenticated.
      * @throws EnvironmentFailureException Thrown in cases where it is not possible to connect to
      *             the server or if there are multiple samples with the given code.
      * @throws UserFailureException Thrown if no sample exists with the specified code.
      */
-    public List<DataSet> listDataSetsForSampleCode(String sampleCode) throws IllegalStateException,
+    public List<DataSet> listDataSets(List<Sample> samples) throws IllegalStateException,
             EnvironmentFailureException, UserFailureException;
 
     /**
diff --git a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/impl/CinaUtilitiesFacade.java b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/impl/CinaUtilitiesFacade.java
index 2adf207556c6db78a17f060de0e844e3285f44cc..17f2e85d07aefcff90d3c33c03bc190a939ba077 100644
--- a/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/impl/CinaUtilitiesFacade.java
+++ b/rtd_cina/source/java/ch/systemsx/cisd/cina/client/util/v1/impl/CinaUtilitiesFacade.java
@@ -39,8 +39,6 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Project;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria;
-import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClause;
-import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClauseAttribute;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SpaceWithProjectsAndRoleAssignments;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 
@@ -239,10 +237,10 @@ public class CinaUtilitiesFacade implements ICinaUtilities
         return state.listVisibleExperiments(experimentType);
     }
 
-    public List<DataSet> listDataSetsForSampleCode(String sampleCode) throws IllegalStateException,
+    public List<DataSet> listDataSets(List<Sample> samples) throws IllegalStateException,
             EnvironmentFailureException
     {
-        return state.listDataSetsForSampleCode(sampleCode);
+        return state.listDataSets(samples);
     }
 
     public IDataSetDss getDataSet(String dataSetCode) throws IllegalStateException,
@@ -292,7 +290,7 @@ abstract class AbstractCinaFacadeState implements ICinaUtilities
         throw new IllegalStateException("Please log in");
     }
 
-    public List<DataSet> listDataSetsForSampleCode(String sampleCode) throws IllegalStateException,
+    public List<DataSet> listDataSets(List<Sample> samples) throws IllegalStateException,
             EnvironmentFailureException
     {
         throw new IllegalStateException("Please log in");
@@ -460,7 +458,7 @@ class AuthenticatedState extends AbstractCinaFacadeState
     }
 
     @Override
-    public List<DataSet> listDataSetsForSampleCode(String sampleCode) throws IllegalStateException,
+    public List<DataSet> listDataSets(List<Sample> samples) throws IllegalStateException,
             EnvironmentFailureException
     {
         // This functionality has only been supported since version 1.1
@@ -470,23 +468,6 @@ class AuthenticatedState extends AbstractCinaFacadeState
             throw new EnvironmentFailureException("Server does not support this feature.");
         }
 
-        // Find the sample that matches the given code (there should only be 1)
-        SearchCriteria searchCriteria = new SearchCriteria();
-        searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE,
-                sampleCode));
-        List<Sample> samples = service.searchForSamples(sessionToken, searchCriteria);
-        if (samples.size() < 1)
-        {
-            throw new UserFailureException("No sample with specified code.");
-        }
-
-        // There should only be 1
-        if (samples.size() > 1)
-        {
-            throw new EnvironmentFailureException(
-                    "Found multiple matching samples -- this should not happen. Please contact administrator to resolve this problem.");
-        }
-
         return service.listDataSets(sessionToken, samples);
     }
 
diff --git a/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplicaTest.java b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplicaTest.java
index 0c85866972c517cbcfc50e2e05fad6a447121d2d..104974b3d77e1e81b4330b9f64c2d1dc111c1b0b 100644
--- a/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplicaTest.java
+++ b/rtd_cina/sourceTest/java/ch/systemsx/cisd/cina/client/util/cli/CommandGetReplicaTest.java
@@ -126,11 +126,16 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
         context.checking(new Expectations()
             {
                 {
-                    SearchCriteria searchCriteria = new SearchCriteria();
-                    searchCriteria.addMatchClause(MatchClause.createAttributeMatch(
+                    // Expectations for the replica samples
+                    SearchCriteria replicaSearchCriteria = new SearchCriteria();
+                    replicaSearchCriteria.addMatchClause(MatchClause.createAttributeMatch(
                             MatchClauseAttribute.CODE, sampleCode));
 
-                    ArrayList<Sample> samples = new ArrayList<Sample>();
+                    SearchCriteria gridSearchCriteria = new SearchCriteria();
+                    gridSearchCriteria.addMatchClause(MatchClause.createAttributeMatch(
+                            MatchClauseAttribute.CODE, "GRID-ID"));
+
+                    ArrayList<Sample> replicaSamples = new ArrayList<Sample>();
                     SampleInitializer sampInitializer = new SampleInitializer();
                     sampInitializer.setCode(sampleCode);
                     sampInitializer.setId((long) 1);
@@ -138,10 +143,10 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
                     sampInitializer.setPermId("PERM-ID");
                     sampInitializer.setSampleTypeCode("SAMPLE-TYPE");
                     sampInitializer.setSampleTypeId((long) 1);
-                    samples.add(new Sample(sampInitializer));
+                    replicaSamples.add(new Sample(sampInitializer));
 
-                    one(service).searchForSamples(SESSION_TOKEN, searchCriteria);
-                    will(returnValue(samples));
+                    one(service).searchForSamples(SESSION_TOKEN, replicaSearchCriteria);
+                    will(returnValue(replicaSamples));
 
                     ArrayList<DataSet> dataSets = new ArrayList<DataSet>();
                     DataSetInitializer dsInitializer = new DataSetInitializer();
@@ -162,8 +167,32 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
                     dsInitializer.setRegistrationDate(new GregorianCalendar(2010, 1, 1).getTime());
                     dataSets.add(new DataSet(dsInitializer));
 
-                    one(service).listDataSets(SESSION_TOKEN, samples);
+                    one(service).listDataSets(SESSION_TOKEN, replicaSamples);
                     will(returnValue(dataSets));
+
+                    // Expectations for the grid samples
+                    ArrayList<Sample> gridSamples = new ArrayList<Sample>();
+                    sampInitializer = new SampleInitializer();
+                    sampInitializer.setCode("GRID-ID");
+                    sampInitializer.setId((long) 2);
+                    sampInitializer.setIdentifier("SPACE/GRID-ID");
+                    sampInitializer.setPermId("GRID-PERM-ID");
+                    sampInitializer.setSampleTypeCode("GRID-SAMPLE-TYPE");
+                    sampInitializer.setSampleTypeId((long) 2);
+                    gridSamples.add(new Sample(sampInitializer));
+
+                    one(service).searchForSamples(SESSION_TOKEN, gridSearchCriteria);
+                    will(returnValue(gridSamples));
+
+                    ArrayList<DataSet> gridDataSets = new ArrayList<DataSet>();
+                    dsInitializer = new DataSetInitializer();
+                    dsInitializer.setCode("BUNDLE-METADATA");
+                    dsInitializer.setDataSetTypeCode(CinaConstants.METADATA_DATA_SET_TYPE_CODE);
+                    dsInitializer.setRegistrationDate(new GregorianCalendar(2010, 0, 1).getTime());
+                    gridDataSets.add(new DataSet(dsInitializer));
+                    one(service).listDataSets(SESSION_TOKEN, gridSamples);
+                    will(returnValue(gridDataSets));
+
                 }
             });
     }
@@ -188,6 +217,14 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
                 (metadataInfos.size() > 0) ? metadataInfos.toArray(new FileInfoDssDTO[metadataInfos
                         .size()]) : new FileInfoDssDTO[0];
 
+        ArrayList<FileInfoDssDTO> bundleMetadataInfos =
+                getFileInfosForPath(new File(parent, "Bundle"),
+                        new File(parent, "Bundle/original"), "BundleMetadata", "BundleMetadata");
+        final FileInfoDssDTO[] bundleMetadataInfosArray =
+                (bundleMetadataInfos.size() > 0) ? bundleMetadataInfos
+                        .toArray(new FileInfoDssDTO[bundleMetadataInfos.size()])
+                        : new FileInfoDssDTO[0];
+
         context.checking(new Expectations()
             {
                 {
@@ -209,6 +246,14 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
                             "Metadata/original/ReplicaMetadata/Metadata.txt"))));
 
                     // The command should not ask for the -METADATA-OLD dataset!
+
+                    one(dssComponent).getDataSet("BUNDLE-METADATA");
+                    will(returnValue(dataSetDss));
+                    one(dataSetDss).listFiles(startPath, true);
+                    will(returnValue(bundleMetadataInfosArray));
+                    one(dataSetDss).getFile(startPath + "BundleMetadata.xml");
+                    will(returnValue(new FileInputStream(new File(parent,
+                            "Bundle/original/BundleMetadata.xml"))));
                 }
             });
     }
@@ -284,9 +329,10 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
     {
         String[] bundleContents = outputFolder.list();
         Arrays.sort(bundleContents);
-        assertEquals(2, bundleContents.length);
+        assertEquals(3, bundleContents.length);
         assertEquals(BundleStructureConstants.METADATA_FOLDER_NAME, bundleContents[0]);
-        assertEquals(BundleStructureConstants.RAW_IMAGES_FOLDER_NAME, bundleContents[1]);
+        assertEquals(BundleStructureConstants.BUNDLE_METADATA_FILE_NAME, bundleContents[1]);
+        assertEquals(BundleStructureConstants.RAW_IMAGES_FOLDER_NAME, bundleContents[2]);
     }
 
     @Test
@@ -303,7 +349,7 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
         ResultCode exitCode =
                 command.execute(new String[]
                     { "-s", "url", "-u", USER_ID, "-p", PASSWORD, "-o", outputFolder.getPath(),
-                            "REPLICA-ID" });
+                            "GRID-ID", "REPLICA-ID" });
 
         assertEquals(ResultCode.OK, exitCode);
 
@@ -333,7 +379,7 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
         ResultCode exitCode =
                 command.execute(new String[]
                     { "-s", "url", "-u", USER_ID, "-p", PASSWORD, "-o", outputFolder.getPath(),
-                            "REPLICA-ID1", "REPLICA-ID2" });
+                            "GRID-ID", "REPLICA-ID1", "REPLICA-ID2" });
 
         assertEquals(ResultCode.OK, exitCode);
 
@@ -367,7 +413,7 @@ public class CommandGetReplicaTest extends AbstractFileSystemTestCase
         try
         {
             command.execute(new String[]
-                { "-s", "url", "-u", USER_ID, "-p", PASSWORD, "REPLICA-ID" });
+                { "-s", "url", "-u", USER_ID, "-p", PASSWORD, "GRID-ID", "REPLICA-ID" });
             fail("Command should throw an exception when run against an older version of the interface.");
         } catch (EnvironmentFailureException e)
         {