diff --git a/cli/Commands/Config/ConfigList.php b/cli/Commands/Config/ConfigList.php
new file mode 100644
index 0000000000000000000000000000000000000000..e818ac0d731041494f655ed13c652d9f6263cdeb
--- /dev/null
+++ b/cli/Commands/Config/ConfigList.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Studip\Cli\Commands\Config;
+
+use ConfigurationModel;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ConfigList extends Command
+{
+    protected static $defaultName = 'config:list';
+
+    protected function configure()
+    {
+        $this->setDescription('List all Stud.IP configuration.');
+        $this->setHelp('This command shows a list of available configurations.');
+        $this->addArgument('config-section', InputArgument::OPTIONAL, 'Section of the configuration.');
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $section  = $input->getArgument('config-section');
+        $sections = ConfigurationModel::getConfig($section);
+
+        foreach ($sections as $section => $configs) {
+            $data = [];
+            foreach ($configs as $config) {
+                $data[] = [
+                    $config['field'],
+                    $config['type'],
+                    mila(kill_format((string)$config['value']),40),
+                    $config['range'],
+                     mila(kill_format((string)$config['description']),40),
+                ];
+            }
+            $table = new Table($output);
+            $table->setColumnMaxWidth(1, 10);
+            $table->setColumnMaxWidth(2, 50);
+            $table->setColumnMaxWidth(3, 10);
+            $table->setColumnMaxWidth(4, 50);
+            $table->setHeaderTitle($section ?? _('Ohne Kategorie'));
+            $table->setHeaders(['Field', 'Type', 'Value', 'Range', 'Description']);
+            $table->setRows($data);
+            $table->setStyle('box');
+            $table->render();
+        }
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/Config/GetConfigValue.php b/cli/Commands/Config/GetConfigValue.php
new file mode 100644
index 0000000000000000000000000000000000000000..46fe903b6a29da14f40ed193675145cac9018a36
--- /dev/null
+++ b/cli/Commands/Config/GetConfigValue.php
@@ -0,0 +1,107 @@
+<?php
+
+namespace Studip\Cli\Commands\Config;
+
+use Course;
+use Institute;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use User;
+use RangeFactory;
+
+class GetConfigValue extends Command
+{
+    protected static $defaultName = 'config:get';
+
+    protected function configure(): void
+    {
+        $this->setDescription('Get value of a Stud.IP configuration key.');
+        $this->setHelp('This command will return the value of a Stud.IP configuration key.');
+        $this->addArgument('config-key', InputArgument::REQUIRED, 'Key of the configuration.');
+        $this->addOption(
+            'user',
+            'u',
+            InputOption::VALUE_OPTIONAL,
+            'Read configuration for a user'
+        );
+        $this->addOption(
+            'course',
+            'c',
+            InputOption::VALUE_OPTIONAL,
+            'Read configuration for a course'
+        );
+        $this->addOption(
+            'inst',
+            'i',
+            InputOption::VALUE_OPTIONAL,
+            'Read configuration for a institute'
+        );
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $configKey   = $input->getArgument('config-key');
+        $userId      = $input->getOption('user');
+        $courseId    = $input->getOption('course');
+        $instituteId = $input->getOption('inst');
+
+        $range = null;
+        if ($userId && $courseId && $instituteId) {
+            $output->writeln('<error>Please select one specific range</error>');
+            return Command::FAILURE;
+        }
+        if ($userId) {
+            $range = User::find($userId);
+            if (empty($range)) {
+                $output->writeln('<error>Could not find user</error>');
+                return Command::FAILURE;
+            }
+
+        } else if ($courseId) {
+            $range = Course::find($courseId);
+            if (empty($range)) {
+                $output->writeln('<error>Could not find course</error>');
+                return Command::FAILURE;
+            }
+        } else if ($instituteId) {
+            $range = Institute::find($instituteId);
+            if (empty($range)) {
+                $output->writeln('<error>Could not find institute</error>');
+                return Command::FAILURE;
+            }
+        }
+
+        if ($range) {
+            $config = $range->getConfiguration();
+        } else {
+            $config = \Config::get();
+        }
+
+        if (empty($config)) {
+            $output->writeln('<error>Could not find config</error>');
+            return Command::FAILURE;
+        }
+
+        $metadata = $config->getMetadata($configKey) ?: [
+            'field'       => $configKey,
+            'type'        => 'string',
+            'description' => 'missing in table `config`',
+        ];
+        if (isset($metadata['is_default'])) {
+            $metadata['is_default'] = $metadata['is_default'] ? 'true' : 'false';
+        }
+        $metadata['value'] = $config->$configKey;
+        $pairs             = array_map(null, array_keys($metadata), array_values($metadata));
+
+        $table = new Table($output);
+        $table->setHeaders(['Field', 'Value'])->setRows($pairs);
+        $table->setStyle('box');
+        $table->render();
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/Config/SectionList.php b/cli/Commands/Config/SectionList.php
new file mode 100644
index 0000000000000000000000000000000000000000..28a0ed79ff85a715053c38b7b3c873bb23b8e19d
--- /dev/null
+++ b/cli/Commands/Config/SectionList.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Studip\Cli\Commands\Config;
+
+use ConfigurationModel;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SectionList extends Command
+{
+    protected static $defaultName = 'config:section-list';
+
+    protected function configure(): void
+    {
+        $this->setDescription('List all configuration sections');
+        $this->setHelp('This command shows a list of available configuration sections.');
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $ranges = ConfigurationModel::getConfig();
+        $data = [];
+        foreach (array_keys($ranges) as $range) {
+            $data[] = [$range ?? _('Ohne Kategorie')];
+        }
+        $table  = new Table($output);
+        $table->setHeaders(['Range'])
+        ->setRows($data)
+        ->setStyle('box')
+        ->render();
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/Config/SetConfigValue.php b/cli/Commands/Config/SetConfigValue.php
new file mode 100644
index 0000000000000000000000000000000000000000..9444dc954a1c28ae18366fb107c5731289e24505
--- /dev/null
+++ b/cli/Commands/Config/SetConfigValue.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Studip\Cli\Commands\Config;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\Table;
+
+class SetConfigValue extends Command
+{
+    protected static $defaultName = 'config:set';
+
+    protected function configure(): void
+    {
+        $this->setDescription('Set value of a Stud.IP configuration key.');
+        $this->setHelp('This command will set the value of a Stud.IP configuration key.');
+        $this->addArgument('config-key', InputArgument::REQUIRED, 'Key of the configuration.');
+        $this->addArgument('config-value', InputArgument::REQUIRED, 'Value of the configuration.');
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $configKey = $input->getArgument('config-key');
+        $configValue = $input->getArgument('config-value');
+        $metadata = \Config::get()->getMetadata($configKey);
+        if (!$metadata) {
+            throw new \RuntimeException("Unknown config key '{$configKey}");
+        }
+
+        \Config::get()->store($configKey, $configValue);
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/Course/GetCourse.php b/cli/Commands/Course/GetCourse.php
new file mode 100644
index 0000000000000000000000000000000000000000..97a777234336f0c07d64918220d2cf8c995cc213
--- /dev/null
+++ b/cli/Commands/Course/GetCourse.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Studip\Cli\Commands\Course;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\Table;
+use Symfony\Component\Console\Helper\TableSeparator;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Course;
+
+class GetCourse extends Command
+{
+    protected static $defaultName = 'course:get';
+
+    protected function configure(): void
+    {
+        $this->setDescription('Get data of Stud.IP courses.');
+        $this->setHelp('This command will return the course data.');
+        $this->addOption(
+            'field',
+            'f',
+            InputOption::VALUE_OPTIONAL,
+            'In which database field should be searched',
+            'name'
+        );
+        $this->addArgument('needle', InputArgument::REQUIRED, 'Value to search for a course.');
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $needle = $input->getArgument('needle');
+        $field = $input->getOption('field');
+
+        if ($field === 'id') {
+            $courses = array_filter([Course::find($needle)]);
+        } else {
+            $courses = Course::findBySQL($field . " LIKE :needle ORDER BY $field", [':needle' => "%$needle%"]);
+        }
+
+        if (empty($courses)) {
+            $output->writeln('<error>Could not find courses</error>');
+            return Command::FAILURE;
+        }
+        $data = [];
+
+        foreach ($courses as $i =>  $course) {
+            $data[] = [
+                $course->id,
+                $course->veranstaltungsnummer,
+                $course->getFullName(),
+                $course->getTextualSemester()
+            ];
+            if ($i + 1 < count($courses)) {
+                $data[] = [new TableSeparator(), new TableSeparator()];
+            }
+        }
+
+        $table = new Table($output);
+        $table->setHeaders(['Id', 'Course-number', 'Name', 'Semester'])
+            ->setRows($data)
+            ->setStyle('box')
+            ->render();
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/User/GetUser.php b/cli/Commands/User/GetUser.php
new file mode 100644
index 0000000000000000000000000000000000000000..402356c94c2bab398d5a47e1f7d92ca84401e364
--- /dev/null
+++ b/cli/Commands/User/GetUser.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace Studip\Cli\Commands\User;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\Table;
+use User;
+
+class GetUser extends Command
+{
+    protected static $defaultName = 'user:get';
+
+    protected function configure(): void
+    {
+        $this->setDescription('Get data of Stud.IP users.');
+        $this->setHelp('This command will return the user data.');
+        $this->addOption(
+            'field',
+            'f',
+            InputOption::VALUE_OPTIONAL,
+            'In which database field should be searched',
+            'username'
+        );
+        $this->addArgument('needle', InputArgument::REQUIRED, 'Value to search for a user.');
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $needle = $input->getArgument('needle');
+        $field = $input->getOption('field');
+
+        if ($field === 'id') {
+            $field = 'user_id';
+        }
+
+        $users = User::findBySQL($field . ' = ?', [$needle]);
+
+        if (empty($users)) {
+            $output->writeln('<error>Could not find users</error>');
+            return Command::FAILURE;
+        }
+        $data = [];
+        foreach ($users as $user) {
+            $data[] = [
+                $user->id,
+                $user->username,
+                $user->vorname,
+                $user->nachname,
+                $user->email,
+                $user->auth_plugin,
+            ];
+        }
+
+        $table = new Table($output);
+        $table->setHeaders(['Id', 'Username', 'Firstname', 'Lastname', 'Email', 'Auth-Plugin'])
+            ->setRows($data)
+            ->setStyle('box')
+            ->render();
+
+        return Command::SUCCESS;
+    }
+}
diff --git a/cli/Commands/Users/UserDelete.php b/cli/Commands/User/UsersDelete.php
similarity index 97%
rename from cli/Commands/Users/UserDelete.php
rename to cli/Commands/User/UsersDelete.php
index 2ba854e60d8c0d61edb37e8928a424174306ff31..33b41c30c29498958d87a24e5391aa7fe4589d00 100644
--- a/cli/Commands/Users/UserDelete.php
+++ b/cli/Commands/User/UsersDelete.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Studip\Cli\Commands\Users;
+namespace Studip\Cli\Commands\User;
 
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputArgument;
@@ -8,7 +8,7 @@ use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 
-class UserDelete extends Command
+class UsersDelete extends Command
 {
     protected static $defaultName = 'user:delete';
 
diff --git a/cli/studip b/cli/studip
index 6ba02ce51be78456aecd657b168aac0636c9335e..d830e31f7600094c8f59c4b22b55cf8513c5982d 100755
--- a/cli/studip
+++ b/cli/studip
@@ -19,6 +19,11 @@ $commands = [
     Commands\Checks\HelpTours::class,
     Commands\CleanupAdmissionRules::class,
     Commands\Composer\GenerateUpdateList::class,
+    Commands\Config\ConfigList::class,
+    Commands\Config\GetConfigValue::class,
+    Commands\Config\SectionList::class,
+    Commands\Config\SetConfigValue::class,
+    Commands\Course\GetCourse::class,
     Commands\Cronjobs\CronjobExecute::class,
     Commands\Cronjobs\CronjobExecute::class,
     Commands\Cronjobs\CronjobList::class,
@@ -56,8 +61,8 @@ $commands = [
     Commands\Resources\UpdateBookingIntervals::class,
     Commands\SORM\DescribeModels::class,
     Commands\Twillo\PrivateKeys::class,
-    Commands\Users\UserDelete::class,
-    Commands\Users\UserDelete::class,
+    Commands\User\UsersDelete::class,
+    Commands\User\GetUser::class,
 ];
 $creator = function ($command) {
     return new $command();