diff --git a/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py b/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py
new file mode 100644
index 0000000000000000000000000000000000000000..12166ae11b5d1a7945fe43c7ad0ea04734a2f71f
--- /dev/null
+++ b/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py
@@ -0,0 +1,175 @@
+"""
+This command will be run by an ansible script.
+"""
+
+import os
+import json
+import fnmatch
+import logging
+
+from provider.oauth2.models import Client
+from provider.constants import CONFIDENTIAL
+from edx_oauth2_provider.models import TrustedClient
+from django.contrib.auth.models import User
+from django.contrib.sites.models import Site
+from django.core.management.base import BaseCommand
+
+from openedx.core.djangoapps.theming.models import SiteTheme
+from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
+
+LOG = logging.getLogger(__name__)
+
+
+class Command(BaseCommand):
+    """
+    Command to create the site, site themes, configuration and oauth2 clients for all WL-sites.
+
+    Example:
+    ./manage.py lms create_sites_and_configurations --dns-name whitelabel --theme-path /edx/src/edx-themes/edx-platform
+    """
+    dns_name = None
+    theme_path = None
+    ecommerce_user = None
+    discovery_user = None
+
+    def add_arguments(self, parser):
+        """
+        Add arguments to the command parser.
+        """
+        parser.add_argument(
+            "--dns-name",
+            type=str,
+            help="Enter DNS name of sandbox.",
+            required=True
+        )
+
+        parser.add_argument(
+            "--theme-path",
+            type=str,
+            help="Enter theme directory path",
+            required=True
+        )
+
+    def _create_oauth2_client(self, url, site_name, is_discovery=True):
+        """
+        Creates the oauth2 client and add it in trusted clients.
+        """
+
+        client, _ = Client.objects.get_or_create(
+            redirect_uri="{url}complete/edx-oidc/".format(url=url),
+            defaults={
+                "user": self.discovery_user if is_discovery else self.ecommerce_user,
+                "name": "{site_name}_{client_type}_client".format(
+                    site_name=site_name,
+                    client_type="discovery" if is_discovery else "ecommerce",
+                ),
+                "url": url,
+                "client_id": "{client_type}-key-{site_name}".format(
+                    client_type="discovery" if is_discovery else "ecommerce",
+                    site_name=site_name
+                ),
+                "client_secret": "{client_type}-secret-{dns_name}".format(
+                    client_type="discovery" if is_discovery else "ecommerce",
+                    dns_name=self.dns_name
+                ),
+                "client_type": CONFIDENTIAL,
+                "logout_uri": "{url}logout/".format(url=url)
+            }
+        )
+        LOG.info("Adding {client} oauth2 client as trusted client".format(client=client.name))
+        TrustedClient.objects.get_or_create(client=client)
+
+    def _create_sites(self, site_domain, theme_dir_name, site_configuration):
+        """
+        Create Sites, SiteThemes and SiteConfigurations
+        """
+        site, created = Site.objects.get_or_create(
+            domain=site_domain,
+            defaults={"name": theme_dir_name}
+        )
+        if created:
+            LOG.info("Creating '{site_name}' SiteTheme".format(site_name=site_domain))
+            SiteTheme.objects.create(site=site, theme_dir_name=theme_dir_name)
+
+            LOG.info("Creating '{site_name}' SiteConfiguration".format(site_name=site_domain))
+            SiteConfiguration.objects.create(site=site, values=site_configuration, enabled=True)
+        else:
+            LOG.info("'{site_domain}' site already exists".format(site_domain=site_domain))
+
+    def find(self, pattern, path):
+        """
+        Matched the given pattern in given path and returns the list of matching files
+        """
+        result = []
+        for root, dirs, files in os.walk(path):  # pylint: disable=unused-variable
+            for name in files:
+                if fnmatch.fnmatch(name, pattern):
+                    result.append(os.path.join(root, name))
+        return result
+
+    def _get_sites_data(self):
+        """
+        Reads the json files from theme directory and returns the site data in JSON format.
+        "site_a":{
+            "theme_dir_name": "site_a.edu.au"
+            "configuration": {
+                "key1": "value1",
+                "key2": "value2"
+            }
+        }
+        """
+        site_data = {}
+        for config_file in self.find('sandbox_configuration.json', self.theme_path):
+            LOG.info("Reading file from {file}".format(file=config_file))
+            configuration_data = json.loads(
+                json.dumps(
+                    json.load(
+                        open(config_file)
+                    )
+                ).replace("{dns_name}", self.dns_name)
+            )['lms_configuration']
+
+            site_data[configuration_data['sandbox_name']] = {
+                "site_domain": configuration_data['site_domain'],
+                "theme_dir_name": configuration_data['theme_dir_name'],
+                "configuration": configuration_data['configuration']
+            }
+        return site_data
+
+    def get_or_create_service_user(self, username):
+        """
+        Creates the service user for ecommerce and discovery.
+        """
+        return User.objects.get_or_create(
+            username=username,
+            defaults={
+                "is_staff": True,
+                "is_superuser": True
+            }
+        )
+
+    def handle(self, *args, **options):
+
+        self.theme_path = options['theme_path']
+        self.dns_name = options['dns_name']
+
+        self.discovery_user, _ = self.get_or_create_service_user("lms_catalog_service_user")
+        self.ecommerce_user, _ = self.get_or_create_service_user("ecommerce_worker")
+
+        all_sites = self._get_sites_data()
+
+        # creating Sites, SiteThemes, SiteConfigurations and oauth2 clients
+        for site_name, site_data in all_sites.items():
+            site_domain = site_data['site_domain']
+
+            discovery_url = "https://discovery-{site_domain}/".format(site_domain=site_domain)
+            ecommerce_url = "https://ecommerce-{site_domain}/".format(site_domain=site_domain)
+
+            LOG.info("Creating '{site_name}' Site".format(site_name=site_name))
+            self._create_sites(site_domain, site_data['theme_dir_name'], site_data['configuration'])
+
+            LOG.info("Creating discovery oauth2 client for '{site_name}' site".format(site_name=site_name))
+            self._create_oauth2_client(discovery_url, site_name, is_discovery=True)
+
+            LOG.info("Creating ecommerce oauth2 client for '{site_name}' site".format(site_name=site_name))
+            self._create_oauth2_client(ecommerce_url, site_name, is_discovery=False)
diff --git a/openedx/core/djangoapps/theming/management/commands/tests/__init__.py b/openedx/core/djangoapps/theming/management/commands/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/openedx/core/djangoapps/theming/management/commands/tests/test_create_sites_and_configurations.py b/openedx/core/djangoapps/theming/management/commands/tests/test_create_sites_and_configurations.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6e712856c2eee419252cbe28abda2981233b9e4
--- /dev/null
+++ b/openedx/core/djangoapps/theming/management/commands/tests/test_create_sites_and_configurations.py
@@ -0,0 +1,156 @@
+"""
+Test cases for create_sites_and_configurations command.
+"""
+
+import mock
+
+from django.test import TestCase
+from django.contrib.auth.models import User
+from django.contrib.sites.models import Site
+from django.core.management import call_command, CommandError
+
+from provider.oauth2.models import Client
+from edx_oauth2_provider.models import TrustedClient
+from openedx.core.djangoapps.theming.models import SiteTheme
+
+SITES = ['site_a', 'site_b']
+
+
+def _generate_site_config(dns_name, site_domain):
+    """ Generate the site configuration for a given site """
+    return {
+        "lms_url": "{domain}-{dns_name}.sandbox.edx.org".format(domain=site_domain, dns_name=dns_name),
+        "platform_name": "{domain}-{dns_name}".format(domain=site_domain, dns_name=dns_name)
+    }
+
+
+def _get_sites(dns_name):
+    """ Creates the mocked data for management command """
+    sites = {}
+    for site in SITES:
+        sites.update({
+            site: {
+                "theme_dir_name": "{}_dir_name".format(site),
+                "configuration": _generate_site_config(dns_name, site),
+                "site_domain": "{site}-{dns_name}.sandbox.edx.org".format(site=site, dns_name=dns_name)
+            }
+        })
+    return sites
+
+
+class TestCreateSiteAndConfiguration(TestCase):
+    """ Test the create_site_and_configuration command """
+    def setUp(self):
+        super(TestCreateSiteAndConfiguration, self).setUp()
+
+        self.dns_name = "dummy_dns"
+        self.theme_path = "/dummyA/dummyB/"
+
+    def _assert_sites_are_valid(self):
+        """
+        Checks that data of all sites is valid
+        """
+        sites = Site.objects.all()
+        # there is an extra default site.
+        self.assertEqual(len(sites), len(SITES) + 1)
+        for site in sites:
+            if site.name in SITES:
+                site_theme = SiteTheme.objects.get(site=site)
+
+                self.assertEqual(
+                    site_theme.theme_dir_name,
+                    "{}_dir_name".format(site.name)
+                )
+
+                self.assertDictEqual(
+                    dict(site.configuration.values),
+                    _generate_site_config(self.dns_name, site.name)
+                )
+
+    def _assert_ecommerce_clients_are_valid(self):
+        """
+        Checks that all ecommerce clients are valid
+        """
+        service_user = User.objects.filter(username="ecommerce_worker")
+        self.assertEqual(len(service_user), 1)
+        self.assertTrue(service_user[0].is_staff)
+
+        clients = Client.objects.filter(user=service_user)
+        self.assertEqual(len(clients), len(SITES))
+
+        for client in clients:
+            self.assertEqual(client.user.username, service_user[0].username)
+            site_name = client.name[:6]
+            ecommerce_url = "https://ecommerce-{site_name}-{dns_name}.sandbox.edx.org/".format(
+                site_name=site_name,
+                dns_name=self.dns_name
+            )
+            self.assertEqual(client.url, ecommerce_url)
+            self.assertEqual(
+                client.redirect_uri,
+                "{ecommerce_url}complete/edx-oidc/".format(ecommerce_url=ecommerce_url)
+            )
+            self.assertEqual(
+                len(TrustedClient.objects.filter(client=client)),
+                1
+            )
+
+    def _assert_discovery_clients_are_valid(self):
+        """
+        Checks that all discovery clients are valid
+        """
+        service_user = User.objects.filter(username="lms_catalog_service_user")
+        self.assertEqual(len(service_user), 1)
+        self.assertTrue(service_user[0].is_staff)
+
+        clients = Client.objects.filter(user=service_user)
+        self.assertEqual(len(clients), len(SITES))
+
+        for client in clients:
+            self.assertEqual(client.user.username, service_user[0].username)
+            site_name = client.name[:6]
+            discovery_url = "https://discovery-{site_name}-{dns_name}.sandbox.edx.org/".format(
+                site_name=site_name,
+                dns_name=self.dns_name
+            )
+            self.assertEqual(client.url, discovery_url)
+            self.assertEqual(
+                client.redirect_uri,
+                "{discovery_url}complete/edx-oidc/".format(discovery_url=discovery_url)
+            )
+            self.assertEqual(
+                len(TrustedClient.objects.filter(client=client)),
+                1
+            )
+
+    def test_without_dns(self):
+        """ Test the command without dns_name """
+        with self.assertRaises(CommandError):
+            call_command(
+                "create_sites_and_configurations"
+            )
+
+    @mock.patch(
+        'openedx.core.djangoapps.theming.management.commands.create_sites_and_configurations.Command._get_sites_data'
+    )
+    def test_with_dns(self, mock_get_sites):
+        """ Test the command with dns_name """
+        mock_get_sites.return_value = _get_sites(self.dns_name)
+        call_command(
+            "create_sites_and_configurations",
+            "--dns-name", self.dns_name,
+            "--theme-path", self.theme_path
+        )
+        self._assert_sites_are_valid()
+        self._assert_discovery_clients_are_valid()
+        self._assert_ecommerce_clients_are_valid()
+
+        call_command(
+            "create_sites_and_configurations",
+            "--dns-name", self.dns_name,
+            "--theme-path", self.theme_path
+        )
+        # if we run command with same dns then it will not duplicates the sites and oauth2 clients.
+        self._assert_sites_are_valid()
+        self._assert_discovery_clients_are_valid()
+        self._assert_ecommerce_clients_are_valid()