diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index e6db237063252bdc2359b1ac512134aa2b0080ae..355c6b984e70f8c57fd3dbdd7dd63e7d5ecf2919 100644
--- a/nomad/metainfo/metainfo.py
+++ b/nomad/metainfo/metainfo.py
@@ -1782,6 +1782,47 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
             else:
                 self.m_set(prop, value)
 
+    def m_setdefault(self, path):
+        '''Given a root section and a path, looks if a unique section can be found
+        under that path and returns it. Will create the sections along the path if
+        no instances are found.
+        '''
+        parts = path.split(".")
+        root = self
+        for part in parts:
+            error = AttributeError(f'Could not find section definition for path "{part}"')
+            try:
+                child = getattr(root, part)
+            except Exception as e:
+                raise error from e
+            sub_sections = root.m_def.all_sub_sections
+            try:
+                child_section = sub_sections[part]
+            except Exception as e:
+                raise error from e
+            repeats = child_section.repeats
+
+            # See if child exists. Repeating subsection is accepted only if
+            # there is one instance.
+            if child:
+                if repeats:
+                    if len(child) != 1:
+                        raise ValueError(f'Cannot resolve "{part}" as several instances were found')
+                    root = child[0]
+                else:
+                    root = child
+            # Otherwise create child
+            else:
+                child_cls = child_section.sub_section.section_cls
+                child_instance = child_cls()
+                if repeats:
+                    root.m_add_sub_section(child_section, child_instance)
+                else:
+                    setattr(root, part, child_instance)
+                root = child_instance
+
+        return root
+
     def m_as(self, section_cls: Type[MSectionBound]) -> MSectionBound:
         ''' 'Casts' this section to the given extending sections. '''
         return cast(MSectionBound, self)
diff --git a/tests/metainfo/test_metainfo.py b/tests/metainfo/test_metainfo.py
index 55055b6398250adaddea83a329130502354e2ad7..9a610b26bc461224852899e2830c66e3556eba31 100644
--- a/tests/metainfo/test_metainfo.py
+++ b/tests/metainfo/test_metainfo.py
@@ -137,7 +137,7 @@ class TestM2:
 
     def test_unset_sub_section(self):
         run = Run()
-        assert run.systems == []
+        assert run.systems == []  # pylint: disable=use-implicit-booleaness-not-comparison
         assert run.parsing is None
 
     def test_properties(self):
@@ -426,6 +426,14 @@ class TestM2:
         assert 'this_does_not_exist_in_metainfo' not in serialized
 
 
+existing_repeating = Run()
+existing_repeating.systems.append(System())
+existing_nonrepeating = Run()
+existing_nonrepeating.parsing = Parsing()
+existing_multiple = Run()
+existing_multiple.systems = [System(), System()]
+
+
 class TestM1:
     ''' Test for meta-info instances. '''
 
@@ -488,7 +496,7 @@ class TestM1:
 
     def test_sub_section_lst(self):
         run = Run()
-        assert run.systems == []
+        assert run.systems == []  # pylint: disable=use-implicit-booleaness-not-comparison
         run.systems.append(System())
 
         assert len(run.systems) == 1
@@ -817,6 +825,24 @@ class TestM1:
         assert parent.single_sub_section is not None
         assert len(parent.many_sub_section) == 2
 
+    @pytest.mark.parametrize('root,path,exception', [
+        pytest.param(Run(), 'parsing', None, id="non-existing non-repeating section"),
+        pytest.param(Run(), 'systems', None, id="non-existing repeating section"),
+        pytest.param(existing_nonrepeating, 'parsing', None, id="existing non-repeating section"),
+        pytest.param(existing_repeating, 'systems', None, id="existing repeating section"),
+        pytest.param(Run(), 'code_name', 'Could not find section definition for path "code_name"', id="cannot target quantity"),
+        pytest.param(Run(), 'missing', 'Could not find section definition for path "missing"', id="invalid path"),
+        pytest.param(existing_multiple, 'systems', 'Cannot resolve "systems" as several instances were found', id="ambiguous path"),
+    ])
+    def test_m_setdefault(self, root, path, exception):
+        if not exception:
+            system = root.m_setdefault(path)
+            assert system
+        else:
+            with pytest.raises(Exception) as exc_info:
+                system = root.m_setdefault(path)
+            assert exception in str(exc_info.value)
+
 
 class TestEnvironment: