diff --git a/core/management/commands/extractsubmissions.py b/core/management/commands/extractsubmissions.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac8db1d5ff3c6030d3b874ba0297728e8120fd1d
--- /dev/null
+++ b/core/management/commands/extractsubmissions.py
@@ -0,0 +1,12 @@
+from django.core.management.base import BaseCommand
+from core import models
+
+
+class Command(BaseCommand):
+    help = 'Extract all submissions from this instance'
+
+    def handle(self, *args, **kwargs):
+        for submission in models.Submission.objects.filter(
+                feedback__isnull=False).order_by('type'):
+            print(submission.feedback.score, repr(submission.text),
+                  file=open(str(submission.type).replace(' ', '_'), 'a'))
diff --git a/core/management/commands/importer.py b/core/management/commands/importer.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d0bd87c6116a3de726ff1926fd146c4629f76df
--- /dev/null
+++ b/core/management/commands/importer.py
@@ -0,0 +1,10 @@
+from django.core.management.base import BaseCommand
+
+import util.importer
+
+
+class Command(BaseCommand):
+    help = 'Start the Grady command line importer'
+
+    def handle(self, *args, **kwargs):
+        util.importer.start()
diff --git a/core/management/commands/maketestdata.py b/core/management/commands/maketestdata.py
new file mode 100644
index 0000000000000000000000000000000000000000..075cf243e320592e0db25ca78afd82af8cf72c76
--- /dev/null
+++ b/core/management/commands/maketestdata.py
@@ -0,0 +1,10 @@
+from django.core.management.base import BaseCommand
+
+from util.factories import init_test_instance
+
+
+class Command(BaseCommand):
+    help = 'Creates some initial test data for the application'
+
+    def handle(self, *args, **options):
+        init_test_instance()
diff --git a/core/management/commands/replaceusernames.py b/core/management/commands/replaceusernames.py
new file mode 100644
index 0000000000000000000000000000000000000000..d496ee956be59c1baf18601f05f763d07b1069e7
--- /dev/null
+++ b/core/management/commands/replaceusernames.py
@@ -0,0 +1,31 @@
+import argparse
+import json
+import sys
+
+from django.core.management.base import BaseCommand
+
+from core.models import Student
+
+
+class Command(BaseCommand):
+    help = ('replaces all usernames based on a '
+            'matrikel_no -> new_name dict (input should be JSON)')
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            'matno2username_dict',
+            help='the mapping as a JSON file',
+            default=sys.stdin,
+            type=argparse.FileType('r')
+        )
+
+    def _handle(self, matno2username_dict, **kwargs):
+        matno2username = json.JSONDecoder().decode(matno2username_dict.read())
+        for student in Student.objects.all():
+            if student.matrikel_no in matno2username:
+                new_name = matno2username[student.matrikel_no]
+                student.user.username = new_name
+                student.user.save()
+
+    def handle(self, *args, **options):
+        self._handle(*args, **options)
diff --git a/core/management/commands/setstudentpasswords.py b/core/management/commands/setstudentpasswords.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b63a275cff529e117ea1de59db82f31d659cab6
--- /dev/null
+++ b/core/management/commands/setstudentpasswords.py
@@ -0,0 +1,42 @@
+import csv
+import secrets
+import sys
+
+from django.core.management.base import BaseCommand
+
+from core.models import Student
+
+
+class Command(BaseCommand):
+    help = ('All student passwords will be changed'
+            'and a list of these password will be printed')
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            'instance',
+            help="Name of the instance that generated the passwords"
+        )
+
+    def _handle(self, *args, output=sys.stdout, instance="", **kwargs):
+        with open('/usr/share/dict/words') as words:
+            choose_from = list({word.strip().lower()
+                                for word in words if 5 < len(word) < 8})
+
+        writer = csv.writer(output)
+        writer.writerow(
+            ['Name', 'Matrikel', 'Username', 'password', 'instance'])
+
+        for student in Student.objects.all():
+            password = ''.join(secrets.choice(choose_from) for _ in range(3))
+
+            student.user.set_password(password)
+            student.user.save()
+
+            if not student.user.fullname:
+                student.user.fullname = '__no_name__'
+
+            writer.writerow([student.user.fullname, student.matrikel_no,
+                             student.user.username, password, instance])
+
+    def handle(self, *args, **options):
+        self._handle(*args, **options)
diff --git a/core/management/commands/usermod.py b/core/management/commands/usermod.py
new file mode 100644
index 0000000000000000000000000000000000000000..14a95621055783ba33c2b392f5857a5487b4dad4
--- /dev/null
+++ b/core/management/commands/usermod.py
@@ -0,0 +1,37 @@
+from django.contrib.auth import get_user_model
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+    help = 'All user accounts will be disabled'
+
+    def add_arguments(self, parser):
+        parser.add_argument(
+            'switch',
+            choices=('enable', 'disable'),
+            default='enable',
+            help='enable all users (enable) or disable all (disable)'
+        )
+        filter_group = parser.add_mutually_exclusive_group()
+        filter_group.add_argument(
+            '--exclude',
+            default=(),
+            nargs='+',
+            help='Provide all users you want to exclude from the operation'
+        )
+        filter_group.add_argument(
+            '--include',
+            help=('Provide users you want to operate on'
+                  'Everything else is untouched'),
+            nargs='+',
+            default=())
+
+    def handle(self, switch, exclude=None, include=None, *args, **kwargs):
+        if include:
+            for user in get_user_model().objects.filter(username__in=include):
+                user.is_active = switch == 'enable'
+                user.save()
+        else:  # this includes nothing set
+            for user in get_user_model().objects.exclude(username__in=exclude):
+                user.is_active = switch == 'enable'
+                user.save()
diff --git a/core/tests/test_commands.py b/core/tests/test_commands.py
new file mode 100644
index 0000000000000000000000000000000000000000..8286c8e10f1d318750fbad6a242662821105ce51
--- /dev/null
+++ b/core/tests/test_commands.py
@@ -0,0 +1,35 @@
+from django.core.management import call_command
+from django.contrib.auth import get_user_model
+from django.test import TestCase
+
+from util.factories import GradyUserFactory
+
+from core.models import Student
+import tempfile
+import json
+
+
+class CommandsTestCase(TestCase):
+
+    factory = GradyUserFactory()
+
+    def test_usermod(self):
+        self.factory.make_tutor(username='otto')
+        args = ['disable']
+        opts = {'include': ('otto',)}
+        call_command('usermod', *args, **opts)
+
+        someone = get_user_model().objects.get(username='otto')
+        self.assertFalse(someone.is_active)
+
+    def test_replaceusernames(self):
+        self.factory.make_student(matrikel_no=88884444, username='before')
+
+        with tempfile.NamedTemporaryFile() as matno2username:
+            matno2username.write(json.dumps({'88884444': 'after'}).encode())
+            matno2username.flush()
+            args = [matno2username.name]
+            call_command('replaceusernames', *args, **{})
+
+        student = Student.objects.get(matrikel_no=88884444)
+        self.assertEqual('after', student.user.username)
diff --git a/delbert.py b/delbert.py
deleted file mode 100755
index d3526487ca037b4a1d0fc1c89116c25e768bc6cf..0000000000000000000000000000000000000000
--- a/delbert.py
+++ /dev/null
@@ -1,143 +0,0 @@
-import argparse
-import csv
-import json
-import os
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'grady.settings')
-import secrets
-import sys
-
-import django
-django.setup()
-from django.contrib.auth.models import User
-
-import util.importer
-from core.models import Student, Submission
-
-
-unused_variable = []
-
-
-def parseme():
-    parser = argparse.ArgumentParser()
-    subparsers = parser.add_subparsers(dest="command")
-
-    parser.add_argument(
-        '-o', '--output',
-        help='Where the output goes (not info messages)',
-        default=sys.stdout,
-        type=argparse.FileType(mode='r'),
-    )
-
-    ### parser for printing out new passwordlists ###
-    passwordlist = subparsers.add_parser(
-        'passwordlist',
-        help='all student passwords will be changed and a list of these password will be printed'
-    )
-    passwordlist.add_argument(
-        'instance',
-        default='',
-        help='name of the instance that generated the passwords'
-    )
-
-    ### parser for replacing usernames ###
-    replaceusernames = subparsers.add_parser(
-        'replaceusernames',
-        help='replaces all usernames based on a matrikel_no -> new_name dict (input should be JSON)'
-    )
-    replaceusernames.add_argument(
-        'matno2username_dict',
-        help='the mapping as a JSON file',
-        default=sys.stdin,
-        type=argparse.FileType('r')
-    )
-
-    ### parser for enabling or disabling users ###
-    enableusers = subparsers.add_parser(
-        'enableusers',
-        help='All user accounts will be disabled'
-    )
-    enableusers.add_argument(
-        'switch',
-        choices=('on', 'off'),
-        default='on',
-        help='enable all users (on) or disable all (off)'
-    )
-    filter_group = enableusers.add_mutually_exclusive_group()
-    filter_group.add_argument(
-        '-e', '--exclude',
-        default=(),
-        nargs='+',
-        help='give exceptions by username in a comma separated list'
-    )
-    filter_group.add_argument(
-        '-i', '--include',
-        help='only apply to these users',
-        nargs='+',
-        default=())
-
-    ### parser for extracting submissions ###
-    subparsers.add_parser('extractsubmissions')
-
-    ### parser for extracting submissions ###
-    subparsers.add_parser('importer')
-
-    return parser.parse_args()
-
-
-def handle_passwordlist(output=sys.stdout, instance="", **kwargs):
-    with open('/usr/share/dict/words') as words:
-        choose_from = list({word.strip().lower()
-                            for word in words if 5 < len(word) < 8})
-
-    writer = csv.writer(output)
-    writer.writerow(['Name', 'Matrikel', 'Username', 'password', 'instance'])
-
-    for student in Student.objects.all():
-        password = ''.join(secrets.choice(choose_from) for _ in range(3))
-
-        student.user.set_password(password)
-        student.user.save()
-
-        writer.writerow([student.name, student.matrikel_no,
-                         student.user.username, password, instance])
-
-
-def handle_enableusers(switch, exclude, include, **kwargs):
-
-    if include:
-        for user in User.objects.filter(username__in=include):
-            user.is_active = switch == 'on'
-            user.save()
-    else:  # this includes nothing set
-        for user in User.objects.exclude(username__in=exclude):
-            user.is_active = switch == 'on'
-            user.save()
-
-
-def handle_replaceusernames(matno2username_dict, **kwargs):
-    matno2username = json.JSONDecoder().decode(matno2username_dict.read())
-    for student in Student.objects.all():
-        if student.matrikel_no in matno2username:
-            new_name = matno2username[student.matrikel_no]
-            student.user.username = new_name
-            student.user.save()
-
-
-def handle_extractsubmissions(output, **kwargs):
-    for submission in Submission.objects.filter(feedback__isnull=False).order_by('type'):
-        print(submission.feedback.score, repr(submission.text),
-              file=open(str(submission.type).replace(' ', '_'), 'a'))
-
-
-def handle_importer(**kwargs):
-    util.importer.start()
-
-
-def main():
-    args = parseme()
-    if args.command:
-        globals()['handle_' + args.command](**vars(args))
-
-
-if __name__ == '__main__':
-    main()
diff --git a/util/factories.py b/util/factories.py
index 8888c0439c1105252b0202322439e752feb58289..63da6ecf45e9311f49225f1e29f29344b293431e 100644
--- a/util/factories.py
+++ b/util/factories.py
@@ -45,12 +45,13 @@ class GradyUserFactory:
     def _get_random_name(prefix='', suffix='', k=1):
         return ''.join((prefix, get_random_password(k), suffix))
 
