diff --git a/mpsd-software.py b/mpsd-software.py
index 1962a139a9a8230b209a0ddec36b806cfc74e396..438dccc4f1ec39abc6c1163ac6468d3dd9f7d8e6 100755
--- a/mpsd-software.py
+++ b/mpsd-software.py
@@ -15,6 +15,7 @@ import time
 from pathlib import Path
 from typing import List, Tuple, Union
 import re
+import shutil
 
 # If 'rich' is available ("pip install rich" or "apt-get install python3-rich"),
 # then use coloured output, otherwise proceed as before
@@ -979,13 +980,40 @@ def install_environment(
             )
 
 
-def remove_environment(release, package_sets, target_dir):
+def remove_environment(mpsd_release, root_dir, package_sets="NONE", force_remove=False):
     """Remove release from installation."""
     msg = (
-        f"Removing release {release} with package_sets {package_sets} from {target_dir}"
+        f"Removing release {mpsd_release}"
+        f" with package_sets {package_sets} from {root_dir}"
     )
-    logging.info(msg)
-    raise NotImplementedError(msg)
+    logging.warning(msg)
+    if package_sets == "NONE":
+        logging.warning(
+            "Please specify package_sets to remove, or 'ALL' to remove all toolchains"
+        )
+        sys.exit(1)
+    if "ALL" in package_sets:
+        # we need to remove the entire release folder
+        logging.warning(
+            f"Removing release {mpsd_release} from {root_dir}"
+            "do you want to continue? [y/n]"
+        )
+        if force_remove or input().lower() == "y":
+            folders_to_remove = os.listdir(root_dir / mpsd_release)
+            # skip logs folder
+            if "logs" in folders_to_remove:
+                folders_to_remove.remove("logs")
+            for folder in folders_to_remove:
+                shutil.rmtree(root_dir / mpsd_release / folder)
+                sys.exit(0)
+    for package_set in package_sets:
+        # we load the spack environment and remove the package_set
+        spack_env = ""
+        commands_to_execute = [
+            f"source {spack_env}",
+            f"spack env remove -y {package_set}",
+        ]
+        run(" && ".join(commands_to_execute), shell=True, check=True)
 
 
 def start_new_environment(release, from_release, target_dir):
@@ -1179,7 +1207,7 @@ def main():
 
     # Check the command and run related function
     if args.action == "remove":
-        remove_environment(args.release, args.package_set, root_dir)
+        remove_environment(args.release, root_dir, args.package_set)
     elif args.action == "start-new":
         start_new_environment(args.from_release, args.to_release, root_dir)
     elif args.action == "install":
diff --git a/test_mpsd-software.py b/test_mpsd-software.py
index fd0434adaf4f6b583d017cafdcde8f8c1202c687..ce31308efe3dfd5ed377aeb8c7837bc5122ffc5c 100644
--- a/test_mpsd-software.py
+++ b/test_mpsd-software.py
@@ -344,6 +344,14 @@ def test_install_environment_zlib():
     )
     assert len(build_log) == 4
 
+    # test that the removal now works
+    # mod.remove_environment(
+    #     mpsd_release=mpsd_release_to_test,
+    #     package_sets=[package_set_to_test],
+    #     root_dir=root_dir,
+    # )
+    # # ensure that the module files are removed
+
 
 def test_metadata_logging(tmp_path):
     """Test that metadata is logged and read correctly."""
@@ -446,32 +454,68 @@ def test_create_log_file_names():
     assert build_log_file_name is None
 
 
-def test_environment_status(tmp_path):
-    """Test that the environment status is correct."""
-    toolchain_map = mod.environment_status("fake-release", tmp_path)
-    assert toolchain_map is None
-    # create a fake environment
-    mpsd_release = "dev-23a"
-    test_microarch = mod.get_native_microarchitecture()
-    expected_toolchain_map = {test_microarch: ["foss2021a", "intel2021a"]}
+def create_fake_environment(tmp_path, mpsd_release, expected_toolchain_map=None):
+    """Create a fake environment with toolchains for testing."""
+    if not expected_toolchain_map:
+        test_microarch = mod.get_native_microarchitecture()
+        expected_toolchain_map = {test_microarch: ["foss2021a", "intel2021a"]}
+
     for microarch in expected_toolchain_map.keys():
         toolchain_lmod_folder = (
             tmp_path / mpsd_release / microarch / "lmod" / "Core" / "toolchains"
         )
-        toolchain_lmod_folder.mkdir(parents=True)
+        toolchain_lmod_folder.mkdir(parents=True, exist_ok=True)
         spack_folder = tmp_path / mpsd_release / microarch / "spack"
-        spack_folder.mkdir(parents=True)
+        spack_folder.mkdir(parents=True, exist_ok=True)
+        logs_folder = tmp_path / mpsd_release / microarch / "logs"
+        logs_folder.mkdir(parents=True, exist_ok=True)
         for toolchain in expected_toolchain_map[microarch]:
-            toolchain_file = toolchain_lmod_folder / f"{toolchain}.lua"
-            toolchain_file.touch()
+            toolchain_lua_file = toolchain_lmod_folder / f"{toolchain}.lua"
+            toolchain_lua_file.touch()
 
-    # check that the environment status is correct
+    return expected_toolchain_map
+
+
+def test_environment_status(tmp_path):
+    """Test that the environment status is correct."""
+    toolchain_map = mod.environment_status("fake-release", tmp_path)
+    assert toolchain_map is None
+    mpsd_release = "dev-23a"
+    expected_toolchain_map = create_fake_environment(tmp_path, mpsd_release)
+    # check that the environment statuxis is correct
     toolchain_map = mod.environment_status(mpsd_release, tmp_path)
     # convert each list to a set to ensure that the order doesn't matter
     for microarch in expected_toolchain_map.keys():
         assert set(toolchain_map[microarch]) == set(expected_toolchain_map[microarch])
 
 
+@pytest.mark.skip(reason="not implemented yet")
+def test_remove_environment(tmp_path):
+    """Test that the remove_environment works as expected."""
+    mpsd_release = "dev-23a"
+    # create a fake environment
+    create_fake_environment(tmp_path, mpsd_release)
+    # check that the environment status is correct
+    toolchain_map = mod.environment_status(mpsd_release, tmp_path)
+    assert toolchain_map is not None
+
+    # test removal  without arguments (should sys.exit(1))
+    create_fake_environment(tmp_path, mpsd_release)
+    with pytest.raises(SystemExit):
+        mod.remove_environment(mpsd_release, tmp_path, force_remove=True)
+
+    # test removal of the complete environment
+    mod.remove_environment(mpsd_release, tmp_path, ["ALL"], force_remove=True)
+    toolchain_map = mod.environment_status(mpsd_release, tmp_path)
+    assert toolchain_map is None
+    # ensure that logs folder remains
+    logs_folder = tmp_path / mpsd_release / "logs"
+    assert logs_folder.exists()
+
+    # test removal of a single toolchain
+    # done in test_install_environment_zlib
+
+
 def test_interface(tmp_path):
     """Test other things (not implemented yet)."""
     pass