diff --git a/Framework/API/inc/MantidAPI/WorkspaceGroup.h b/Framework/API/inc/MantidAPI/WorkspaceGroup.h
index 057f4035f52281b6fcfd8eb9ffa7ffabce5ed371..2d118a1b691de8fda18b48205c0b38ebc2982b10 100644
--- a/Framework/API/inc/MantidAPI/WorkspaceGroup.h
+++ b/Framework/API/inc/MantidAPI/WorkspaceGroup.h
@@ -67,7 +67,7 @@ public:
   /// Sort the internal data structure according to member name
   void sortMembersByName();
   /// Adds a workspace to the group.
-  void addWorkspace(Workspace_sptr workspace);
+  void addWorkspace(const Workspace_sptr &workspace);
   /// Return the number of entries within the group
   int getNumberOfEntries() const { return static_cast<int>(this->size()); }
   /// Return the size of the group, so it is more like a container
@@ -75,7 +75,7 @@ public:
   /// Return the ith workspace
   Workspace_sptr getItem(const size_t index) const;
   /// Return the workspace by name
-  Workspace_sptr getItem(const std::string wsName) const;
+  Workspace_sptr getItem(const std::string &wsName) const;
   /// Return all workspaces in the group as one call for thread safety
   std::vector<Workspace_sptr> getAllItems() const;
   /// Remove a workspace from the group
