diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index f1a55dc3f0acb1031982196149da8edcb1a2d6ef..fe7a8b12b998dab13c95cce183eec95e387ae6bc 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,23 +1,17 @@
-// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
-// https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet
 {
 	"name": "Puppet Development Kit (Community)",
 	"dockerFile": "Dockerfile",
 
-	// Set *default* container specific settings.json values on container create.
 	"settings": {
-		"terminal.integrated.shell.linux": "/bin/bash"
+		"terminal.integrated.profiles.linux": {
+			"bash": {
+				"path": "bash",
+			}
+		}
 	},
 
-	// Add the IDs of extensions you want installed when the container is created.
 	"extensions": [
 		"puppet.puppet-vscode",
 		"rebornix.Ruby"
 	]
-
-	// Use 'forwardPorts' to make a list of ports inside the container available locally.
-	// "forwardPorts": [],
-
-	// Use 'postCreateCommand' to run commands after the container is created.
-	// "postCreateCommand": "pdk --version",
 }
diff --git a/.rubocop.yml b/.rubocop.yml
index 8f782e741528905cd59743f73283f8a39e9bf210..31e8248ff813e956702d5c67844aeb0e2affc917 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -4,7 +4,7 @@ require:
 - rubocop-rspec
 AllCops:
   DisplayCopNames: true
-  TargetRubyVersion: '2.4'
+  TargetRubyVersion: '2.5'
   Include:
   - "**/*.rb"
   Exclude:
diff --git a/Gemfile b/Gemfile
index 18272fd72e8b95feb3fe64e34a51a9b75a7af794..0057a1722c6e185755de3802eef2da5c724db7c7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,28 +13,39 @@ def location_for(place_or_version, fake_version = nil)
   end
 end
 
-ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments
-minor_version = ruby_version_segments[0..1].join('.')
-
 group :development do
-  gem "json", '= 2.0.4',                                         require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
-  gem "json", '= 2.1.0',                                         require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
-  gem "json", '= 2.3.0',                                         require: false if Gem::Requirement.create(['>= 2.7.0', '< 2.8.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
-  gem "puppet-module-posix-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby]
-  gem "puppet-module-posix-dev-r#{minor_version}", '~> 1.0',     require: false, platforms: [:ruby]
-  gem "puppet-module-win-default-r#{minor_version}", '~> 1.0',   require: false, platforms: [:mswin, :mingw, :x64_mingw]
-  gem "puppet-module-win-dev-r#{minor_version}", '~> 1.0',       require: false, platforms: [:mswin, :mingw, :x64_mingw]
-  gem "puppet-lint-absolute_classname-check", '3.0.1',           require: false
-  gem "puppet-lint-absolute_template_path", '1.0.1',             require: false
-  gem "puppet-lint-empty_trailing_lines", '0.0.1',               require: false
-  gem "puppet-lint-file_ensure-check", '1.0.0',                  require: false
-  gem "puppet-lint-strict_indent-check", '2.0.8',                require: false
-  gem "puppet-lint-trailing_comma-check", '0.4.2',               require: false
-  gem "puppet-lint-unquoted_string-check", '2.1.0',              require: false
+  gem "json", '= 2.1.0',                                  require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+  gem "json", '= 2.3.0',                                  require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+  gem "json", '= 2.5.1',                                  require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+  gem "json", '= 2.6.1',                                  require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+  gem "json", '= 2.6.3',                                  require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup))
+  gem "voxpupuli-puppet-lint-plugins", '~> 3.1',          require: false
+  gem "facterdb", '~> 1.18',                              require: false
+  gem "metadata-json-lint", '>= 2.0.2', '< 4.0.0',        require: false
+  gem "puppetlabs_spec_helper", '>= 3.0.0', '< 5.0.0',    require: false
+  gem "rspec-puppet-facts", '~> 2.0',                     require: false
+  gem "codecov", '~> 0.2',                                require: false
+  gem "dependency_checker", '~> 0.2',                     require: false
+  gem "parallel_tests", '~> 3.4',                         require: false
+  gem "pry", '~> 0.10',                                   require: false
+  gem "simplecov-console", '~> 0.5',                      require: false
+  gem "puppet-debugger", '~> 1.0',                        require: false
+  gem "rubocop", '= 1.6.1',                               require: false
+  gem "rubocop-performance", '= 1.9.1',                   require: false
+  gem "rubocop-rspec", '= 2.0.1',                         require: false
+  gem "rb-readline", '= 0.5.5',                           require: false, platforms: [:mswin, :mingw, :x64_mingw]
+  gem "concurrent-ruby", '< 1.2.0',                       require: false
+  gem "puppet-lint-absolute_classname-check", '>= 3.0.1', require: false
+  gem "puppet-lint-absolute_template_path", '>= 1.0.1',   require: false
+  gem "puppet-lint-empty_trailing_lines", '>= 0.0.1',     require: false
+  gem "puppet-lint-file_ensure-check", '>= 1.0.0',        require: false
+  gem "puppet-lint-strict_indent-check", '>= 2.0.8',      require: false
+  gem "puppet-lint-trailing_comma-check", '>= 0.4.3',     require: false
+  gem "puppet-lint-unquoted_string-check", '>= 2.1.0',    require: false
 end
 group :system_tests do
