diff --git a/operations/cleanup_script.py b/operations/cleanup_script.py
new file mode 100644
index 0000000000000000000000000000000000000000..b25742e822af5ce90a737910057e164a06f8c6e7
--- /dev/null
+++ b/operations/cleanup_script.py
@@ -0,0 +1,35 @@
+# ensure compatability with Spack v0.18.0
+try:
+ from spack.package_base import PackageStillNeededError
+except:
+ from spack.package import PackageStillNeededError
+
+needed = set()
+# keep packages that are part of an environment
+for e in spack.environment.all_environments():
+ needed.update(e.all_hashes())
+# also keep packages that provide compilers (and their dependencies)
+for c in spack.compilers.all_compiler_specs():
+ pkg_spec = spack.compilers.pkg_spec_for_compiler(c)
+ needed.update([dep.dag_hash() for pkg in spack.store.db.query(pkg_spec) for dep in pkg.traverse()])
+
+installed = {spec.dag_hash(): spec for spec in spack.store.db.query()}
+to_remove = set(installed) - needed
+
+# this will try to uninstall ANY package that is not part of an environment
+# including test dependencies
+# for a list of all the packages that will be uninstalled:
+print('The following packages will be uninstalled:')
+print('\n'.join(sorted([installed[h].short_spec+' ('+h+')' for h in to_remove])))
+
+# iteratively uninstall packages with no dependents
+while to_remove:
+ # print('New iteration')
+ for hash in to_remove.copy():
+ spec = installed[hash]
+ try:
+ spec.package.do_uninstall()
+ to_remove.discard(hash)
+ except PackageStillNeededError:
+ pass
+ # print('Not ready to remove', spec.short_spec, 'in this iteration')