-    def _make_base_user(self, username, groupname, password=None, store_pw=False, **kwargs):
+    def _make_base_user(self, username, groupname, password=None,
+                        store_pw=False, **kwargs):
         """ This is a specific wrapper for the django update_or_create method of
         objects.
             * A new user is created and password and group are set accordingly
-            * If the user was there before password is NOT change but group is. A
-              user must only have one group.
+            * If the user was there before password is NOT change but group is.
+            * A user must only have one group.
 
         Returns:
             (User object, str): The user object that was added to the group and
@@ -96,7 +97,9 @@ class GradyUserFactory:
 
         return generic_user
 
-    def make_student(self, username=None, matrikel_no=None, exam=None, **kwargs):
+    def make_student(self, username=None,
+                     matrikel_no=None,
+                     exam=None, **kwargs):
         """ Creates a student. Defaults can be passed via kwargs like in
         relation managers objects.update method. """
         user = self._make_user_generic(username, STUDENTS, **kwargs)
@@ -125,7 +128,7 @@ def make_exams(exams=[], **kwargs):
 def make_submission_types(submission_types=[], **kwargs):
     return [SubmissionType.objects.get_or_create(
         name=submission_type['name'], defaults=submission_type)[0]
-            for submission_type in submission_types]
+        for submission_type in submission_types]
 
 
 def make_students(students=[], **kwargs):