-  gem "puppet-module-posix-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby]
-  gem "puppet-module-win-system-r#{minor_version}", '~> 1.0',   require: false, platforms: [:mswin, :mingw, :x64_mingw]
+  gem "puppet_litmus", '< 1.0.0', require: false, platforms: [:ruby]
+  gem "serverspec", '~> 2.41',    require: false
 end
 
 puppet_version = ENV['PUPPET_GEM_VERSION']
diff --git a/Rakefile b/Rakefile
index 2906c15babbebe65d3ed29e72a07328609fefe8e..0f8754eb61e400db1d117cad5026f06d3ba6ff89 100644
--- a/Rakefile
+++ b/Rakefile
@@ -43,6 +43,7 @@ end
 
 PuppetLint.configuration.send('disable_relative')
 
+
 if Bundler.rubygems.find_name('github_changelog_generator').any?
   GitHubChangelogGenerator::RakeTask.new :changelog do |config|
     raise "Set CHANGELOG_GITHUB_TOKEN environment variable eg 'export CHANGELOG_GITHUB_TOKEN=valid_token_here'" if Rake.application.top_level_tasks.include? "changelog" and ENV['CHANGELOG_GITHUB_TOKEN'].nil?
diff --git a/manifests/aes_sw.pp b/manifests/aes_sw.pp
index a042f0011bfbc8be3d2fd28a6e928117bcc4e1dc..2bfa4847928646d0c2d8eb6d214437a0bbcfbd51 100644
--- a/manifests/aes_sw.pp
+++ b/manifests/aes_sw.pp
@@ -1,5 +1,4 @@
 class aes::aes_sw {
-
   $examadm_user = examadm
   $examadm_group = $examadm_user
   $examadm_home = "/home/${examadm_user}"
@@ -37,11 +36,12 @@ class aes::aes_sw {
 
   file { "${examadm_home}/.ssh/authorized_keys":
     ensure  => file,
-    mode   => '0600',
-    owner  => $examadm_user,
-    group  => $examadm_group,
+    mode    => '0600',
+    owner   => $examadm_user,
+    group   => $examadm_group,
     content => @(SSHPUBKEY),
-command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookback 90 --lookahead 180",no-pty,no-user-rc,no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJW4LP0av20r7lPXNgsftF9oaAXK41AvHyuHwybciZC/QBfTcmYif83563cTg0OzR/p+OSobiDM0odaaFYtP/8xbuVRz87X5bGYm2m8yHHqPxobHkT5g/faMkl9Fef+Al4EsT5tiaYMOhG2lj8XRYuwAb7qjoz3FFbs8TEPE7Sv+4BUCCH94taCuNYLXSxN1EXvw7VW6Ld5QXRFP53l2QUeTqE9oSii3BVrXlqqrLvNV/7nwdwyse4uhff4QrM9o4oc9FaQr8PLlPGxdlbSfIQJMVzHGpeDu0WLw+NqtLO1hsdlvQm7GrT/v8N7GJNKlsvhwnwUuMhTrB0yPMbbub1 klaar36@upp
+      command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookback 90 --lookahead 180",no-pty,no-user-rc,no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJW4LP0av20r7lPXNgsftF9oaAXK41AvHyuHwybciZC/QBfTcmYif83563cTg0OzR/p+OSobiDM0odaaFYtP/8xbuVRz87X5bGYm2m8yHHqPxobHkT5g/faMkl9Fef+Al4EsT5tiaYMOhG2lj8XRYuwAb7qjoz3FFbs8TEPE7Sv+4BUCCH94taCuNYLXSxN1EXvw7VW6Ld5QXRFP53l2QUeTqE9oSii3BVrXlqqrLvNV/7nwdwyse4uhff4QrM9o4oc9FaQr8PLlPGxdlbSfIQJMVzHGpeDu0WLw+NqtLO1hsdlvQm7GrT/v8N7GJNKlsvhwnwUuMhTrB0yPMbbub1 klaar36@upp
+      command="/home/examadm/tal-cli/source/scripts/tal-export.py --written --format ics --lookback 90 --lookahead 180",no-pty,no-user-rc,no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILZ8aEAXw0tRcYrk1aqldepuC6tmdUYZuM270QdDF79o tal written exams to ics
     | SSHPUBKEY
   }
 
@@ -51,7 +51,7 @@ command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookb
     group   => root,
     mode    => '0644',
     content => @(LOGINSERVICE),
-    [Unit]
+          [Unit]
     Description=AES Login server
     After=network.target
 
@@ -78,7 +78,7 @@ command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookb
     group   => root,
     mode    => '0644',
     content => @(MSSERVICE),
-    [Unit]
+          [Unit]
     Description=AES Exam server
     After=network.target
 
@@ -99,7 +99,7 @@ command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookb
     group   => root,
     mode    => '0700',
     content => @(MSCRON),
-    #!/bin/sh
+          #!/bin/sh
     /usr/bin/systemctl restart aes_ms
     | MSCRON
   }
@@ -110,7 +110,7 @@ command="/home/examadm/tal-cli/source/scripts/tal-export.py --format ics --lookb
     group   => root,
     mode    => '0700',
     content => @(MSCRON),
-    #!/bin/sh
+          #!/bin/sh
     /usr/bin/systemctl restart aes_login
     | MSCRON
   }