diff --git a/Framework/API/src/WorkspaceGroup.cpp b/Framework/API/src/WorkspaceGroup.cpp
index 0bdfe8d71a9d215e3f69c863c6516e4be4e84237..54b99597b2ff58793784210e4d3ad0684d49079a 100644
--- a/Framework/API/src/WorkspaceGroup.cpp
+++ b/Framework/API/src/WorkspaceGroup.cpp
@@ -103,7 +103,7 @@ void WorkspaceGroup::sortMembersByName() {
  * @param workspace :: A shared pointer to a workspace to add. If the workspace
  * already exists give a warning.
  */
-void WorkspaceGroup::addWorkspace(Workspace_sptr workspace) {
+void WorkspaceGroup::addWorkspace(const Workspace_sptr &workspace) {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   // check it's not there already
   auto it = std::find(m_workspaces.begin(), m_workspaces.end(), workspace);
@@ -111,7 +111,6 @@ void WorkspaceGroup::addWorkspace(Workspace_sptr workspace) {
     m_workspaces.push_back(workspace);
   } else {
     g_log.warning() << "Workspace already exists in a WorkspaceGroup\n";
-    ;
   }
 }
 
@@ -157,6 +156,7 @@ void WorkspaceGroup::reportMembers(std::set<Workspace_sptr> &memberList) const {
 std::vector<std::string> WorkspaceGroup::getNames() const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   std::vector<std::string> out;
+  out.reserve(m_workspaces.size());
   for (const auto &workspace : m_workspaces) {
     out.push_back(workspace->getName());
   }
@@ -185,11 +185,12 @@ Workspace_sptr WorkspaceGroup::getItem(const size_t index) const {
  * @throws an out_of_range error if the workspace's name not contained in the
  * group's list of workspace names
  */
-Workspace_sptr WorkspaceGroup::getItem(const std::string wsName) const {
+Workspace_sptr WorkspaceGroup::getItem(const std::string &wsName) const {
   std::lock_guard<std::recursive_mutex> _lock(m_mutex);
   for (const auto &workspace : m_workspaces) {
-    if (workspace->getName() == wsName)
+    if (workspace->getName() == wsName) {
       return workspace;
+    }
   }
   throw std::out_of_range("Workspace " + wsName +
                           " not contained in the group");
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h b/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h
index a01ee0d8441eec7f1bf73bcf50c563a06343806d..347a7d7b8232555c8cbc7f28fe4cef62dca1eab7 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/GroupWorkspaces.h
@@ -57,6 +57,8 @@ public:
     return "Transforms\\Grouping;Utility\\Workspaces";
   }
 
+  std::map<std::string, std::string> validateInputs() override;
+
 protected:
   Parallel::ExecutionMode getParallelExecutionMode(
       const std::map<std::string, Parallel::StorageMode> &storageModes)
@@ -72,7 +74,8 @@ private:
   /// Add a workspace to the new group, checking for a WorkspaceGroup and
   /// unrolling it
   void addToGroup(const API::Workspace_sptr &workspace);
-
+  /// Use a glob pattern to select workspaces in the ADS
+  void addToGroup(const std::string &globExpression);
   /// A pointer to the new group
   API::WorkspaceGroup_sptr m_group;
 };
diff --git a/Framework/Algorithms/src/GroupWorkspaces.cpp b/Framework/Algorithms/src/GroupWorkspaces.cpp
index 6936b02aaf8ffb201e56f6beee4463e81746a1b7..a084df52cf583c775b5993147f1969213aca2431 100644
--- a/Framework/Algorithms/src/GroupWorkspaces.cpp
+++ b/Framework/Algorithms/src/GroupWorkspaces.cpp
@@ -5,6 +5,8 @@
 #include "MantidKernel/ArrayProperty.h"
 #include "MantidParallel/Communicator.h"
 
+#include "Poco/Glob.h"
+
 namespace Mantid {
 namespace Algorithms {
 
@@ -16,9 +18,13 @@ using namespace Kernel;
 /// Initialisation method
 void GroupWorkspaces::init() {
 
-  declareProperty(Kernel::make_unique<ArrayProperty<std::string>>(
-                      "InputWorkspaces", boost::make_shared<ADSValidator>()),
-                  "Names of the Input Workspaces to Group");
+  declareProperty(
+      Kernel::make_unique<ArrayProperty<std::string>>(
+          "InputWorkspaces", boost::make_shared<ADSValidator>(true, true)),
+      "Names of the Input Workspaces to Group");
+  declareProperty(
+      std::make_unique<PropertyWithValue<std::string>>("GlobExpression", ""),
+      "Add all Workspaces that match Glob expression to Group");
   declareProperty(
       make_unique<WorkspaceProperty<WorkspaceGroup>>("OutputWorkspace", "",
                                                      Direction::Output),
@@ -32,15 +38,79 @@ void GroupWorkspaces::exec() {
   const std::vector<std::string> inputWorkspaces =
       getProperty("InputWorkspaces");
 
+  const std::string globExpression = getProperty("GlobExpression");
+
   // Clear WorkspaceGroup in case algorithm instance is reused.
   m_group = nullptr;
-  addToGroup(inputWorkspaces);
 
+  if (!inputWorkspaces.empty())
+    addToGroup(inputWorkspaces);
+  if (!globExpression.empty())
+    addToGroup(globExpression);
+  if ((m_group == nullptr) || m_group->isEmpty())
+    throw std::invalid_argument(
+        "Glob pattern " + globExpression +
+        " does not match any workspace names in the ADS.");
   setProperty("OutputWorkspace", m_group);
   auto &notifier = API::AnalysisDataService::Instance().notificationCenter;
   notifier.postNotification(new WorkspacesGroupedNotification(inputWorkspaces));
 }
 
+std::map<std::string, std::string> GroupWorkspaces::validateInputs() {
+  std::map<std::string, std::string> results;
+  const std::vector<std::string> inputWorkspaces =
+      getProperty("InputWorkspaces");
+  std::string globExpression = getProperty("GlobExpression");
+
+  for (auto it = globExpression.begin(); it != globExpression.end(); ++it) {
+    if (*it == '\\') {
+      it = globExpression.erase(it, it + 2);
+    }
+  }
+
+  if (inputWorkspaces.empty() && globExpression.empty()) {
+    results["InputWorkspaces"] =
+        "No InputWorkspace names specified. Rerun with a list of workspaces "
+        "names or a glob expression";
+    return results;
+  }
+
+  // ADSValidator already checks names in inputWorkspaces
+
+  if (!globExpression.empty()) {
+    // This is only a sanity check. If may fail to detect subtle errors in
+    // complex expressions.
+    if (globExpression.find_first_of("*?[]") == std::string::npos) {
+      results["GlobExpression"] = "Expression is expected to contain one or "
+                                  "more of the following characters: *?[";
+      return results;
+    }
+    if (std::count(globExpression.cbegin(), globExpression.cend(), '[') !=
+        std::count(globExpression.cbegin(), globExpression.cend(), ']')) {
+      results["GlobExpression"] = "Expression has a mismatched number of []";
+      return results;
+    }
+  }
+  return results;
+}
+
+/**
+ * Add a list of names to the new group
+ * @param globExpression glob pattern for selecting names from the ADS
+ */
+void GroupWorkspaces::addToGroup(const std::string &globExpression) {
+
+  Poco::Glob glob(globExpression);
+
+  AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
+  const auto names = ads.topLevelItems();
+  for (const auto &name : names) {
+    if (glob.match(name.first)) {
+      addToGroup(name.second);
+    }
+  }
+}
+
 /**
  * Add a list of names to the new group
  * @param names The list of names to add from the ADS
@@ -68,9 +138,10 @@ void GroupWorkspaces::addToGroup(const API::Workspace_sptr &workspace) {
     if (!m_group)
       m_group = boost::make_shared<WorkspaceGroup>(workspace->storageMode());
     else if (communicator().size() != 1 &&
-             m_group->storageMode() != workspace->storageMode())
+             m_group->storageMode() != workspace->storageMode()) {
       throw std::runtime_error(
           "WorkspaceGroup with mixed Parallel::Storage mode is not supported.");
+    }
     m_group->addWorkspace(workspace);
   }
 }
diff --git a/Framework/Algorithms/test/GroupWorkspacesTest.h b/Framework/Algorithms/test/GroupWorkspacesTest.h
index 4d92f2c6bda2b9f2f985cfaa5be94f58c4dac156..0eba9dbd7cea9b945314df5c15f0d049fec7941a 100644
--- a/Framework/Algorithms/test/GroupWorkspacesTest.h
+++ b/Framework/Algorithms/test/GroupWorkspacesTest.h
@@ -7,6 +7,8 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include <cxxtest/TestSuite.h>
 
+#include <algorithm>
+
 class GroupWorkspacesTest : public CxxTest::TestSuite {
 public:
   // This pair of boilerplate methods prevent the suite being created statically
@@ -39,14 +41,17 @@ public:
     TS_ASSERT(alg.isInitialized());
 
     const auto &props = alg.getProperties();
-    TS_ASSERT_EQUALS(props.size(), 2);
+    TS_ASSERT_EQUALS(props.size(), 3);
 
     TS_ASSERT_EQUALS(props[0]->name(), "InputWorkspaces");
     TS_ASSERT(props[0]->isDefault());
 
-    TS_ASSERT_EQUALS(props[1]->name(), "OutputWorkspace");
+    TS_ASSERT_EQUALS(props[1]->name(), "GlobExpression");
     TS_ASSERT(props[1]->isDefault());
-    TS_ASSERT(dynamic_cast<WorkspaceProperty<WorkspaceGroup> *>(props[1]));
+
+    TS_ASSERT_EQUALS(props[2]->name(), "OutputWorkspace");
+    TS_ASSERT(props[2]->isDefault());
+    TS_ASSERT(dynamic_cast<WorkspaceProperty<WorkspaceGroup> *>(props[2]));
   }
 
   void test_Exec_With_Single_Workspace_Succeeds() {
@@ -171,6 +176,123 @@ public:
     removeFromADS(groupName, inputs);
   }
 
+  void test_GlobExpression_Star_Succeeds() {
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_20"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_*"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm(glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, inputs);
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_Question_Succeeds() {
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_20"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_?"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm(glob, groupName));
+
+    std::vector<std::string> group_members(inputs.begin(), inputs.begin() + 2);
+
+    checkGroupExistsWithMembers(groupName, group_members);
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_Brackets_Succeeds() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[0-2]"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm(glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, {inputs[0], inputs[1]});
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_Brackets_Succeeds_2() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[0-3]"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm(glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, inputs);
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_List_And_Glob_Succeeds() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[0-2]"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm({inputs[2]}, glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, inputs);
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_List_And_Glob_Succeeds_2() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[0-3]"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm({inputs[0]}, glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, inputs);
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_EscapedCharacter_Succeeds() {
+    std::vector<std::string> inputs{"test_name_1", "test_?_2", "test_n_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_\\?_?"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm(glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, {inputs[1]});
+
+    removeFromADS(groupName, inputs);
+  }
+
+  void test_GlobExpression_EscapedCharacter_Succeeds_2() {
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[2-3]"};
+    std::string groupName{"test_name_output"};
+
+    TS_ASSERT_THROWS_NOTHING(runAlgorithm({inputs[0]}, glob, groupName));
+
+    checkGroupExistsWithMembers(groupName, inputs);
+
+    removeFromADS(groupName, inputs);
+  }
+
   //========================= Failure Cases
   //===========================================
 
@@ -195,6 +317,57 @@ public:
     removeFromADS("", inputs);
   }
 
+  void test_GlobExpression_Mismatched_Brackets_Fails() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[1-3]]"};
+    std::string groupName{"test_name_output"};
+
+    runAlgorithm(glob, groupName, true);
+
+    TS_ASSERT_EQUALS(
+        false,
+        Mantid::API::AnalysisDataService::Instance().doesExist(groupName));
+
+    removeFromADS("", inputs);
+  }
+
+  void test_GlobExpression_Fails() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_1"};
+    std::string groupName{"test_name_output"};
+
+    runAlgorithm(glob, groupName, true);
+
+    TS_ASSERT_EQUALS(
+        false,
+        Mantid::API::AnalysisDataService::Instance().doesExist(groupName));
+
+    removeFromADS("", inputs);
+  }
+
+  void test_GlobExpression_Empty_Output_Fails() {
+
+    std::vector<std::string> inputs{"test_name_1", "test_name_2",
+                                    "test_name_3"};
+    addTestMatrixWorkspacesToADS(inputs);
+    std::string glob{"test_name_[!1-3]"};
+    std::string groupName{"test_name_output"};
+
+    runAlgorithm(glob, groupName, true);
+
+    TS_ASSERT_EQUALS(
+        false,
+        Mantid::API::AnalysisDataService::Instance().doesExist(groupName));
+
+    removeFromADS("", inputs);
+  }
+
 private:
   void addTestMatrixWorkspacesToADS(const std::vector<std::string> &inputs) {
     for (const auto &input : inputs) {
@@ -236,9 +409,43 @@ private:
     }
   }
 
-  void
-  checkGroupExistsWithMembers(const std::string &groupName,
-                              const std::vector<std::string> &expectedMembers) {
+  void runAlgorithm(const std::string &globExpression,
+                    const std::string &outputWorkspace,
+                    bool errorExpected = false) {
+    Mantid::Algorithms::GroupWorkspaces alg;
+    alg.initialize();
+    alg.setRethrows(true);
+
+    if (errorExpected) {
+      alg.setProperty("GlobExpression", globExpression);
+      alg.setProperty("OutputWorkspace", outputWorkspace);
+      TS_ASSERT_THROWS_ANYTHING(alg.execute());
+    } else {
+      TS_ASSERT_THROWS_NOTHING(
+          alg.setProperty("GlobExpression", globExpression));
+      TS_ASSERT_THROWS_NOTHING(
+          alg.setProperty("OutputWorkspace", outputWorkspace));
+      alg.execute();
+      TS_ASSERT(alg.isExecuted());
+    }
+  }
+
+  void runAlgorithm(const std::vector<std::string> &inputs,
+                    const std::string &globExpression,
+                    const std::string &outputWorkspace) {
+    Mantid::Algorithms::GroupWorkspaces alg;
+    alg.initialize();
+    alg.setRethrows(true);
+
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspaces", inputs));
+    TS_ASSERT_THROWS_NOTHING(alg.setProperty("GlobExpression", globExpression));
+    TS_ASSERT_THROWS_NOTHING(
+        alg.setProperty("OutputWorkspace", outputWorkspace));
+    alg.execute();
+    TS_ASSERT(alg.isExecuted());
+  }
+  void checkGroupExistsWithMembers(const std::string &groupName,
+                                   std::vector<std::string> expectedMembers) {
     using namespace Mantid::API;
 
     auto &ads = AnalysisDataService::Instance();
@@ -248,6 +455,9 @@ private:
     std::vector<std::string> grpVec = result->getNames();
     TS_ASSERT_EQUALS(expectedMembers.size(), grpVec.size());
 
+    std::sort(expectedMembers.begin(), expectedMembers.end());
+    std::sort(grpVec.begin(), grpVec.end());
+
     if (expectedMembers.size() == grpVec.size()) {
       for (size_t i = 0; i < expectedMembers.size(); ++i) {
         TS_ASSERT_EQUALS(expectedMembers[i], grpVec[i]);
diff --git a/docs/source/algorithms/GroupWorkspaces-v1.rst b/docs/source/algorithms/GroupWorkspaces-v1.rst
index 28ea510b27ea25fa4c0d04e718df638fd0b9c169..ac1d5f14a50eeae216ae02ca0b3c6ad85b4fcc82 100644
--- a/docs/source/algorithms/GroupWorkspaces-v1.rst
+++ b/docs/source/algorithms/GroupWorkspaces-v1.rst
@@ -10,7 +10,8 @@ Description
 -----------
 
 This algorithm takes two or more workspaces as input and creates an
-output workspace group.
+output workspace group. A list of workspaces and a glob pattern may
+be specified together.
 
 Usage
 -----
@@ -30,6 +31,15 @@ Usage
   print('Its first  item is {}'.format(group.getItem(0)))
   print('Its second item is {}'.format(group.getItem(1)))
 
+  wrkspc1 = CreateSampleWorkspace()
+  wrkspc2 = CreateSampleWorkspace()
+  anotherGroup = GroupWorkspaces(GlobExpression='wrkspc?')
+
+  # Check the result
+  print('It has {} entries'.format(anotherGroup.getNumberOfEntries()))
+  print('Its first  item is {}'.format(anotherGroup.getItem(0)))
+  print('Its second item is {}'.format(anotherGroup.getItem(1)))
+
 Output
 ######
 
@@ -39,6 +49,9 @@ Output
   It has 2 entries
   Its first  item is ws1
   Its second item is ws2
+  It has 2 entries
+  Its first  item is wrkspc1
+  Its second item is wrkspc2
 
 .. categories::