diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..1ff0c423042b46cb1d617b81efb715defbe8054d
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain
diff --git a/.gitignore b/.gitignore
index d2df1da5b5077d597142e85e19812ba900a4e81c..7cdf465cdfbcae98eaca0ef127878a9b08936ec9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,7 @@ bld/
 [Bb]in/
 [Oo]bj/
 [Ll]og/
+[Pp]roperties/
 
 # Visual Studio 2015 cache/options directory
 .vs/
@@ -268,3 +269,6 @@ __pycache__/
 tools/*
 !tools/packages.config
 dist/
+
+# Dotnet Tool Manifest
+.config/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d9d53b4a2f06b61308d3e57b939120710c5773b6..9c1ce374e77aab64b52c0a2d67a793e82ca4e344 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,71 +1,49 @@
+include:
+  - project: coscine/tools/gitlab-ci-templates
+    file: 
+      - /dotnet.yml
+
 stages:
-  - test
-  - release
-  - releasetrigger
-  - schedule
+  - build
+  - publish
 
-cake:Test:
-  stage: test
-  script:
-    - PowerShell .\build.ps1 --Target Test --Configuration Debug
-  variables:
-    GIT_STRATEGY: clone
-  artifacts:
-    reports:
-      junit: "./Artifacts/TestResults.xml"
-    paths:
-      - "./Artifacts/*"
-  except:
-    - master
-    - tags
 
-cake:Release:
-  stage: release
-  script:
-    - PowerShell .\build.ps1 --Target Release --Configuration Release --nugetApiKey="${NUGET_API_KEY}"
-  variables:
-    GIT_STRATEGY: clone
-  dependencies:
-    - cake:Test
-  artifacts:
-    paths:
-      - "./Artifacts/*"
-  only:
-    - tags
+variables:
+  DOTNET_MAIN_PROJECT_FOLDER: "OrganizationLoader"
 
-cake:Prerelease:
-  stage: release
-  script:
-    - PowerShell .\build.ps1 --Target Prerelease --Configuration Release
-  variables:
-    GIT_STRATEGY: clone
-  dependencies:
-    - cake:Test
-  artifacts:
-    paths:
-      - "./Artifacts/*"
-  except:
-    - tags
-    - master
+build-branch:
+  extends: .build-branch
 
-cake:GitlabRelease:
-  stage: releasetrigger
-  script:
-    - PowerShell .\build.ps1 --Target GitlabRelease --GitlabProjectPath="${CI_PROJECT_PATH}" --gitlabProjectId="${CI_PROJECT_ID}" --gitlabToken="${GITLAB_TOKEN}"
-  only:
-    - master
-  except:
-    - schedules
+build-nuget-release:
+  extends: .build-nuget-release
 
-cake:PushToGit:
-  stage: schedule
-  script:
-    - PowerShell .\build.ps1 --Target Build --Configuration Release
-    - PowerShell .\build.ps1 --Target CopyToArtifacts --Configuration Release
-    - Powershell .\Artifacts\OrganizationLoader.exe --output=Artifacts/index.ttl --force="${04XFQ0F34_FORCE}" --rorId="${04XFQ0F34_ROR_ID}" --username="${04XFQ0F34_USERNAME}" --password="${04XFQ0F34_PASSWORD}" --organizationsLink="${04XFQ0F34_ORGANIZATIONS_LINK}" --employeesLink="${04XFQ0F34_EMPLOYEES_LINK}"
-    - Powershell .\build.ps1 --Target PushToGit --gitlabToken="${GITLAB_TOKEN}" --gitAuthorEmail="${GIT_AUTHOR_EMAIL}" --gitAuthorName="${GIT_AUTHOR_NAME}" --branch="${04XFQ0F34_BRANCH}"
+publish-gitlab-release:
+  extends: .publish-gitlab-release
+  
+publish:
+  extends: .publish-artifact-release
+
+# GENERATE PIPELINE -----------------------------------------
+generate: 
+  rules:
+    - if: $CI_MERGE_REQUEST_ID
+      when: never # Ignore detached head jobs created by merge requests.
+    - if: $CI_PIPELINE_SOURCE == "schedule"
+      when: manual
+    - if: $CI_COMMIT_REF_PROTECTED == "true"
+      when: manual
+    - when: manual
+  stage: commands
+  variables:
+    DEV_BRANCH: "dev"
+    OUTPUT_FOLDER_NAME: "Artifacts"
+    OUTPUT_FILE_NAME: "index.ttl"
+  script: 
+    - dotnet run --project .\src\$DOTNET_MAIN_PROJECT_FOLDER -- --output="$OUTPUT_FOLDER_NAME/$OUTPUT_FILE_NAME" --force="${04XFQ0F34_FORCE}" --rorId="${04XFQ0F34_ROR_ID}" --username="${04XFQ0F34_USERNAME}" --password="${04XFQ0F34_PASSWORD}" --organizationsLink="${04XFQ0F34_ORGANIZATIONS_LINK}" --employeesLink="${04XFQ0F34_EMPLOYEES_LINK}"
+    - Copy-Item -Path ".\dist\**\$OUTPUT_FOLDER_NAME\*.ttl" -Destination "." -Recurse
   artifacts:
     paths:
-      - "./Artifacts/index.ttl"
-  only:
-    - schedules
\ No newline at end of file
+      - .\Artifacts\*.ttl
+    expire_in: 1 week
+
+# TODO: GitLab Push
\ No newline at end of file
diff --git a/GitVersion.yml b/GitVersion.yml
deleted file mode 100644
index 1bdc0fe219f5f35d8a024a66d9fd715f44539640..0000000000000000000000000000000000000000
--- a/GitVersion.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-mode: ContinuousDeployment
-next-version: 1.0.0
-major-version-bump-message: 'Breaking:'
-minor-version-bump-message: '(Update|New):'
-patch-version-bump-message: 'Fix:'
-no-bump-message: '.*'
-commit-message-incrementing: Enabled
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 1cacbda86167c5f5629e9d3f8605295ad009460f..b8cd48a4db77aeee8a31fbec89cd7c8c4fb0b5ff 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2019 RWTH Aachen University
+Copyright (c) 2020 RWTH Aachen University
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
+SOFTWARE.
diff --git a/build.cake b/build.cake
deleted file mode 100644
index 9f060a4ba699a17f3bcb659a0ea119dae38140b9..0000000000000000000000000000000000000000
--- a/build.cake
+++ /dev/null
@@ -1,391 +0,0 @@
-#tool nuget:?package=NUnit.ConsoleRunner&version=3.10.0
-#tool nuget:?package=vswhere&version=2.8.4
-#tool nuget:?package=GitVersion.CommandLine&version=5.1.3
-
-#addin nuget:https://api.nuget.org/v3/index.json?package=Cake.Json&version=6.0.1
-#addin nuget:https://api.nuget.org/v3/index.json?package=Newtonsoft.Json&version=11.0.2
-#addin nuget:https://api.nuget.org/v3/index.json?package=Cake.FileHelpers&version=4.0.1
-
-using System.Net;
-using System.Net.Http;
-using System.Net.Http.Headers;
-
-// Commandline arguments
-var target = Argument("target", "Default");
-var configuration = Argument("configuration", "Release");
-var nugetApiKey = Argument<string>("nugetApiKey", null);
-var version = Argument("nugetVersion", "");
-var gitlabProjectPath = Argument("gitlabProjectPath", "");
-var gitlabProjectId = Argument("gitlabProjectId", "");
-var gitlabToken = Argument("gitlabToken", "");
-var branch = Argument("branch", "");
-var gitAuthorEmail = Argument("gitAuthorEmail", "");
-var gitAuthorName = Argument("gitAuthorName", "");
-
-// Define directories
-var projects = GetFiles("./**/*.csproj");
-var artifactsDir = Directory("./Artifacts");
-string nupkgDir;
-var solutionFile = GetFiles("./**/*.sln").First();
-var projectName = solutionFile.GetFilenameWithoutExtension().ToString();
-var nugetSource = "https://api.nuget.org/v3/index.json";
-var assemblyInfoSubPath = "Properties/AssemblyInfo.cs";
-var semanticVersion = "";
-string localNugetFeed;
-
-// get latest MSBuild version
-var vsLatest  = VSWhereLatest();	
-var msBuildPathX64 = (vsLatest == null) ? null : vsLatest.CombineWithFilePath("./MSBuild/Current/Bin/MSBuild.exe");
-
-Setup(context =>{
-	nupkgDir = $"{artifactsDir.ToString()}/nupkg";
-	var branch = GitVersion(new GitVersionSettings {
-			UpdateAssemblyInfo = false
-		}).BranchName.Replace("/", "-");
-
-	localNugetFeed = $"C:\\coscine\\LocalNugetFeeds\\{branch}";
-	Information("{0}", branch);
-	Information("Started at {0}", DateTime.Now);
-});
-
-Teardown(context =>{
-	Information("Finished at {0}", DateTime.Now);
-});
-
-Task("Clean")
-.Description("Cleans all build and artifacts directories")
-.Does(() =>{
-	var settings = new DeleteDirectorySettings {
-		Recursive = true,
-		Force = true
-	};
-	
-	var directoriesToClean = new List<DirectoryPath>();
-	
-	foreach(var project in projects) {
-		directoriesToClean.Add(Directory($"{project.GetDirectory()}/obj"));
-		directoriesToClean.Add(Directory($"{project.GetDirectory()}/bin"));
-	}
-	
-	directoriesToClean.Add(artifactsDir);
-
-	foreach(var dir in directoriesToClean) {
-		Information("Cleaning {0}", dir.ToString());
-		if (DirectoryExists(dir)) {
-			DeleteDirectory(dir, settings);
-			CreateDirectory(dir);
-		} else {
-			CreateDirectory(dir);
-		}
-	}
-});
-
-Task("Restore")
-.Does(() =>{
-	NuGetRestore(solutionFile, new NuGetRestoreSettings {
-		NoCache = true,
-		FallbackSource = new List<string>{ localNugetFeed },
-	});
-});
-
-Task("Test")
-.IsDependentOn("Build")
-.Does(() =>{
-	NUnit3($"./src/**/bin/{configuration}/*.Tests.dll", new NUnit3Settings {
-		// generate the xml file
-		NoResults = false,
-		Results = new NUnit3Result[] {
-			new NUnit3Result() {
-				FileName = $"{artifactsDir}/TestResults.xml",
-				Transform = $"{Context.Environment.WorkingDirectory}/nunit3-junit.xslt"
-			}
-		}
-	});
-});
-
-Task("GitVersion")
-.Does(() => {
-	if(string.IsNullOrWhiteSpace(version)) {
-		version = GitVersion(new GitVersionSettings {
-			UpdateAssemblyInfo = false
-		}).NuGetVersionV2;
-	}
-	var index = version.IndexOf("-");
-	semanticVersion = index > 0 ? version.Substring(0, index) : version;
-	Information("Version: {0}, SemanticVersion: {1}", version, semanticVersion);
-});
-
-Task("UpdateAssemblyInfo")
-.Does(() =>{
-	var index = version.IndexOf("-");
-	var semanticVersion = index > 0 ? version.Substring(0, index) : version;
-
-	foreach(var project in projects) {
-		CreateAssemblyInfo($"{project.GetDirectory()}/{assemblyInfoSubPath}", new AssemblyInfoSettings {
-			Product = project.GetFilenameWithoutExtension().ToString(),
-			Title = project.GetFilenameWithoutExtension().ToString(),
-			Company = "IT Center, RWTH Aachen University",
-			Version = semanticVersion,
-			FileVersion = semanticVersion,
-			InformationalVersion = version,
-			Copyright = $"{DateTime.Now.Year} IT Center, RWTH Aachen University",
-			Description = $"{project.GetFilenameWithoutExtension().ToString()} is a part of the CoScInE group."
-		});
-	}
-});
-
-Task("GitlabRelease")
-.IsDependentOn("GitVersion")
-.Does(() => {
-	var client = new HttpClient();
-	client.DefaultRequestHeaders.Add("PRIVATE-TOKEN", gitlabToken);
-	
-	// get the latest tag
-	var result = client.GetAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/repository/tags").Result;
-	if(!result.IsSuccessStatusCode) {
-		throw new Exception("Tag query failed.");
-	}
-
-	var tagList = result.Content.ReadAsStringAsync().Result;
-	var jArray = JArray.Parse(tagList);
-	// null if not tags exists yet
-	var lastTag = jArray.Select(x => x["name"]).FirstOrDefault();
-
-	var url = $"https://git.rwth-aachen.de/{gitlabProjectPath}";
-	
-	if(url.EndsWith(".git")) {
-		url = url.Substring(0, url.Length - ".git".Length);
-	}
-
-	if(url.EndsWith("/")) {
-		url = url.Substring(0, url.Length - 1);
-	}
-
-	var description = "";
-	// First line of description
-	// Gitlab compare url, if something can be compared
-	if(lastTag == null) {
-		description = $"# {semanticVersion} ({DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day})\n\n\n";
-	} else {
-		description = $"# [{semanticVersion}]({url}/compare/{lastTag}...v{semanticVersion}) ({DateTime.Now.Year}-{DateTime.Now.Month}-{DateTime.Now.Day})\n\n\n";
-	}
-
-	// From when will messages be parsed, null results in all messages
-	var logParam = "";
-	if(lastTag != null) {
-		logParam = $"{lastTag}..Head";
-	}
-
-	Information(lastTag);
-
-	IEnumerable<string> redirectedStandardOutput;
-	var exitCodeWithArgument =
-		StartProcess(
-			"git",
-			new ProcessSettings {
-				Arguments = $"log {logParam} --pretty=format:HASH%h:%B",
-				RedirectStandardOutput = true
-			},
-			out redirectedStandardOutput
-		);
-
-	var prefixList = new Dictionary<string, List<string>>{
-		{"Fix", new List<string>()},
-		{"Update", new List<string>()},
-		{"New", new List<string>()},
-		{"Breaking", new List<string>()},
-		{"Docs", new List<string>()},
-		{"Build", new List<string>()},
-		{"Upgrade", new List<string>()},
-		{"Chore", new List<string>()},
-	};
-
-	var currentHash = "";
-	// Output last line of process output.
-	foreach(var line in redirectedStandardOutput) {
-		var commitMessage = "";
-		if(line.StartsWith("HASH")) {
-			currentHash = line.Substring("HASH".Length);
-			currentHash = currentHash.Substring(0, currentHash.IndexOf(":"));
-			commitMessage = line.Substring(currentHash.Length + line.IndexOf(currentHash) + 1);
-		} else {
-			commitMessage = line;
-		}
-
-		foreach(var kv in prefixList) {
-			if(commitMessage.StartsWith($"{kv.Key}:")) {
-				kv.Value.Add($"* {commitMessage.Substring(kv.Key.Length + 1).Trim()} {currentHash}");
-				break;
-			}
-		};
-	}
-	
-	foreach(var kv in prefixList) {
-		if(kv.Value.Any()) {
-			description += $" ### {kv.Key}\n\n";
-			foreach(var line in kv.Value) {
-				description += $"{line}\n";
-			}
-			description += "\n";
-		}
-	}
-	// correctly escape the json newlines
-	description = description.Replace("\n", "\\n");
-	Information("Description: {0}", description);
-
-	// create tag
-	result = client.PostAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/repository/tags?tag_name=v{semanticVersion}&ref=master", null).Result;
-	Information("Create tag: {0}", result.Content.ReadAsStringAsync().Result);
-	if(!result.IsSuccessStatusCode) {
-		throw new Exception("Tag creation failed.");
-	}
-
-	// create release
-	var json = $"{{\"name\": \"v{semanticVersion}\", \"tag_name\": \"v{semanticVersion}\", \"description\": \"{description}\"}}";
-	var content = new StringContent(json, Encoding.UTF8, "application/json");
-	result = client.PostAsync($"https://git.rwth-aachen.de/api/v4/projects/{gitlabProjectId}/releases", content).Result;
-	Information("Create release: {0}", result.Content.ReadAsStringAsync().Result);
-	if(!result.IsSuccessStatusCode) {
-		throw new Exception("Release creation failed.");
-	}
-});
-
-Task("Build")
-.IsDependentOn("Clean")
-.IsDependentOn("GitVersion")
-.IsDependentOn("UpdateAssemblyInfo")
-.IsDependentOn("Restore")
-.Does(() =>{
-		var frameworkSettingsWindows = new MSBuildSettings {
-			Configuration = configuration
-		};
-		
-		frameworkSettingsWindows.ToolPath = msBuildPathX64;
-		frameworkSettingsWindows.WorkingDirectory = Context.Environment.WorkingDirectory;
-
-		if (configuration.Equals("Release")) {
-			frameworkSettingsWindows.WithProperty("DebugSymbols", "false");
-			frameworkSettingsWindows.WithProperty("DebugType", "None");
-		}
-
-		// Use MSBuild
-		Information("Building {0}", solutionFile);
-		MSBuild(solutionFile, frameworkSettingsWindows);
-});
-
-Task("NugetPack")
-.IsDependentOn("Build")
-.Does(() =>{
-	foreach(var project in projects) {
-			var nuspec = $"{project.GetDirectory()}/{project.GetFilenameWithoutExtension()}.nuspec";
-			if(!project.ToString().EndsWith(".Tests") && FileExists(nuspec))
-			{
-				var settings = new NuGetPackSettings 
-				{
-					OutputDirectory = nupkgDir,
-					Version = version,
-					Properties = new Dictionary<string, string>
-					{
-						{ "Configuration", configuration}
-					}
-				};				
-				NuGetPack(project.ToString(), settings);
-			}
-		}
-});
-
-Task("NugetPush")
-.IsDependentOn("NugetPack")
-.Does(() =>{
-	var nupkgs = GetFiles($"{nupkgDir}/*.nupkg");
-	Information("Need to push {0} packages", nupkgs.Count);
-	if(!String.IsNullOrWhiteSpace(nugetApiKey)) {
-		foreach(var nupkg in nupkgs) {
-			Information("Pushing {0}", nupkg);
-			NuGetPush(nupkg, new NuGetPushSettings {
-				Source = nugetSource,
-				ApiKey = nugetApiKey
-			});
-		}
-	} else {
-		Information("NugetApiKey is not set. Can't push.");
-		throw new Exception("NugetApiKey is not set. Can't push.");
-	}
-});
-
-Task("CopyToArtifacts")
-.Does(() =>{
-	foreach(var project in projects) {
-		if(!project.GetDirectory().ToString().EndsWith(".Tests")
-		&& !FileExists($"{project.GetDirectory()}/{project.GetFilenameWithoutExtension()}.nuspec")
-		&& DirectoryExists(project.GetDirectory()))
-		{
-			Information("Copying {0}/* to {1}", $"{project.GetDirectory()}/bin/{configuration}", artifactsDir);
-			CopyDirectory($"{project.GetDirectory()}/bin/{configuration}/", artifactsDir);
-		}
-	}
-});
-
-Task("NugetPushLocal")
-.IsDependentOn("NugetPack")
-.Does(() =>{	
-	var nupkgs = GetFiles($"{nupkgDir}/*.nupkg");
-	foreach(var nupkg in nupkgs) {
-		if(!DirectoryExists(localNugetFeed)) {
-			CreateDirectory(localNugetFeed);
-		}
-		CopyFile(nupkg.ToString(), $"{localNugetFeed}\\{nupkg.GetFilename()}");
-	}
-});
-
-Task("PushToGit")
-.Does(() =>{
-	if(FileExists($"{artifactsDir}/index.ttl"))
-	{
-
-		var client = new HttpClient();
-		var content = FileReadText($"{artifactsDir}/index.ttl");
-		var request = new HttpRequestMessage
-		{
-			Method = HttpMethod.Put,
-			RequestUri = new Uri("https://git.rwth-aachen.de/api/v4/projects/47542/repository/files/index.ttl"),
-			Headers =
-			{
-				{ "private-token", gitlabToken },
-			},
-			Content = new StringContent($"{{\"branch\": \"{branch}\", \"author_email\":\"{gitAuthorEmail}\", \"author_name\": \"{gitAuthorName}\", \"content\": \"{content.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\"", "\\\"")}\", \"commit_message\": \"update file\"}}")
-			{
-				Headers =
-				{
-					ContentType = new MediaTypeHeaderValue("application/json")
-				}
-			}
-		};
-		using (var response = client.SendAsync(request).Result)
-		{
-			var body = response.Content.ReadAsStringAsync().Result;
-			Information("IsSuccess: {0}", response.IsSuccessStatusCode);
-			Information("StatusCode: {0}", response.StatusCode);
-			Information("Response: {0}", response.Content.ReadAsStringAsync().Result);
-			response.EnsureSuccessStatusCode();
-		}		
-	} else {
-		Information("No index ttl found. Nothing to do.");
-	}
-});
-
-Task("Prerelease")
-.IsDependentOn("Build")
-.IsDependentOn("CopyToArtifacts")
-.IsDependentOn("NugetPushLocal");
-
-Task("Release")
-.IsDependentOn("NugetPack")
-.IsDependentOn("CopyToArtifacts")
-.IsDependentOn("NugetPushLocal")
-.IsDependentOn("NugetPush");
-
-Task("Default")
-.IsDependentOn("Test");
-
-RunTarget(target);
diff --git a/build.ps1 b/build.ps1
deleted file mode 100644
index f83382e8e4092ba6cf32a47f9dfa4e211c878430..0000000000000000000000000000000000000000
--- a/build.ps1
+++ /dev/null
@@ -1,255 +0,0 @@
-#The MIT License (MIT)
-#
-#Copyright (c) 2014 - 2016 Patrik Svensson, Mattias Karlsson, Gary Ewan Park and contributors
-#
-#Permission is hereby granted, free of charge, to any person obtaining a copy of
-#this software and associated documentation files (the "Software"), to deal in
-#the Software without restriction, including without limitation the rights to
-#use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-#the Software, and to permit persons to whom the Software is furnished to do so,
-#subject to the following conditions:
-#
-#The above copyright notice and this permission notice shall be included in all
-#copies or substantial portions of the Software.
-#
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-#FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-#COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-#IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-#CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-##########################################################################
-# This is the Cake bootstrapper script for PowerShell.
-# This file was downloaded from https://github.com/cake-build/resources
-# Feel free to change this file to fit your needs.
-##########################################################################
-
-<#
-
-.SYNOPSIS
-This is a Powershell script to bootstrap a Cake build.
-
-.DESCRIPTION
-This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
-and execute your Cake build script with the parameters you provide.
-
-.PARAMETER Script
-The build script to execute.
-.PARAMETER Target
-The build script target to run.
-.PARAMETER Configuration
-The build configuration to use.
-.PARAMETER Verbosity
-Specifies the amount of information to be displayed.
-.PARAMETER ShowDescription
-Shows description about tasks.
-.PARAMETER DryRun
-Performs a dry run.
-.PARAMETER Experimental
-Uses the nightly builds of the Roslyn script engine.
-.PARAMETER Mono
-Uses the Mono Compiler rather than the Roslyn script engine.
-.PARAMETER SkipToolPackageRestore
-Skips restoring of packages.
-.PARAMETER ScriptArgs
-Remaining arguments are added here.
-
-.LINK
-https://cakebuild.net
-
-#>
-
-[CmdletBinding()]
-Param(
-    [string]$Script = "build.cake",
-    [string]$Target,
-    [string]$Configuration,
-    [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
-    [string]$Verbosity,
-    [switch]$ShowDescription,
-    [Alias("WhatIf", "Noop")]
-    [switch]$DryRun,
-    [switch]$Experimental,
-    [switch]$Mono,
-    [switch]$SkipToolPackageRestore,
-    [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
-    [string[]]$ScriptArgs
-)
-
-[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
-function MD5HashFile([string] $filePath)
-{
-    if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
-    {
-        return $null
-    }
-
-    [System.IO.Stream] $file = $null;
-    [System.Security.Cryptography.MD5] $md5 = $null;
-    try
-    {
-        $md5 = [System.Security.Cryptography.MD5]::Create()
-        $file = [System.IO.File]::OpenRead($filePath)
-        return [System.BitConverter]::ToString($md5.ComputeHash($file))
-    }
-    finally
-    {
-        if ($file -ne $null)
-        {
-            $file.Dispose()
-        }
-    }
-}
-
-function GetProxyEnabledWebClient
-{
-    $wc = New-Object System.Net.WebClient
-    $proxy = [System.Net.WebRequest]::GetSystemWebProxy()
-    $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials        
-    $wc.Proxy = $proxy
-    return $wc
-}
-
-Write-Host "Preparing to run build script..."
-
-if(!$PSScriptRoot){
-    $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
-}
-
-$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
-$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins"
-$MODULES_DIR = Join-Path $TOOLS_DIR "Modules"
-$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
-$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
-$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
-$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
-$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
-$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
-$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
-
-# Make sure tools folder exists
-if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
-    Write-Verbose -Message "Creating tools directory..."
-    New-Item -Path $TOOLS_DIR -Type directory | out-null
-}
-
-# Make sure that packages.config exist.
-if (!(Test-Path $PACKAGES_CONFIG)) {
-    Write-Verbose -Message "Downloading packages.config..."    
-    try {        
-        $wc = GetProxyEnabledWebClient
-        $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
-        Throw "Could not download packages.config."
-    }
-}
-
-# Try find NuGet.exe in path if not exists
-if (!(Test-Path $NUGET_EXE)) {
-    Write-Verbose -Message "Trying to find nuget.exe in PATH..."
-    $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
-    $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
-    if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
-        Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
-        $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
-    }
-}
-
-# Try download NuGet.exe if not exists
-if (!(Test-Path $NUGET_EXE)) {
-    Write-Verbose -Message "Downloading NuGet.exe..."
-    try {
-        $wc = GetProxyEnabledWebClient
-        $wc.DownloadFile($NUGET_URL, $NUGET_EXE)
-    } catch {
-        Throw "Could not download NuGet.exe."
-    }
-}
-
-# Save nuget.exe path to environment to be available to child processed
-$ENV:NUGET_EXE = $NUGET_EXE
-
-# Restore tools from NuGet?
-if(-Not $SkipToolPackageRestore.IsPresent) {
-    Push-Location
-    Set-Location $TOOLS_DIR
-
-    # Check for changes in packages.config and remove installed tools if true.
-    [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
-    if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
-      ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
-        Write-Verbose -Message "Missing or changed package.config hash..."
-        Remove-Item * -Recurse -Exclude packages.config,nuget.exe
-    }
-
-    Write-Verbose -Message "Restoring tools from NuGet..."
-    $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
-
-    if ($LASTEXITCODE -ne 0) {
-        Throw "An error occurred while restoring NuGet tools."
-    }
-    else
-    {
-        $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
-    }
-    Write-Verbose -Message ($NuGetOutput | out-string)
-
-    Pop-Location
-}
-
-# Restore addins from NuGet
-if (Test-Path $ADDINS_PACKAGES_CONFIG) {
-    Push-Location
-    Set-Location $ADDINS_DIR
-
-    Write-Verbose -Message "Restoring addins from NuGet..."
-    $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
-
-    if ($LASTEXITCODE -ne 0) {
-        Throw "An error occurred while restoring NuGet addins."
-    }
-
-    Write-Verbose -Message ($NuGetOutput | out-string)
-
-    Pop-Location
-}
-
-# Restore modules from NuGet
-if (Test-Path $MODULES_PACKAGES_CONFIG) {
-    Push-Location
-    Set-Location $MODULES_DIR
-
-    Write-Verbose -Message "Restoring modules from NuGet..."
-    $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
-
-    if ($LASTEXITCODE -ne 0) {
-        Throw "An error occurred while restoring NuGet modules."
-    }
-
-    Write-Verbose -Message ($NuGetOutput | out-string)
-
-    Pop-Location
-}
-
-# Make sure that Cake has been installed.
-if (!(Test-Path $CAKE_EXE)) {
-    Throw "Could not find Cake.exe at $CAKE_EXE"
-}
-
-
-
-# Build Cake arguments
-$cakeArguments = @("$Script");
-if ($Target) { $cakeArguments += "-target=$Target" }
-if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
-if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
-if ($ShowDescription) { $cakeArguments += "-showdescription" }
-if ($DryRun) { $cakeArguments += "-dryrun" }
-if ($Experimental) { $cakeArguments += "-experimental" }
-if ($Mono) { $cakeArguments += "-mono" }
-$cakeArguments += $ScriptArgs
-
-# Start Cake
-Write-Host "Running build script..."
-&$CAKE_EXE $cakeArguments
-exit $LASTEXITCODE
diff --git a/build.sh b/build.sh
deleted file mode 100644
index d088917ed78538ff57cf654cf71aad6bf045d655..0000000000000000000000000000000000000000
--- a/build.sh
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env bash
-
-#The MIT License (MIT)
-#
-#Copyright (c) 2014 - 2016 Patrik Svensson, Mattias Karlsson, Gary Ewan Park and contributors
-#
-#Permission is hereby granted, free of charge, to any person obtaining a copy of
-#this software and associated documentation files (the "Software"), to deal in
-#the Software without restriction, including without limitation the rights to
-#use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-#the Software, and to permit persons to whom the Software is furnished to do so,
-#subject to the following conditions:
-#
-#The above copyright notice and this permission notice shall be included in all
-#copies or substantial portions of the Software.
-#
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-#FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-#COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-#IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-#CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-##########################################################################
-# This is the Cake bootstrapper script for Linux and OS X.
-# This file was downloaded from https://github.com/cake-build/resources
-# Feel free to change this file to fit your needs.
-##########################################################################
-
-# Define directories.
-SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-TOOLS_DIR=$SCRIPT_DIR/tools
-NUGET_EXE=$TOOLS_DIR/nuget.exe
-CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe
-PACKAGES_CONFIG=$TOOLS_DIR/packages.config
-PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum
-
-# Define md5sum or md5 depending on Linux/OSX
-MD5_EXE=
-if [[ "$(uname -s)" == "Darwin" ]]; then
-    MD5_EXE="md5 -r"
-else
-    MD5_EXE="md5sum"
-fi
-
-# Define default arguments.
-SCRIPT="build.cake"
-TARGET="Default"
-CONFIGURATION="Release"
-VERBOSITY="verbose"
-DRYRUN=
-SHOW_VERSION=false
-SCRIPT_ARGUMENTS=()
-
-# Parse arguments.
-for i in "$@"; do
-    case $1 in
-        -s|--script) SCRIPT="$2"; shift ;;
-        -t|--target) TARGET="$2"; shift ;;
-        -c|--configuration) CONFIGURATION="$2"; shift ;;
-        -v|--verbosity) VERBOSITY="$2"; shift ;;
-        -d|--dryrun) DRYRUN="-dryrun" ;;
-        --version) SHOW_VERSION=true ;;
-        --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
-        *) SCRIPT_ARGUMENTS+=("$1") ;;
-    esac
-    shift
-done
-
-# Make sure the tools folder exist.
-if [ ! -d "$TOOLS_DIR" ]; then
-  mkdir "$TOOLS_DIR"
-fi
-
-# Make sure that packages.config exist.
-if [ ! -f "$TOOLS_DIR/packages.config" ]; then
-    echo "Downloading packages.config..."
-    curl -Lsfo "$TOOLS_DIR/packages.config" https://cakebuild.net/download/bootstrapper/packages
-    if [ $? -ne 0 ]; then
-        echo "An error occurred while downloading packages.config."
-        exit 1
-    fi
-fi
-
-# Download NuGet if it does not exist.
-if [ ! -f "$NUGET_EXE" ]; then
-    echo "Downloading NuGet..."
-    curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
-    if [ $? -ne 0 ]; then
-        echo "An error occurred while downloading nuget.exe."
-        exit 1
-    fi
-fi
-
-# Restore tools from NuGet.
-pushd "$TOOLS_DIR" >/dev/null
-if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then
-    find . -type d ! -name . | xargs rm -rf
-fi
-
-mono "$NUGET_EXE" install -ExcludeVersion
-if [ $? -ne 0 ]; then
-    echo "Could not restore NuGet packages."
-    exit 1
-fi
-
-$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
-
-popd >/dev/null
-
-# Make sure that Cake has been installed.
-if [ ! -f "$CAKE_EXE" ]; then
-    echo "Could not find Cake.exe at '$CAKE_EXE'."
-    exit 1
-fi
-
-# Start Cake
-if $SHOW_VERSION; then
-    exec mono "$CAKE_EXE" -version
-else
-    exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
-fi
\ No newline at end of file
diff --git a/src/OrganizationLoader.Tests/OrganizationLoader.Tests.csproj b/src/OrganizationLoader.Tests/OrganizationLoader.Tests.csproj
index d44c54b4f12d8b7d20bf328cc1a1fb5717e9598e..886f0bfafbfba04175fe2bd7adddf720677c588e 100644
--- a/src/OrganizationLoader.Tests/OrganizationLoader.Tests.csproj
+++ b/src/OrganizationLoader.Tests/OrganizationLoader.Tests.csproj
@@ -1,94 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\packages\NUnit3TestAdapter.3.17.0\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.17.0\build\net35\NUnit3TestAdapter.props')" />
-  <Import Project="..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" />
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{03640D83-D935-41BE-80A7-7C723FBF58B4}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Coscine.OrganizationLoader.Tests</RootNamespace>
-    <AssemblyName>Coscine.OrganizationLoader.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <Deterministic>true</Deterministic>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Consul, Version=1.6.1.1, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
-      <HintPath>..\packages\Consul.1.6.1.1\lib\net461\Consul.dll</HintPath>
-    </Reference>
-    <Reference Include="Coscine.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
-      <HintPath>..\packages\Coscine.Configuration.2.0.0\lib\net461\Coscine.Configuration.dll</HintPath>
-    </Reference>
-    <Reference Include="dotNetRDF, Version=2.5.1.0, Culture=neutral, PublicKeyToken=6055ffe4c97cc780, processorArchitecture=MSIL">
-      <HintPath>..\packages\dotNetRDF.2.5.1\lib\net40\dotNetRDF.dll</HintPath>
-    </Reference>
-    <Reference Include="HtmlAgilityPack, Version=1.11.17.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
-      <HintPath>..\packages\HtmlAgilityPack.1.11.17\lib\Net45\HtmlAgilityPack.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.12.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Net.Http.WebRequest" />
-    <Reference Include="System.Security" />
-    <Reference Include="System.Web" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-    <Reference Include="VDS.Common, Version=1.10.0.0, Culture=neutral, PublicKeyToken=ab5f4eb908061bf0, processorArchitecture=MSIL">
-      <HintPath>..\packages\VDS.Common.1.10.0\lib\net40-client\VDS.Common.dll</HintPath>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="OrganizationLoaderTests.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
+
   <ItemGroup>