diff --git a/manifests/auth.pp b/manifests/auth.pp
index 564425af99a318a55dd8c1c8e9a65770a445daed..ae5ba62684f4ebce9b72e35671886bdb0948a2be 100644
--- a/manifests/auth.pp
+++ b/manifests/auth.pp
@@ -1,8 +1,7 @@
-class aes::auth(
+class aes::auth (
   Optional[String] $keytab_production = undef,
   Optional[String] $keytab_devel = undef
 ) {
-
   $auth_user = auth
   $auth_group = $auth_user
   $auth_home = "/srv/${auth_user}"
@@ -47,7 +46,7 @@ class aes::auth(
     comment    => 'Authentication server for AES',
     managehome => false,
     membership => inclusive,
-    groups     => [ 'aes_local_auth' ],
+    groups     => ['aes_local_auth'],
     system     => true,
     shell      => '/sbin/nologin',
   }
@@ -110,7 +109,7 @@ class aes::auth(
 
   exec { 'update-auth-repo' :
     command     => "/opt/utils/update_repo.sh ${auth_home}/src https://oauth2:F-agHaRXCdyFy38q4c-N@gitlab.liu.se/upp-aes/communication.git ${server_type}",
-    environment => [ "REPO_USER=${auth_user}", "REPO_GROUP=${auth_group}", "REPO_ON_UPDATE=${auth_home}/on_update.sh" ],
+    environment => ["REPO_USER=${auth_user}", "REPO_GROUP=${auth_group}", "REPO_ON_UPDATE=${auth_home}/on_update.sh"],
     # This command will need to run "on_update" as root in order to restart the service.
     user        => root,
     group       => root,
diff --git a/manifests/auth_keydb.pp b/manifests/auth_keydb.pp
index fef8c92d8b5a26006ee4661080cd53cbd473f42a..f7a0c5a130b1f91e8ba1cdd5d0cc76dd7ca48a5e 100644
--- a/manifests/auth_keydb.pp
+++ b/manifests/auth_keydb.pp
@@ -1,5 +1,4 @@
 class aes::auth_keydb {
-
   $keydb_user = auth_keydb
   $keydb_group = $keydb_user
   $keydb_home = "/srv/${keydb_user}"
@@ -20,7 +19,7 @@ class aes::auth_keydb {
     comment    => 'Authentication server for AES',
     managehome => false,
     membership => inclusive,
-    groups     => [ 'aes_local_auth' ],
+    groups     => ['aes_local_auth'],
     system     => true,
     shell      => '/sbin/nologin',
   }
@@ -50,7 +49,7 @@ class aes::auth_keydb {
 
   exec { 'update-keydb-repo' :
     command     => "/opt/utils/update_repo.sh ${keydb_home}/src https://oauth2:F-agHaRXCdyFy38q4c-N@gitlab.liu.se/upp-aes/communication.git ${server_type}",
-    environment => [ "REPO_USER=${keydb_user}", "REPO_GROUP=${keydb_group}", "REPO_ON_UPDATE=${keydb_home}/on_update.sh" ],
+    environment => ["REPO_USER=${keydb_user}", "REPO_GROUP=${keydb_group}", "REPO_ON_UPDATE=${keydb_home}/on_update.sh"],
     # This command will need to run "on_update" as root in order to restart the service.
     user        => root,
     group       => root,
@@ -76,4 +75,4 @@ class aes::auth_keydb {
   service { 'aes_temp_userdb' :
     ensure => 'running',
   }
-}
\ No newline at end of file
+}
diff --git a/manifests/broker.pp b/manifests/broker.pp
index d01596fdd15704125f4070315dd9c67bcd33d009..33724401235d0f0f36adee8374d29d9e8c76ac70 100644
--- a/manifests/broker.pp
+++ b/manifests/broker.pp
@@ -1,5 +1,4 @@
 class aes::broker {
-
   $broker_user = broker
   $broker_group = $broker_user
   $broker_home = "/srv/${broker_user}"
@@ -90,7 +89,7 @@ class aes::broker {
 
   exec { 'update-broker-repo' :
     command     => "/opt/utils/update_repo.sh ${broker_home}/src https://oauth2:F-agHaRXCdyFy38q4c-N@gitlab.liu.se/upp-aes/communication.git ${server_type}",
-    environment => [ "REPO_USER=${broker_user}", "REPO_GROUP=${broker_group}", "REPO_ON_UPDATE=${broker_home}/on_update.sh" ],
+    environment => ["REPO_USER=${broker_user}", "REPO_GROUP=${broker_group}", "REPO_ON_UPDATE=${broker_home}/on_update.sh"],
     # This command will need to run "on_update" as root in order to restart the service.
     user        => root,
     group       => root,
diff --git a/manifests/examfiles.pp b/manifests/examfiles.pp
index 15eaf2492c9c35b8ae8828bf0596d449b9b3b2f6..6571ba070d5e7a67871e4f02180201051baaefa3 100644
--- a/manifests/examfiles.pp
+++ b/manifests/examfiles.pp
@@ -1,5 +1,4 @@
 class aes::examfiles {
-
   include users::micis03
   include users::jondy94
   include users::andma54
@@ -32,5 +31,4 @@ class aes::examfiles {
     owner  => root,
     group  => liuitdrs,
   }
-
 }
diff --git a/manifests/init.pp b/manifests/init.pp
index 4165103fac70334202fbf9be7a4e0a2972615cca..1e5903418e2475f2f8bb6fc9ec4ae8f17bc6f21e 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -108,7 +108,7 @@ class aes {
 
   ::server_firewall::rules_file { '45-permit_squid.rules':
     content => @(EOF),
-    service squid is tcp/3128
+          service squid is tcp/3128
     service sclogin is tcp/23431
     service aesmsi is tcp/23816
     service aesmso is tcp/23817
@@ -123,5 +123,4 @@ class aes {
     end policy
     |-EOF
   }
-
 }
diff --git a/manifests/latex.pp b/manifests/latex.pp
index a60733369c86a233fb8a11a24b868bea9e68fb6b..e2d1c8be03fd2deb50bd6b2be5f1a5dd5a839d93 100644
--- a/manifests/latex.pp
+++ b/manifests/latex.pp
@@ -1,5 +1,4 @@
 class aes::latex {
-
   package {
     [
       'texlive',
@@ -15,6 +14,4 @@ class aes::latex {
     ]:
       ensure  => installed,
   }
-
-
 }
diff --git a/manifests/opendsa.pp b/manifests/opendsa.pp
index c54b242937a39f17e94bab8793970ba7ee90265b..c2e623df5b1140a1f771465e4d94317e29ff4ac3 100644
--- a/manifests/opendsa.pp
+++ b/manifests/opendsa.pp
@@ -1,5 +1,4 @@
 class aes::opendsa {
-
   $opendsa_user = opendsa
   $opendsa_group = $opendsa_user
   $opendsa_home = "/srv/${opendsa_user}"
@@ -41,7 +40,7 @@ class aes::opendsa {
 
   exec { 'update-repo':
     command     => "/opt/utils/update_repo.sh ${opendsa_home}/OpenDSA https://oauth2:taNPRZid9Hv6jJtdW_T8@gitlab.liu.se/opendsa/OpenDSA.git exam",
-    environment => [ "REPO_USER=${opendsa_user}", "REPO_GROUP=${opendsa_group}", "REPO_ON_UPDATE=${opendsa_home}/on_update.sh" ],
+    environment => ["REPO_USER=${opendsa_user}", "REPO_GROUP=${opendsa_group}", "REPO_ON_UPDATE=${opendsa_home}/on_update.sh"],
     # This command will need to run "on_update" as root in order to restart the service.
     user        => root,
     group       => root,
@@ -63,5 +62,4 @@ class aes::opendsa {
   }
 
   # Ändra TDDD86-raden i rules.d/opendsa till "TDDD86[AB]_191219"
-
 }
diff --git a/manifests/squid_filter.pp b/manifests/squid_filter.pp
index bb4012356aa4c1fa4cfa9a4e1a13e1a9f8689e95..3e64c0cef8535ded5a578b063845e100e01f54d4 100644
--- a/manifests/squid_filter.pp
+++ b/manifests/squid_filter.pp
@@ -1,5 +1,4 @@
 class aes::squid_filter {
-
   package { 'squid' :
     ensure => 'present',
   }
@@ -65,5 +64,4 @@ class aes::squid_filter {
     ensure => 'running',
     enable => true,
   }
-
 }
diff --git a/manifests/tal_cli.pp b/manifests/tal_cli.pp
index dfc6b2c937e9d8bd4fce3290d67e9a0d1e67d164..253226855e78ea74ef344b5fa73e8d2a88dbc736 100644
--- a/manifests/tal_cli.pp
+++ b/manifests/tal_cli.pp
@@ -1,7 +1,6 @@
-class aes::tal_cli(
+class aes::tal_cli (
   Optional[String] $credentials = undef
 ) {
-
   file { '/home/examadm/tal-cli' :
     ensure => directory,
     owner  => examadm,
@@ -43,9 +42,30 @@ class aes::tal_cli(
 
   exec { 'update-tal-repo' :
     command     => '/opt/utils/update_repo.sh /home/examadm/tal-cli/source https://oauth2:glpat-bfpVssm_zFmt1YRW7cLz@gitlab.liu.se/upp-aes/tal-cli.git master',
-    environment => [ 'REPO_ON_UPDATE=/home/examadm/tal-cli/on_update.sh' ],
+    environment => ['REPO_ON_UPDATE=/home/examadm/tal-cli/on_update.sh'],
     user        => examadm,
     group       => examadm,
     cwd         => '/home/examadm/tal-cli',
   }
+
+  file { '/etc/cron.daily/tal-remind' :
+    ensure  => file,
+    owner   => 'root',
+    group   => 'root',
+    mode    => '0700',
+    content => @(END),
+    #!/bin/bash
+    if [ "$(hostname)" = "aes-devel.edu.liu.se" ]
+    then
+        TO="klas.arvidsson@liu.se"
+    else
+        TO="inrapportering@ida.liu.se"
+    fi
+    if [ -e /home/examadm/ENABLE_TAL_REMINDERS ]
+    then
+        sudo -u examadm /home/examadm/tal-cli/scripts/tal-remind.py --to ${TO} --send
+        sudo -u examadm /home/examadm/tal-cli/scripts/tal-remind.py --to ${TO} --computer-exam --send
+    fi
+    | END
+  }
 }
diff --git a/metadata.json b/metadata.json
index b01ff50fc8501ea71fe6d677d6c5835fde581329..cb6c9a3c1d574c6a1eeb1ddde49db09cf9923184 100644
--- a/metadata.json
+++ b/metadata.json
@@ -26,7 +26,7 @@
       "version_requirement": ">= 6.21.0 < 8.0.0"
     }
   ],
-  "pdk-version": "2.2.0",
+  "pdk-version": "2.6.1",
   "template-url": "https://gitlab.it.liu.se/puppet-infra/pdk-templates.git#liu",
-  "template-ref": "heads/liu-0-gd8925d4"
+  "template-ref": "heads/liu-0-g09dd5f0"
 }