-    <None Include="app.config" />
-    <None Include="packages.config" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
+    <PackageReference Include="NUnit" Version="3.13.3" />
+    <PackageReference Include="NUnit3TestAdapter" Version="4.3.0" />
+    <PackageReference Include="NUnit.Analyzers" Version="3.5.0" />
+    <PackageReference Include="coverlet.collector" Version="3.1.2" />
   </ItemGroup>
+
   <ItemGroup>
-    <ProjectReference Include="..\OrganizationLoader\OrganizationLoader.csproj">
-      <Project>{74141db8-e6ae-49f7-8e99-33ceafb92729}</Project>
-      <Name>OrganizationLoader</Name>
-    </ProjectReference>
+    <ProjectReference Include="..\OrganizationLoader\OrganizationLoader.csproj" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" />
-    <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.17.0\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.17.0\build\net35\NUnit3TestAdapter.props'))" />
-  </Target>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/OrganizationLoader.Tests/OrganizationLoaderTests.cs b/src/OrganizationLoader.Tests/OrganizationLoaderTests.cs
deleted file mode 100644
index 3cc7c652b0744124fc3fca787f954cf0ec6f9f25..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader.Tests/OrganizationLoaderTests.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using Coscine.Configuration;
-using NUnit.Framework;
-using System;
-using System.Net.Http;
-using System.Net.Http.Headers;
-using System.Text;
-using VDS.RDF;
-using VDS.RDF.Parsing;
-
-namespace Coscine.OrganizationLoader.Tests
-{
-    [TestFixture]
-    public class OrganizationLoaderTests
-    {
-        readonly IConfiguration configuration = new ConsulConfiguration();
-
-        [Test]
-        public void GraphParsingTest()
-        {
-            var httpClient = new HttpClient();
-            // Create a basic Authentication header
-            var username = configuration.GetString("coscine/global/organizations/rwth/connection_data/username");
-            var password = configuration.GetString("coscine/global/organizations/rwth/connection_data/password");
-
-            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")));
-
-            string organizationsString;
-            string employeesString;
-
-            using (var response = httpClient.GetStringAsync(configuration.GetString("coscine/global/organizations/rwth/files/organizations/link")))
-            {
-                organizationsString = response.Result;
-            }
-
-            using (var response = httpClient.GetStringAsync(configuration.GetString("coscine/global/organizations/rwth/files/employees/link")))
-            {
-                employeesString = response.Result;
-            }
-
-            var organizations = Program.ParseOrganizations(organizationsString);
-            var employees = Program.LoadEmployees(employeesString, organizations);
-
-            var ttl = Program.GenerateTurtle(organizations, employees, configuration.GetString("coscine/global/organizations/rwth/ror_url"));
-            try
-            {
-                var graph = new Graph();
-                graph.LoadFromString(ttl, new TurtleParser());
-            }
-            catch (Exception)
-            {
-                Assert.True(false);
-            }
-        }
-    }
-}
diff --git a/src/OrganizationLoader.Tests/Properties/AssemblyInfo.cs b/src/OrganizationLoader.Tests/Properties/AssemblyInfo.cs
deleted file mode 100644
index 01c06bc88100b71301e1bf35730738aaddf50a9c..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader.Tests/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by Cake.
-// </auto-generated>
-//------------------------------------------------------------------------------
-using System.Reflection;
-
-[assembly: AssemblyTitle("OrganizationLoader.Tests")]
-[assembly: AssemblyDescription("OrganizationLoader.Tests is a part of the CoScInE group.")]
-[assembly: AssemblyCompany("IT Center, RWTH Aachen University")]
-[assembly: AssemblyProduct("OrganizationLoader.Tests")]
-[assembly: AssemblyVersion("1.2.1")]
-[assembly: AssemblyFileVersion("1.2.1")]
-[assembly: AssemblyInformationalVersion("1.2.1-product-1414-fhp0003")]
-[assembly: AssemblyCopyright("2021 IT Center, RWTH Aachen University")]
-
diff --git a/src/OrganizationLoader.Tests/Tests.cs b/src/OrganizationLoader.Tests/Tests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e1b5270a4de2f5a496180f19e712bc53fcfb2883
--- /dev/null
+++ b/src/OrganizationLoader.Tests/Tests.cs
@@ -0,0 +1,59 @@
+using Coscine.Configuration;
+using NUnit.Framework;
+using System.Net.Http.Headers;
+using System.Text;
+using VDS.RDF;
+using VDS.RDF.Parsing;
+
+namespace OrganizationLoader.Tests;
+
+public class Tests
+{
+    private IConfiguration configuration;
+    private HttpClient httpClient;
+
+    [SetUp]
+    public void Setup()
+    {
+        configuration = new ConsulConfiguration();
+        httpClient = new HttpClient();
+
+        // Create a basic Authentication header
+        var username = configuration.GetString("coscine/global/organizations/rwth/connection_data/username");
+        var password = configuration.GetString("coscine/global/organizations/rwth/connection_data/password");
+
+        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")));
+    }
+
+    [Test]
+    public void GraphParsingTest()
+    {
+        string organizationsString;
+        string employeesString;
+
+        using (var response = httpClient.GetStringAsync(configuration.GetString("coscine/global/organizations/rwth/files/organizations/link")))
+        {
+            organizationsString = response.Result;
+        }
+
+        using (var response = httpClient.GetStringAsync(configuration.GetString("coscine/global/organizations/rwth/files/employees/link")))
+        {
+            employeesString = response.Result;
+        }
+
+        var organizations = Program.ParseOrganizations(organizationsString);
+        var employees = Program.LoadEmployees(employeesString, organizations);
+
+        var ttl = Program.GenerateTurtle(organizations, employees, configuration.GetString("coscine/global/organizations/rwth/ror_url"));
+        try
+        {
+            var graph = new Graph();
+            graph.LoadFromString(ttl, new TurtleParser());
+            Assert.Pass();
+        }
+        catch (Exception)
+        {
+            Assert.Fail("Failed to parse Turtle string");
+        }
+    }
+}
diff --git a/src/OrganizationLoader.Tests/app.config b/src/OrganizationLoader.Tests/app.config
deleted file mode 100644
index efa0c157b4a15808632a7dfb3240e974dbcf6bcb..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader.Tests/app.config
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="linq2db" publicKeyToken="e41013125f9e410a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Coscine.Configuration" publicKeyToken="ce3d7a32d7dc1e5a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="dotNetRDF" publicKeyToken="6055ffe4c97cc780" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.5.1.0" newVersion="2.5.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Coscine.Database" publicKeyToken="767d77427707b70a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.22.1.0" newVersion="1.22.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.11.24.0" newVersion="1.11.24.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Caching.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/src/OrganizationLoader.Tests/packages.config b/src/OrganizationLoader.Tests/packages.config
deleted file mode 100644
index 5244cd860f32829c055d38d57b9fc79bdc065ead..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader.Tests/packages.config
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Consul" version="1.6.1.1" targetFramework="net461" />
-  <package id="Coscine.Configuration" version="2.0.0" targetFramework="net461" />
-  <package id="dotNetRDF" version="2.5.1" targetFramework="net461" />
-  <package id="HtmlAgilityPack" version="1.11.17" targetFramework="net461" />
-  <package id="Newtonsoft.Json" version="12.0.3" targetFramework="net461" />
-  <package id="NUnit" version="3.12.0" targetFramework="net461" />
-  <package id="NUnit3TestAdapter" version="3.17.0" targetFramework="net461" />
-  <package id="VDS.Common" version="1.10.0" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/src/OrganizationLoader.sln b/src/OrganizationLoader.sln
index a82e02c7ac4730c0fce255171efc97ab16ba324d..a215348d89cde4de8bb2d3ea2eaa6eb3acfd384b 100644
--- a/src/OrganizationLoader.sln
+++ b/src/OrganizationLoader.sln
@@ -1,11 +1,11 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.28803.156
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33516.290
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationLoader", "OrganizationLoader\OrganizationLoader.csproj", "{74141DB8-E6AE-49F7-8E99-33CEAFB92729}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationLoader", "OrganizationLoader\OrganizationLoader.csproj", "{AE8B3FEC-B69C-4852-A18A-7634F620F7DC}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationLoader.Tests", "OrganizationLoader.Tests\OrganizationLoader.Tests.csproj", "{03640D83-D935-41BE-80A7-7C723FBF58B4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrganizationLoader.Tests", "OrganizationLoader.Tests\OrganizationLoader.Tests.csproj", "{051F4B7F-A82A-4C14-9606-8DDF760463BD}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,19 +13,19 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{74141DB8-E6AE-49F7-8E99-33CEAFB92729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{74141DB8-E6AE-49F7-8E99-33CEAFB92729}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{74141DB8-E6AE-49F7-8E99-33CEAFB92729}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{74141DB8-E6AE-49F7-8E99-33CEAFB92729}.Release|Any CPU.Build.0 = Release|Any CPU
-		{03640D83-D935-41BE-80A7-7C723FBF58B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{03640D83-D935-41BE-80A7-7C723FBF58B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{03640D83-D935-41BE-80A7-7C723FBF58B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{03640D83-D935-41BE-80A7-7C723FBF58B4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE8B3FEC-B69C-4852-A18A-7634F620F7DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE8B3FEC-B69C-4852-A18A-7634F620F7DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE8B3FEC-B69C-4852-A18A-7634F620F7DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE8B3FEC-B69C-4852-A18A-7634F620F7DC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{051F4B7F-A82A-4C14-9606-8DDF760463BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{051F4B7F-A82A-4C14-9606-8DDF760463BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{051F4B7F-A82A-4C14-9606-8DDF760463BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{051F4B7F-A82A-4C14-9606-8DDF760463BD}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {9C09B46C-8D03-4E62-B112-0191A5F42D4A}
+		SolutionGuid = {E50CAE55-D8A0-4676-A4A9-C2A2FB16B658}
 	EndGlobalSection
 EndGlobal
diff --git a/src/OrganizationLoader/App.config b/src/OrganizationLoader/App.config
deleted file mode 100644
index 8a8a619fb943efb6089e5b0f87754067d5a17824..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/App.config
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-  <configSections>
-  <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
-  <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
-  </configSections>
-  <startup>
-    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
-  </startup>
-  <entityFramework>
-    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
-      <parameters>
-        <parameter value="mssqllocaldb" />
-      </parameters>
-    </defaultConnectionFactory>
-    <providers>
-      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
-    </providers>
-  </entityFramework>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="Coscine.Configuration" publicKeyToken="ce3d7a32d7dc1e5a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="dotNetRDF" publicKeyToken="6055ffe4c97cc780" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.5.1.0" newVersion="2.5.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Coscine.Database" publicKeyToken="767d77427707b70a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.22.1.0" newVersion="1.22.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.11.24.0" newVersion="1.11.24.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="linq2db" publicKeyToken="e41013125f9e410a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Caching.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-3.1.12.0" newVersion="3.1.12.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>
\ No newline at end of file
diff --git a/src/OrganizationLoader/Employee.cs b/src/OrganizationLoader/Employee.cs
deleted file mode 100644
index 9d447dd025ae4cadef237cf00c57fb2a9ca4d507..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/Employee.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-
-namespace Coscine.OrganizationLoader
-{
-    public class Employee
-    {
-        public string Surname { get; set; }
-        public string PreferredName { get; set; }
-        public string ID { get; set; }
-        public string RONID { get; set; }
-        public List<string> Memberships { get; set; }
-        public string DegreePre { get; set; }
-        public string DegreePost { get; set; }
-        public string Ubpublications { get; set; }
-        public List<Role> RoleAssignments { get; set; }
-    }
-}
diff --git a/src/OrganizationLoader/Organization.cs b/src/OrganizationLoader/Organization.cs
deleted file mode 100644
index c29e79606298f074179bf9a8e8e105a13459dd97..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/Organization.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Collections.Generic;
-
-namespace Coscine.OrganizationLoader
-{
-    public class Organization
-    {
-        public string OrgId { get; set; }
-        public string Name { get; set; }
-        public string IKZ { get; set; }
-        public string Abbreviation { get; set; }
-        public string CMSLink { get; set; }
-
-        public List<Employee> Members { get; set; } = new List<Employee>();
-    }
-}
diff --git a/src/OrganizationLoader/OrganizationLoader.csproj b/src/OrganizationLoader/OrganizationLoader.csproj
index 1c28856ba3bb0aaea4282c43782d7b03e181c605..c342da71c3e57bf8c4ae35d36d15c428eb861988 100644
--- a/src/OrganizationLoader/OrganizationLoader.csproj
+++ b/src/OrganizationLoader/OrganizationLoader.csproj
@@ -1,239 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="..\packages\LibGit2Sharp.NativeBinaries.2.0.306\build\net46\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.306\build\net46\LibGit2Sharp.NativeBinaries.props')" />
-  <Import Project="..\packages\linq2db.t4models.3.0.1\build\linq2db.t4models.props" Condition="Exists('..\packages\linq2db.t4models.3.0.1\build\linq2db.t4models.props')" />
-  <Import Project="..\packages\linq2db.SqlServer.3.0.1\build\linq2db.SqlServer.props" Condition="Exists('..\packages\linq2db.SqlServer.3.0.1\build\linq2db.SqlServer.props')" />
-  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{74141DB8-E6AE-49F7-8E99-33CEAFB92729}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Coscine.OrganizationLoader</RootNamespace>
-    <AssemblyName>OrganizationLoader</AssemblyName>
-    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
-    <Deterministic>true</Deterministic>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="Consul, Version=1.6.1.1, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
-      <HintPath>..\packages\Consul.1.6.1.1\lib\net461\Consul.dll</HintPath>
-    </Reference>
-    <Reference Include="Coscine.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
-      <HintPath>..\packages\Coscine.Configuration.2.0.0\lib\net461\Coscine.Configuration.dll</HintPath>
-    </Reference>
-    <Reference Include="Coscine.Database, Version=2.3.0.0, Culture=neutral, PublicKeyToken=767d77427707b70a, processorArchitecture=MSIL">
-      <HintPath>..\packages\Coscine.Database.2.3.0\lib\net461\Coscine.Database.dll</HintPath>
-    </Reference>
-    <Reference Include="dotNetRDF, Version=2.5.1.0, Culture=neutral, PublicKeyToken=6055ffe4c97cc780, processorArchitecture=MSIL">
-      <HintPath>..\packages\dotNetRDF.2.5.1\lib\net40\dotNetRDF.dll</HintPath>
-    </Reference>
-    <Reference Include="dotNetRDF.Data.Virtuoso, Version=2.5.1.0, Culture=neutral, PublicKeyToken=6055ffe4c97cc780, processorArchitecture=MSIL">
-      <HintPath>..\packages\dotNetRDF.Data.Virtuoso.2.5.1\lib\net40\dotNetRDF.Data.Virtuoso.dll</HintPath>
-    </Reference>
-    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
-    </Reference>
-    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
-      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
-    </Reference>
-    <Reference Include="HtmlAgilityPack, Version=1.11.24.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
-      <HintPath>..\packages\HtmlAgilityPack.1.11.24\lib\Net45\HtmlAgilityPack.dll</HintPath>
-    </Reference>
-    <Reference Include="Inflector, Version=1.2.2.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\Inflector.NetStandard.1.2.2\lib\net461\Inflector.dll</HintPath>
-    </Reference>
-    <Reference Include="LibGit2Sharp, Version=0.26.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
-      <HintPath>..\packages\LibGit2Sharp.0.26.2\lib\net46\LibGit2Sharp.dll</HintPath>
-    </Reference>
-    <Reference Include="linq2db, Version=3.0.1.0, Culture=neutral, PublicKeyToken=e41013125f9e410a, processorArchitecture=MSIL">
-      <HintPath>..\packages\linq2db.3.0.1\lib\net46\linq2db.dll</HintPath>
-    </Reference>
-    <Reference Include="LinqKit, Version=1.1.23.0, Culture=neutral, PublicKeyToken=bc217f8844052a91, processorArchitecture=MSIL">
-      <HintPath>..\packages\LinqKit.1.1.23\lib\net45\LinqKit.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Bcl.HashCode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Bcl.HashCode.1.1.1\lib\net461\Microsoft.Bcl.HashCode.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Data.SqlClient, Version=1.13.20136.2, Culture=neutral, PublicKeyToken=23ec7fc2d6eaa4a5, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Data.SqlClient.1.1.3\lib\net46\Microsoft.Data.SqlClient.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.EntityFrameworkCore.3.1.12\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.Abstractions, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.EntityFrameworkCore.Abstractions.3.1.12\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.Relational, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.EntityFrameworkCore.Relational.3.1.12\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.EntityFrameworkCore.SqlServer, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.EntityFrameworkCore.SqlServer.3.1.12\lib\netstandard2.0\Microsoft.EntityFrameworkCore.SqlServer.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Caching.Abstractions, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Caching.Abstractions.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Caching.Memory, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Caching.Memory.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.3.1.12\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.3.1.12\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Logging.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Options, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Options.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Primitives, Version=3.1.12.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Extensions.Primitives.3.1.12\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.Identity.Client, Version=3.0.8.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.Identity.Client.3.0.8\lib\net45\Microsoft.Identity.Client.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.IdentityModel.JsonWebTokens, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IdentityModel.JsonWebTokens.5.5.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.IdentityModel.Logging, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IdentityModel.Logging.5.5.0\lib\net461\Microsoft.IdentityModel.Logging.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.IdentityModel.Protocols, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IdentityModel.Protocols.5.5.0\lib\net461\Microsoft.IdentityModel.Protocols.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.5.5.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll</HintPath>
-    </Reference>
-    <Reference Include="Microsoft.IdentityModel.Tokens, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\Microsoft.IdentityModel.Tokens.5.5.0\lib\net461\Microsoft.IdentityModel.Tokens.dll</HintPath>
-    </Reference>
-    <Reference Include="NDesk.Options, Version=0.2.1.0, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\NDesk.Options.0.2.1\lib\NDesk.Options.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="System" />
-    <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
-    </Reference>
-    <Reference Include="System.ComponentModel.DataAnnotations" />
-    <Reference Include="System.Configuration" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Data.Common, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Data.Common.4.3.0\lib\net451\System.Data.Common.dll</HintPath>
-      <Private>True</Private>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.7.1\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.IdentityModel" />
-    <Reference Include="System.IdentityModel.Tokens.Jwt, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.IdentityModel.Tokens.Jwt.5.5.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Net.Http.WebRequest" />
-    <Reference Include="System.Numerics" />
-    <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Security" />
-    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Web" />
-    <Reference Include="System.Windows.Forms" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-    <Reference Include="VDS.Common, Version=1.10.0.0, Culture=neutral, PublicKeyToken=ab5f4eb908061bf0, processorArchitecture=MSIL">
-      <HintPath>..\packages\VDS.Common.1.10.0\lib\net40-client\VDS.Common.dll</HintPath>
-    </Reference>
-    <Reference Include="virtado4, Version=4.0.0.0, Culture=neutral, PublicKeyToken=391bf132017ae989, processorArchitecture=MSIL">
-      <HintPath>..\packages\OpenLink.Data.Virtuoso.7.20.3214.1\lib\net40\virtado4.dll</HintPath>
-    </Reference>
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="Employee.cs" />
-    <Compile Include="Organization.cs" />
-    <Compile Include="OrganizationMapping.cs" />
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ResourceType.cs" />
-    <Compile Include="Role.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="App.config" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
-    <PropertyGroup>
-      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
-    </PropertyGroup>
-    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
-    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
-    <Error Condition="!Exists('..\packages\linq2db.SqlServer.3.0.1\build\linq2db.SqlServer.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\linq2db.SqlServer.3.0.1\build\linq2db.SqlServer.props'))" />
-    <Error Condition="!Exists('..\packages\linq2db.t4models.3.0.1\build\linq2db.t4models.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\linq2db.t4models.3.0.1\build\linq2db.t4models.props'))" />
-    <Error Condition="!Exists('..\packages\LibGit2Sharp.NativeBinaries.2.0.306\build\net46\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\LibGit2Sharp.NativeBinaries.2.0.306\build\net46\LibGit2Sharp.NativeBinaries.props'))" />
-    <Error Condition="!Exists('..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets'))" />
-  </Target>
-  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
-  <Import Project="..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets" Condition="Exists('..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets')" />
-</Project>
\ No newline at end of file
+<Project Sdk="Microsoft.NET.Sdk">
+
+	<PropertyGroup>
+		<OutputType>Exe</OutputType>
+		<TargetFramework>net6.0</TargetFramework>
+		<ImplicitUsings>enable</ImplicitUsings>
+		<Nullable>enable</Nullable>
+		<Version>0.0.0</Version>
+	</PropertyGroup>
+
+	<PropertyGroup>
+		<Authors>RWTH Aachen University</Authors>
+		<Company>IT Center, RWTH Aachen University</Company>
+		<Copyright>©2023 IT Center, RWTH Aachen University</Copyright>
+		<Description>OrganizationLoader is a part of the Coscine group.</Description>
+	</PropertyGroup>
+
+	<ItemGroup>
+		<PackageReference Include="CommandLineParser" Version="2.9.1" />
+		<PackageReference Include="Coscine.Database" Version="2.20.0" />
+		<PackageReference Include="dotNetRdf" Version="3.0.0" />
+	</ItemGroup>
+
+</Project>
diff --git a/src/OrganizationLoader/OrganizationMapping.cs b/src/OrganizationLoader/OrganizationMapping.cs
deleted file mode 100644
index 5ccd98a950bc11dc47e2f82edfe5ea2a305d84bd..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/OrganizationMapping.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Coscine.OrganizationLoader
-{
-    public class OrganizationMapping
-    {
-        public string EntityId { get; set; }
-        public string RorId { get; set; }
-    }
-}
diff --git a/src/OrganizationLoader/Program.cs b/src/OrganizationLoader/Program.cs
index 04e857b84fdb84e8be5c807b2608a90deabab7ed..3d3b645863e2149f373c2ef03dc558ae38218771 100644
--- a/src/OrganizationLoader/Program.cs
+++ b/src/OrganizationLoader/Program.cs
@@ -1,156 +1,108 @@
-using Coscine.Configuration;
-using NDesk.Options;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.Http;
+using CommandLine;
+using Coscine.Configuration;
+using OrganizationLoader.Utility;
+using System.Data;
 using System.Net.Http.Headers;
 using System.Security.Cryptography;
 using System.Text;
 using System.Xml;
 
-namespace Coscine.OrganizationLoader
+namespace OrganizationLoader;
+
+public class Program
 {
-    public class Program
-    {
-        private static HttpClient _httpClient;
+    private static readonly HttpClient _httpClient = new();
 
-        private static readonly List<ResourceType> _resourceTypes = new List<ResourceType>
+    private static readonly List<ResourceType> _resourceTypes = new()
+    {
+        new ResourceType
         {
-            new ResourceType
-            {
-                Name ="rds",
-                Quota = 25,
-                MaxQuota = 100,
-                HasQuota = true,
-            },
-            new ResourceType
-            {  Name ="rdss3",
-                Quota = 0,
-                MaxQuota = 0,
-                HasQuota = true,
-            },
-            new ResourceType
-            {  Name = "linked",
-               Quota = -1,
-               MaxQuota = -1,
-               HasQuota = false,
-            },
-        };
-
-        // taken from https://tools.aai.dfn.de/entities/ and https://git.rwth-aachen.de/coscine/graphs/organizations/-/raw/master/ROR/index.ttl
-        private static readonly List<OrganizationMapping> _organizationMappings = new List<OrganizationMapping>
+            Name ="rds",
+            Quota = 25,
+            MaxQuota = 100,
+            HasQuota = true,
+        },
+        new ResourceType
+        {  Name ="rdss3",
+            Quota = 0,
+            MaxQuota = 0,
+            HasQuota = true,
+        },
+        new ResourceType
+        {  Name = "linked",
+           Quota = -1,
+           MaxQuota = -1,
+           HasQuota = false,
+        },
+    };
+
+    // taken from https://tools.aai.dfn.de/entities/ and https://git.rwth-aachen.de/coscine/graphs/organizations/-/raw/master/ROR/index.ttl
+    private static readonly List<OrganizationMapping> _organizationMappings = new()
+    {
+        new OrganizationMapping
         {
-            new OrganizationMapping
-            {
-                RorId = "https://ror.org/04xfq0f34",
-                EntityId = "https://login.rz.rwth-aachen.de/shibboleth",
-            },
-            new OrganizationMapping
-            {
-                RorId = "https://ror.org/04xfq0f34",
-                EntityId = "https://login-test.rz.rwth-aachen.de/shibboleth",
-            },
-        };
-
-        static void Main(string[] args)
+            RorId = "https://ror.org/04xfq0f34",
+            EntityId = "https://login.rz.rwth-aachen.de/shibboleth",
+        },
+        new OrganizationMapping
         {
-            bool showHelp = false;
-            bool force = false;
-            string username = null;
-            string password = null;
-            string organizationsLink = null;
-            string employeesLink = null;
-            string rorId = null;
-            string output = null;
-
-            var optionSet = new OptionSet() {
-                { "force=",  "Skip checks for to many or no changes in the exports.",
-                   x => force = x != null && x == "true" },
-                { "username=",  "Username for the export. If none is provided, the consul value is used.",
-                   x => username = x },
-                { "password=",  "Password for the export. If none is provided, the consul value is used.",
-                   x => password = x },
-                { "organizationsLink=",  "Link for the organizations export. If none is provided, the consul value is used.",
-                   x => organizationsLink = x },
-                { "employeesLink=",  "Link for the employee export. If none is provided, the consul value is used.",
-                   x => employeesLink = x },
-                { "rorId=",  "The RWTH ror Id. If none is provided, the consul value is used.",
-                   x => rorId = x },
-                { "output=",  "Output for the generated file (Mandatory).",
-                   x => output = x },
-                { "h|help",  "show help and exit",
-                   x => showHelp = x != null },
-            };
-
-            List<string> extra;
-            try
-            {
-                extra = optionSet.Parse(args);
-            }
-            catch (OptionException e)
-            {
-                Console.WriteLine(e.Message);
-                Console.WriteLine("Try '--help' for more information.");
-                return;
-            }
-
-            if (showHelp)
-            {
-                foreach (var option in optionSet)
-                {
-                    Console.WriteLine($"{option}: {option.Description}");
-                }
-                return;
-            }
-
-            if (force)
-            {
-                Console.WriteLine("Forced execution! Checks will be skipped.");
-            }
+            RorId = "https://ror.org/04xfq0f34",
+            EntityId = "https://login-test.rz.rwth-aachen.de/shibboleth",
+        },
+    };
 
-            if (string.IsNullOrWhiteSpace(output))
-            {
-                Console.WriteLine("No value for output provided.");
-                return;
-            }
+    static void Main(string[] args)
+    {
+        var parser = new Parser(with => with.HelpWriter = null);
+        var parserResult = parser.ParseArguments<CommandLineOptions>(args);
 
+        parserResult.WithParsed(options =>
+        {
             var configuration = new ConsulConfiguration();
 
-            rorId = string.IsNullOrWhiteSpace(rorId) ? configuration.GetString("coscine/global/organizations/rwth/ror_url") : rorId;
-            if (string.IsNullOrWhiteSpace(rorId))
+            options.RorId = string.IsNullOrWhiteSpace(options.RorId) ?
+                configuration.GetString("coscine/global/organizations/rwth/ror_url") : options.RorId;
+            if (string.IsNullOrWhiteSpace(options.RorId))
             {
                 Console.WriteLine("No value for rorId provided.");
+                return; // If a required value is missing, you might want to stop the execution
             }
 
-            organizationsLink = string.IsNullOrWhiteSpace(organizationsLink) ? configuration.GetString("coscine/global/organizations/rwth/files/organizations/link") : organizationsLink;
-            if (string.IsNullOrWhiteSpace(organizationsLink))
+            options.OrganizationsLink = string.IsNullOrWhiteSpace(options.OrganizationsLink) ?
+                configuration.GetString("coscine/global/organizations/rwth/files/organizations/link") : options.OrganizationsLink;
+            Console.WriteLine($"Using URI: {options.OrganizationsLink}");
+            if (string.IsNullOrWhiteSpace(options.OrganizationsLink))
             {
-                Console.WriteLine("No value for organizationsLink provided.");
+                Console.WriteLine("No value for organizations link provided.");
+                return;
             }
 
-            employeesLink = string.IsNullOrWhiteSpace(employeesLink) ? configuration.GetString("coscine/global/organizations/rwth/files/employees/link") : employeesLink;
-            if (string.IsNullOrWhiteSpace(employeesLink))
+            options.EmployeesLink = string.IsNullOrWhiteSpace(options.EmployeesLink) ?
+                configuration.GetString("coscine/global/organizations/rwth/files/employees/link") : options.EmployeesLink;
+            if (string.IsNullOrWhiteSpace(options.EmployeesLink))
             {
-                Console.WriteLine("No value for employeesLink provided.");
+                Console.WriteLine("No value for employees link provided.");
+                return;
             }
 
-            username = string.IsNullOrWhiteSpace(username) ? configuration.GetString("coscine/global/organizations/rwth/connection_data/username") : username;
-            if (string.IsNullOrWhiteSpace(username))
+            options.Username = string.IsNullOrWhiteSpace(options.Username) ?
+                configuration.GetString("coscine/global/organizations/rwth/connection_data/username") : options.Username;
+            if (string.IsNullOrWhiteSpace(options.Username))
             {
                 Console.WriteLine("No value for username provided.");
+                return;
             }
 
-            password = string.IsNullOrWhiteSpace(password) ? configuration.GetString("coscine/global/organizations/rwth/connection_data/password") : password;
-            if (string.IsNullOrWhiteSpace(password))
+            options.Password = string.IsNullOrWhiteSpace(options.Password) ?
+                configuration.GetString("coscine/global/organizations/rwth/connection_data/password") : options.Password;
+            if (string.IsNullOrWhiteSpace(options.Password))
             {
                 Console.WriteLine("No value for password provided.");
+                return;
             }
 
-            _httpClient = new HttpClient();
             // Create a basic Authentication header
-            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")));
+            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{options.Username}:{options.Password}")));
 
             var previousEmployeeCountString = configuration.GetString("coscine/global/organizations/rwth/files/employees/number_of_entries");
             var previousEmployeeCount = previousEmployeeCountString != null ? int.Parse(previousEmployeeCountString) : -1;
@@ -168,8 +120,8 @@ namespace Coscine.OrganizationLoader
             {
                 Console.WriteLine("Downloading...");
 
-                organizationsString = DownloadExport(organizationsLink);
-                employeesString = DownloadExport(employeesLink);
+                organizationsString = DownloadExport(options.OrganizationsLink);
+                employeesString = DownloadExport(options.EmployeesLink);
             }
             catch (Exception e)
             {
@@ -182,18 +134,18 @@ namespace Coscine.OrganizationLoader
             var organizations = ParseOrganizations(organizationsString);
             var employees = LoadEmployees(employeesString, organizations);
 
-            if (!force)
+            if (!options.Force)
             {
                 Console.WriteLine("Checking...");
 
-                if (previousEmployeeCount > 0 && Math.Abs(previousEmployeeCount - employees.Count()) > previousEmployeeCount * 0.1f)
+                if (previousEmployeeCount > 0 && Math.Abs(previousEmployeeCount - employees.Count) > previousEmployeeCount * 0.1f)
                 {
-                    Console.WriteLine($"To many employees changed! Previously: {previousEmployeeCount}, Now: {employees.Count()}, Difference: {Math.Abs(previousEmployeeCount - employees.Count())} or {((float)Math.Abs(previousEmployeeCount - employees.Count()) / previousEmployeeCount) * 100} %");
+                    Console.WriteLine($"To many employees changed! Previously: {previousEmployeeCount}, Now: {employees.Count}, Difference: {Math.Abs(previousEmployeeCount - employees.Count)} or {(float)Math.Abs(previousEmployeeCount - employees.Count) / previousEmployeeCount * 100} %");
                     return;
                 }
-                if (previousOrganizationsCount > 0 && Math.Abs(previousOrganizationsCount - organizations.Count()) > previousOrganizationsCount * 0.1f)
+                if (previousOrganizationsCount > 0 && Math.Abs(previousOrganizationsCount - organizations.Count) > previousOrganizationsCount * 0.1f)
                 {
-                    Console.WriteLine($"To many organizations changed! Previously: {previousOrganizationsCount}, Now: {organizations.Count()}, Difference: {Math.Abs(previousOrganizationsCount - organizations.Count())} or {((float)Math.Abs(previousOrganizationsCount - organizations.Count()) / previousOrganizationsCount) * 100} %");
+                    Console.WriteLine($"To many organizations changed! Previously: {previousOrganizationsCount}, Now: {organizations.Count}, Difference: {Math.Abs(previousOrganizationsCount - organizations.Count)} or {(float)Math.Abs(previousOrganizationsCount - organizations.Count) / previousOrganizationsCount * 100} %");
                     return;
                 }
             }
@@ -201,205 +153,209 @@ namespace Coscine.OrganizationLoader
             var organizationsSha = Sha256Hash(organizationsString);
             var employeesSha = Sha256Hash(employeesString);
 
-            if (!force && previousEmployeeSha != null && previousEmployeeSha == employeesSha && previousOrganizationsSha != null && previousOrganizationsSha == organizationsSha)
+            if (!options.Force && previousEmployeeSha != null && previousEmployeeSha == employeesSha && previousOrganizationsSha != null && previousOrganizationsSha == organizationsSha)
             {
                 Console.WriteLine("The sha of the exports has not changed.");
                 return;
             }
 
-            Console.WriteLine("Generating ttl file...");
+            Console.WriteLine("Generating .ttl file...");
 
-            var ttl = GenerateTurtle(organizations, employees, rorId);
+            var ttl = GenerateTurtle(organizations, employees, options.RorId);
 
-            var file = new FileInfo(output);
-            file.Directory.Create();
-            File.WriteAllText(output, ttl);
-            Console.WriteLine($"File written to {output}");
+            var file = new FileInfo(options.Output);
+            file.Directory?.Create();
+            File.WriteAllText(options.Output, ttl);
+            Console.WriteLine($"File written to {options.Output}");
 
             Console.WriteLine("Saving to Consul...");
 
-            configuration.Put("coscine/global/organizations/rwth/files/organizations/number_of_entries", organizations.Count().ToString());
-            configuration.Put("coscine/global/organizations/rwth/files/employees/number_of_entries", employees.Count().ToString());
+            configuration.Put("coscine/global/organizations/rwth/files/organizations/number_of_entries", organizations.Count.ToString());
+            configuration.Put("coscine/global/organizations/rwth/files/employees/number_of_entries", employees.Count.ToString());
             configuration.Put("coscine/global/organizations/rwth/files/organizations/sha", organizationsSha);
             configuration.Put("coscine/global/organizations/rwth/files/employees/sha", employeesSha);
 
             Console.WriteLine("Finished");
-        }
-
-        public static string Sha256Hash(string value)
+        })
+        .WithNotParsed(errs =>
         {
-            using (var hash = SHA256.Create())
-            {
-                return string.Concat(hash
-                  .ComputeHash(Encoding.UTF8.GetBytes(value))
-                  .Select(item => item.ToString("x2")));
-            }
-        }
+            Console.WriteLine(CommandLine.Text.HelpText.AutoBuild(parserResult));
+        });
+    }
 
-        public static List<Employee> LoadEmployees(string xml, Dictionary<string, Organization> organizations)
-        {
-            var employeeDocument = new XmlDocument();
+    public static string Sha256Hash(string value)
+    {
+        using var hash = SHA256.Create();
+        return string.Concat(hash
+          .ComputeHash(Encoding.UTF8.GetBytes(value))
+          .Select(item => item.ToString("x2")));
+    }
+
+    public static List<Employee> LoadEmployees(string xml, Dictionary<string, Organization> organizations)
+    {
+        var employeeDocument = new XmlDocument();
 
-            employeeDocument.LoadXml(xml);
+        employeeDocument.LoadXml(xml);
 
-            var employees = new List<Employee>();
+        var employees = new List<Employee>();
 
-            foreach (XmlNode node in employeeDocument.SelectNodes("/IDM_Exports/Employees/Employee"))
+        foreach (XmlNode node in employeeDocument.SelectNodes("/IDM_Exports/Employees/Employee"))
+        {
+            var employee = new Employee
             {
-                var employee = new Employee
-                {
-                    Surname = node["Surname"].InnerText?.Trim(),
-                    PreferredName = node["PreferredName"].InnerText?.Trim(),
-                    ID = node["ID"].InnerText?.Trim(),
-                    RONID = node["RONID"].InnerText?.Trim(),
-                    Memberships = node["OrganizationMemberships"]?.ChildNodes?.Cast<XmlNode>().Select(x => x["OrgId"].InnerText?.Trim()).ToList(),
-                    DegreePre = node["DegreePre"]?.InnerText,
-                    DegreePost = node["DegreePost"]?.InnerText,
-                    Ubpublications = node["Ubpublications"]?.InnerText?.Trim(),
-                    RoleAssignments = node["RoleAssignments"]?.ChildNodes?.Cast<XmlNode>().Select(x => new Role { RID = x["RID"].InnerText?.Trim(), OrgId = x["OrgId"].InnerText?.Trim() }).ToList(),
-
-                };
-
-                employees.Add(employee);
-                if (employee.Memberships != null)
-                {
-                    foreach (var orgId in employee.Memberships)
-                    {
-                        organizations[orgId].Members.Add(employee);
-                    }
-                }
-            }
+                Surname = node["Surname"]?.InnerText?.Trim(),
+                PreferredName = node["PreferredName"]?.InnerText?.Trim(),
+                ID = node["ID"]?.InnerText?.Trim(),
+                RONID = node["RONID"]?.InnerText?.Trim(),
+                Memberships = node["OrganizationMemberships"]?.ChildNodes?.Cast<XmlNode>().Select(x => x["OrgId"]?.InnerText?.Trim())?.ToList(),
+                DegreePre = node["DegreePre"]?.InnerText,
+                DegreePost = node["DegreePost"]?.InnerText,
+                Ubpublications = node["Ubpublications"]?.InnerText?.Trim(),
+                RoleAssignments = node["RoleAssignments"]?.ChildNodes?.Cast<XmlNode>().Select(x => new Role { RID = x["RID"]?.InnerText?.Trim(), OrgId = x["OrgId"]?.InnerText?.Trim() }).ToList(),
 
-            return employees;
-        }
+            };
 
-        public static string DownloadExport(string link)
-        {
-            using (var response = _httpClient.GetStringAsync(link))
+            employees.Add(employee);
+            if (employee.Memberships != null)
             {
-                return response.Result;
+                foreach (var orgId in employee.Memberships)
+                {
+                    organizations[orgId].Members.Add(employee);
+                }
             }
         }
 
-        public static Dictionary<string, Organization> ParseOrganizations(string xml)
-        {
-            var organizationDocument = new XmlDocument();
+        return employees;
+    }
+
+    public static string DownloadExport(string link)
+    {
+        using var response = _httpClient.GetStringAsync(link);
+        return response.Result;
+    }
 
-            organizationDocument.LoadXml(xml);
+    public static Dictionary<string, Organization> ParseOrganizations(string xml)
+    {
+        var organizationDocument = new XmlDocument();
 
-            var organizations = new Dictionary<string, Organization>();
+        organizationDocument.LoadXml(xml);
 
-            foreach (XmlNode node in organizationDocument.SelectNodes("/IDM_Exports/Organizations/Organization"))
-            {
-                organizations.Add(node["OrgId"].InnerText,
-                     new Organization
-                     {
-                         OrgId = node["OrgId"].InnerText?.Trim(),
-                         // IDM changed this to capital and might change it back. Keeps us safe for now.
-                         Name = (node["NAME"] ?? node["Name"]).InnerText?.Trim(),
-                         IKZ = node["IKZ"].InnerText?.Trim(),
-                         Abbreviation = node["Abbreviation"]?.InnerText?.Trim(),
-                         CMSLink = node["CMSLink"].InnerText?.Trim(),
-                     }
-                 );
-            }
+        var organizations = new Dictionary<string, Organization>();
 
-            return organizations;
+        foreach (XmlNode node in organizationDocument.SelectNodes("/IDM_Exports/Organizations/Organization"))
+        {
+            organizations.Add(node["OrgId"]?.InnerText,
+                 new Organization
+                 {
+                     OrgId = node["OrgId"]?.InnerText?.Trim(),
+                     // IDM changed this to capital and might change it back. Keeps us safe for now.
+                     Name = (node["NAME"] ?? node["Name"])?.InnerText?.Trim(),
+                     IKZ = node["IKZ"]?.InnerText?.Trim(),
+                     Abbreviation = node["Abbreviation"]?.InnerText?.Trim(),
+                     CMSLink = node["CMSLink"]?.InnerText?.Trim(),
+                 }
+             );
         }
 
-        public static string GenerateTurtle(Dictionary<string, Organization> organizations, List<Employee> employees, string rorId)
+        return organizations;
+    }
+
+    public static string GenerateTurtle(Dictionary<string, Organization> organizations, List<Employee> employees, string rorId)
+    {
+        // Disposed by streamWriter
+        var memoryStream = new MemoryStream();
+
+        using var streamWriter = new StreamWriter(memoryStream);
+        // Header
+        streamWriter.WriteLine($"@base <{rorId}> .");
+        streamWriter.WriteLine();
+        streamWriter.WriteLine(@"@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .");
+        streamWriter.WriteLine(@"@prefix org: <http://www.w3.org/ns/org#> .");
+        streamWriter.WriteLine(@"@prefix dcterms: <http://purl.org/dc/terms/> .");
+        streamWriter.WriteLine(@"@prefix foaf: <http://xmlns.com/foaf/0.1/> .");
+        streamWriter.WriteLine(@"@prefix coscineresource: <https://purl.org/coscine/terms/resource#> .");
+        streamWriter.WriteLine();
+        streamWriter.WriteLine($"<{rorId}>");
+        streamWriter.WriteLine(@"    dcterms:publisher <https://itc.rwth-aachen.de/> ;");
+        streamWriter.WriteLine(@"    dcterms:rights ""Copyright © 2023 IT Center, RWTH Aachen University"" ;");
+        streamWriter.WriteLine(@"    dcterms:title ""RWTH Aachen University""@en ;");
+        streamWriter.WriteLine();
+        streamWriter.WriteLine(@"    a org:FormalOrganization ;");
+        streamWriter.WriteLine(@"    rdfs:label ""RWTH Aachen University"" ;");
+
+        foreach (var organization in organizations.Values)
         {
-            // Disposed by streamWriter
-            var memoryStream = new MemoryStream();
+            streamWriter.WriteLine($"    org:hasUnit <{rorId}#{organization.OrgId}> ;");
+        }
 
-            using (var streamWriter = new StreamWriter(memoryStream))
-            {
-                // Header
-                streamWriter.WriteLine($"@base <{rorId}> .");
-                streamWriter.WriteLine();
-                streamWriter.WriteLine(@"@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .");
-                streamWriter.WriteLine(@"@prefix org: <http://www.w3.org/ns/org#> .");
-                streamWriter.WriteLine(@"@prefix dcterms: <http://purl.org/dc/terms/> .");
-                streamWriter.WriteLine(@"@prefix foaf: <http://xmlns.com/foaf/0.1/> .");
-                streamWriter.WriteLine(@"@prefix coscineresource: <https://purl.org/coscine/terms/resource#> .");
-                streamWriter.WriteLine();
-                streamWriter.WriteLine($"<{rorId}>");
-                streamWriter.WriteLine(@"    dcterms:publisher <https://itc.rwth-aachen.de/> ;");
-                streamWriter.WriteLine(@"    dcterms:rights ""Copyright © 2020 IT Center, RWTH Aachen University"" ;");
-                streamWriter.WriteLine(@"    dcterms:title ""RWTH Aachen University""@en ;");
-                streamWriter.WriteLine();
-                streamWriter.WriteLine(@"    a org:FormalOrganization ;");
-                streamWriter.WriteLine(@"    rdfs:label ""RWTH Aachen University"" ;");
-
-                foreach (var organization in organizations.Values)
-                {
-                    streamWriter.WriteLine($"    org:hasUnit <{rorId}#{organization.OrgId}> ;");
-                }
+        streamWriter.WriteLine(".");
 
-                streamWriter.WriteLine(".");
+        // Organizations
+        foreach (var organization in organizations.Values)
+        {
+            streamWriter.WriteLine($"<{rorId}#{organization.OrgId}>");
+            streamWriter.WriteLine($"   rdfs:label \"{organization.Name}\" ;");
+            streamWriter.WriteLine($"   org:identifier \"org-id:{organization.OrgId}\" ;");
+            streamWriter.WriteLine($"   org:identifier \"ikz:{organization.IKZ}\" ;");
+            streamWriter.WriteLine($"   a org:OrganizationalUnit ;");
+            streamWriter.WriteLine(".");
+        }
 
-                // Organizations
-                foreach (var organization in organizations.Values)
+        // Memberships
+        foreach (var employee in employees)
+        {
+            if (employee.Memberships != null)
+            {
+                foreach (var membership in employee.Memberships)
                 {
-                    streamWriter.WriteLine($"<{rorId}#{organization.OrgId}>");
-                    streamWriter.WriteLine($"   rdfs:label \"{organization.Name}\" ;");
-                    streamWriter.WriteLine($"   org:identifier \"org-id:{organization.OrgId}\" ;");
-                    streamWriter.WriteLine($"   org:identifier \"ikz:{organization.IKZ}\" ;");
-                    streamWriter.WriteLine($"   a org:OrganizationalUnit ;");
+                    streamWriter.WriteLine("[] a org:Membership ;");
+                    streamWriter.WriteLine($"    org:member <{rorId}#{employee.ID}> ;");
+                    streamWriter.WriteLine($"    org:organization <{rorId}#{membership}> ;");
                     streamWriter.WriteLine(".");
                 }
+            }
+        }
 
-                // Memberships
-                foreach (var employee in employees)
-                {
-                    if (employee.Memberships != null)
-                    {
-                        foreach (var membership in employee.Memberships)
-                        {
-                            streamWriter.WriteLine("[] a org:Membership ;");
-                            streamWriter.WriteLine($"    org:member <{rorId}#{employee.ID}> ;");
-                            streamWriter.WriteLine($"    org:organization <{rorId}#{membership}> ;");
-                            streamWriter.WriteLine(".");
-                        }
-                    }
-                }
+        // Persons
+        foreach (var employee in employees)
+        {
+            streamWriter.WriteLine($"<{rorId}#{employee.ID}>");
+            streamWriter.WriteLine($"    foaf:name \"{employee.PreferredName} {employee.Surname}\" ;");
+            streamWriter.WriteLine($"    foaf:givenName \"{employee.PreferredName}\" ;");
+            streamWriter.WriteLine($"    foaf:familyName \"{employee.Surname}\" ;");
+            streamWriter.WriteLine($"    foaf:openId \"{employee.ID}\" ;");
+            streamWriter.WriteLine($"    a foaf:Person ;");
+            streamWriter.WriteLine(".");
+        }
 
-                // Persons
-                foreach (var employee in employees)
-                {
-                    streamWriter.WriteLine($"<{rorId}#{employee.ID}>");
-                    streamWriter.WriteLine($"    foaf:name \"{employee.PreferredName} {employee.Surname}\" ;");
-                    streamWriter.WriteLine($"    foaf:givenName \"{employee.PreferredName}\" ;");
-                    streamWriter.WriteLine($"    foaf:familyName \"{employee.Surname}\" ;");
-                    streamWriter.WriteLine($"    foaf:openId \"{employee.ID}\" ;");
-                    streamWriter.WriteLine($"    a foaf:Person ;");
-                    streamWriter.WriteLine(".");
-                }
+        // Default Quoting
+        foreach (var resourceType in _resourceTypes)
+        {
+            streamWriter.WriteLine($"<{rorId}> coscineresource:typeSpecification [");
+            streamWriter.WriteLine($@"    coscineresource:type <https://purl.org/coscine/terms/resource/types#{resourceType.Name}>;");
+            if (resourceType.HasQuota)
+            {
+                streamWriter.WriteLine($@"    coscineresource:defaultQuota ""{resourceType.Quota}"";");
+                streamWriter.WriteLine($@"    coscineresource:defaultMaxQuota ""{resourceType.MaxQuota}"";");
+            }
+            streamWriter.WriteLine("].");
+        }
 
-                // Default Quoting
-                foreach (var resourceType in _resourceTypes)
-                {
-                    streamWriter.WriteLine($"<{rorId}> coscineresource:typeSpecification [");
-                    streamWriter.WriteLine($@"    coscineresource:type <https://purl.org/coscine/terms/resource/types#{resourceType.Name}>;");
-                    if (resourceType.HasQuota)
-                    {
-                        streamWriter.WriteLine($@"    coscineresource:defaultQuota ""{resourceType.Quota}"";");
-                        streamWriter.WriteLine($@"    coscineresource:defaultMaxQuota ""{resourceType.MaxQuota}"";");
-                    }
-                    streamWriter.WriteLine("].");
-                }
+        // Ror to entity mapping
+        foreach (var organizationMapping in _organizationMappings)
+        {
+            // Specs require the org identifier to be a literal, even if it is an url.
+            streamWriter.WriteLine($@"<{organizationMapping.RorId}> org:identifier ""{organizationMapping.EntityId}"" .");
+        }
 
-                // Ror to entity mapping
-                foreach (var organizationMapping in _organizationMappings)
-                {
-                    // Specs require the org identifier to be a literal, even if it is an url.
-                    streamWriter.WriteLine($@"<{organizationMapping.RorId}> org:identifier ""{organizationMapping.EntityId}"" .");
-                }
+        // Contact Information
+        streamWriter.WriteLine($"<{rorId}> coscineresource:contactInformation [");
+        streamWriter.WriteLine(@"    foaf:name ""Service Desk"";");
+        streamWriter.WriteLine(@"    foaf:mbox <mailto:servicedesk@rwth-aachen.de>;");
+        streamWriter.WriteLine("].");
 
-                streamWriter.Flush();
+        streamWriter.Flush();
 
-                return Encoding.UTF8.GetString(memoryStream.ToArray());
-            }
-        }
+        return Encoding.UTF8.GetString(memoryStream.ToArray());
     }
-}
+}
\ No newline at end of file
diff --git a/src/OrganizationLoader/Properties/AssemblyInfo.cs b/src/OrganizationLoader/Properties/AssemblyInfo.cs
deleted file mode 100644
index d6d64cbbcd4f451a838b3b3743ee2bb36b4dc2a5..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by Cake.
-// </auto-generated>
-//------------------------------------------------------------------------------
-using System.Reflection;
-
-[assembly: AssemblyTitle("OrganizationLoader")]
-[assembly: AssemblyDescription("OrganizationLoader is a part of the CoScInE group.")]
-[assembly: AssemblyCompany("IT Center, RWTH Aachen University")]
-[assembly: AssemblyProduct("OrganizationLoader")]
-[assembly: AssemblyVersion("1.2.1")]
-[assembly: AssemblyFileVersion("1.2.1")]
-[assembly: AssemblyInformationalVersion("1.2.1-product-1414-fhp0003")]
-[assembly: AssemblyCopyright("2021 IT Center, RWTH Aachen University")]
-
diff --git a/src/OrganizationLoader/Role.cs b/src/OrganizationLoader/Role.cs
deleted file mode 100644
index 72c71bf54335a05f618b266211b1a2df659365c7..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/Role.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Coscine.OrganizationLoader
-{
-    public class Role
-    {
-        public string RID { get; set; }
-        public string OrgId { get; set; }
-    }
-}
diff --git a/src/OrganizationLoader/Utility/CommandLineOptions.cs b/src/OrganizationLoader/Utility/CommandLineOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e1a3f5b7e8cb558212c2bf18cdfca2f17cb3fac
--- /dev/null
+++ b/src/OrganizationLoader/Utility/CommandLineOptions.cs
@@ -0,0 +1,30 @@
+using CommandLine;
+
+namespace OrganizationLoader.Utility;
+
+public class CommandLineOptions
+{
+    [Option('f', "force", Required = false, HelpText = "Skip checks for too many or no changes in the exports.")]
+    public bool Force { get; set; }
+
+    [Option('u', "username", Required = false, HelpText = "Username for the export. If none is provided, the consul value is used.")]
+    public string Username { get; set; } = null!;
+
+    [Option('p', "password", Required = false, HelpText = "Password for the export. If none is provided, the consul value is used.")]
+    public string Password { get; set; } = null!;
+
+    [Option("organizationsLink", Required = false, HelpText = "Link for the organizations export. If none is provided, the consul value is used.")]
+    public string OrganizationsLink { get; set; } = null!;
+
+    [Option("employeesLink", Required = false, HelpText = "Link for the employee export. If none is provided, the consul value is used.")]
+    public string EmployeesLink { get; set; } = null!;
+
+    [Option("rorId", Required = false, HelpText = "The RWTH ror Id. If none is provided, the consul value is used.")]
+    public string RorId { get; set; } = null!;
+
+    [Option('o', "output", Required = true, HelpText = "Output for the generated file.")]
+    public string Output { get; set; } = null!;
+
+    [Option('h', "help", Required = false, HelpText = "Show help and exit.")]
+    public bool ShowHelp { get; set; }
+}
\ No newline at end of file
diff --git a/src/OrganizationLoader/Utility/Employee.cs b/src/OrganizationLoader/Utility/Employee.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3014ab1dd14c40188e2beffa239f795f78febdd8
--- /dev/null
+++ b/src/OrganizationLoader/Utility/Employee.cs
@@ -0,0 +1,15 @@
+namespace OrganizationLoader.Utility
+{
+    public class Employee
+    {
+        public string? Surname { get; set; }
+        public string? PreferredName { get; set; }
+        public string? ID { get; set; }
+        public string? RONID { get; set; }
+        public List<string>? Memberships { get; set; }
+        public string? DegreePre { get; set; }
+        public string? DegreePost { get; set; }
+        public string? Ubpublications { get; set; }
+        public List<Role>? RoleAssignments { get; set; }
+    }
+}
diff --git a/src/OrganizationLoader/Utility/Organization.cs b/src/OrganizationLoader/Utility/Organization.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d6928d10ea5f838d4ab3a69c3d18f6636bbf6fc
--- /dev/null
+++ b/src/OrganizationLoader/Utility/Organization.cs
@@ -0,0 +1,13 @@
+namespace OrganizationLoader.Utility
+{
+    public class Organization
+    {
+        public string? OrgId { get; set; }
+        public string? Name { get; set; }
+        public string? IKZ { get; set; }
+        public string? Abbreviation { get; set; }
+        public string? CMSLink { get; set; }
+
+        public List<Employee>? Members { get; set; } = new List<Employee>();
+    }
+}
diff --git a/src/OrganizationLoader/Utility/OrganizationMapping.cs b/src/OrganizationLoader/Utility/OrganizationMapping.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cd6c1d57a6feb40a89443276eb86a4b51617205
--- /dev/null
+++ b/src/OrganizationLoader/Utility/OrganizationMapping.cs
@@ -0,0 +1,8 @@
+namespace OrganizationLoader.Utility
+{
+    public class OrganizationMapping
+    {
+        public string? EntityId { get; set; }
+        public string? RorId { get; set; }
+    }
+}
diff --git a/src/OrganizationLoader/ResourceType.cs b/src/OrganizationLoader/Utility/ResourceType.cs
similarity index 84%
rename from src/OrganizationLoader/ResourceType.cs
rename to src/OrganizationLoader/Utility/ResourceType.cs
index 89d91fb55f28d6e5598ac75ca2a6bcd32d66b0a1..0c88ca541ee0a1513d15c2bd1729834c99c6b692 100644
--- a/src/OrganizationLoader/ResourceType.cs
+++ b/src/OrganizationLoader/Utility/ResourceType.cs
@@ -1,4 +1,4 @@
-namespace Coscine.OrganizationLoader
+namespace OrganizationLoader.Utility
 {
     public class ResourceType
     {
diff --git a/src/OrganizationLoader/Utility/Role.cs b/src/OrganizationLoader/Utility/Role.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cbd89734b62015ca3ce06b7354df401ab9f4909
--- /dev/null
+++ b/src/OrganizationLoader/Utility/Role.cs
@@ -0,0 +1,8 @@
+namespace OrganizationLoader.Utility
+{
+    public class Role
+    {
+        public string? RID { get; set; }
+        public string? OrgId { get; set; }
+    }
+}
diff --git a/src/OrganizationLoader/packages.config b/src/OrganizationLoader/packages.config
deleted file mode 100644
index 1938e2177d4ea907c314c589e9cc6f39b48e3e86..0000000000000000000000000000000000000000
--- a/src/OrganizationLoader/packages.config
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Consul" version="1.6.1.1" targetFramework="net461" />
-  <package id="Coscine.Configuration" version="2.0.0" targetFramework="net461" />
-  <package id="Coscine.Database" version="2.3.0" targetFramework="net461" />
-  <package id="dotNetRDF" version="2.5.1" targetFramework="net461" />
-  <package id="dotNetRDF.Data.Virtuoso" version="2.5.1" targetFramework="net461" />
-  <package id="EntityFramework" version="6.4.4" targetFramework="net461" />
-  <package id="HtmlAgilityPack" version="1.11.24" targetFramework="net461" />
-  <package id="Inflector.NetStandard" version="1.2.2" targetFramework="net461" />
-  <package id="LibGit2Sharp" version="0.26.2" targetFramework="net461" />
-  <package id="LibGit2Sharp.NativeBinaries" version="2.0.306" targetFramework="net461" />
-  <package id="linq2db" version="3.0.1" targetFramework="net461" />
-  <package id="linq2db.SqlServer" version="3.0.1" targetFramework="net461" />
-  <package id="linq2db.t4models" version="3.0.1" targetFramework="net461" />
-  <package id="LinqKit" version="1.1.23" targetFramework="net461" />
-  <package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.1" targetFramework="net461" />
-  <package id="Microsoft.Bcl.HashCode" version="1.1.1" targetFramework="net461" />
-  <package id="Microsoft.Data.SqlClient" version="1.1.3" targetFramework="net461" />
-  <package id="Microsoft.Data.SqlClient.SNI" version="1.1.0" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Abstractions" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Analyzers" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.Relational" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.EntityFrameworkCore.SqlServer" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Caching.Abstractions" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Caching.Memory" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Configuration" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Configuration.Abstractions" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Configuration.Binder" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.DependencyInjection" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Logging" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Logging.Abstractions" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Options" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Extensions.Primitives" version="3.1.12" targetFramework="net461" />
-  <package id="Microsoft.Identity.Client" version="3.0.8" targetFramework="net461" />
-  <package id="Microsoft.IdentityModel.JsonWebTokens" version="5.5.0" targetFramework="net461" />
-  <package id="Microsoft.IdentityModel.Logging" version="5.5.0" targetFramework="net461" />
-  <package id="Microsoft.IdentityModel.Protocols" version="5.5.0" targetFramework="net461" />
-  <package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.5.0" targetFramework="net461" />
-  <package id="Microsoft.IdentityModel.Tokens" version="5.5.0" targetFramework="net461" />
-  <package id="NDesk.Options" version="0.2.1" targetFramework="net461" />
-  <package id="Newtonsoft.Json" version="12.0.3" targetFramework="net461" />
-  <package id="OpenLink.Data.Virtuoso" version="7.20.3214.1" targetFramework="net461" />
-  <package id="System.Buffers" version="4.5.1" targetFramework="net461" />
-  <package id="System.Collections.Immutable" version="1.7.1" targetFramework="net461" />
-  <package id="System.ComponentModel.Annotations" version="4.7.0" targetFramework="net461" />
-  <package id="System.Data.Common" version="4.3.0" targetFramework="net461" />
-  <package id="System.Diagnostics.DiagnosticSource" version="4.7.1" targetFramework="net461" />
-  <package id="System.IdentityModel.Tokens.Jwt" version="5.5.0" targetFramework="net461" />
-  <package id="System.Memory" version="4.5.4" targetFramework="net461" />
-  <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
-  <package id="System.Runtime.CompilerServices.Unsafe" version="4.7.1" targetFramework="net461" />
-  <package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net461" />
-  <package id="VDS.Common" version="1.10.0" targetFramework="net461" />
-</packages>
\ No newline at end of file
diff --git a/tools/packages.config b/tools/packages.config
deleted file mode 100644
index 0328dfb13c9a9b74920150725d27cd0e231c4815..0000000000000000000000000000000000000000
--- a/tools/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-    <package id="Cake" version="1.0.0" />
-</packages>