diff --git a/typo3/sysext/core/Classes/Console/CommandRegistry.php b/typo3/sysext/core/Classes/Console/CommandRegistry.php
index ce79263708e87250b4d895c9c8ca3d0a171b8951..cbfc91a2aa68c1aa6e505f542c65737b1c6cee39 100644
--- a/typo3/sysext/core/Classes/Console/CommandRegistry.php
+++ b/typo3/sysext/core/Classes/Console/CommandRegistry.php
@@ -56,6 +56,26 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface
         }
     }
 
+    /**
+     * @param string $identifier
+     * @throws CommandNameAlreadyInUseException
+     * @throws UnknownCommandException
+     * @return Command
+     */
+    public function getCommandByIdentifier(string $identifier): Command
+    {
+        $this->populateCommandsFromPackages();
+
+        if (!isset($this->commands[$identifier])) {
+            throw new UnknownCommandException(
+                sprintf('Command "%s" has not been registered.', $identifier),
+                1510906768
+            );
+        }
+
+        return $this->commands[$identifier] ?? null;
+    }
+
     /**
      * Find all Configuration/Commands.php files of extensions and create a registry from it.
      * The file should return an array with a command key as key and the command description
@@ -79,7 +99,12 @@ class CommandRegistry implements \IteratorAggregate, SingletonInterface
         foreach ($this->packageManager->getActivePackages() as $package) {
             $commandsOfExtension = $package->getPackagePath() . 'Configuration/Commands.php';
             if (@is_file($commandsOfExtension)) {
-                $commands = require_once $commandsOfExtension;
+                /*
+                 * We use require instead of require_once here because it eases the testability as require_once returns
+                 * a boolean from the second execution on. As this class is a singleton, this require is only called
+                 * once per request anyway.
+                 */
+                $commands = require $commandsOfExtension;
                 if (is_array($commands)) {
                     foreach ($commands as $commandName => $commandConfig) {
                         if (array_key_exists($commandName, $this->commands)) {
diff --git a/typo3/sysext/core/Classes/Console/UnknownCommandException.php b/typo3/sysext/core/Classes/Console/UnknownCommandException.php
new file mode 100644
index 0000000000000000000000000000000000000000..e583bd7f3cbba4942cb28fa5050f51a6b6959b44
--- /dev/null
+++ b/typo3/sysext/core/Classes/Console/UnknownCommandException.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Core\Console;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Exception;
+
+/**
+ * Exception thrown when an unregistered command is asked for
+ */
+class UnknownCommandException extends Exception
+{
+}
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-79462-IntroduceSchedulerTaskToExecuteConsoleCommand.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-79462-IntroduceSchedulerTaskToExecuteConsoleCommand.rst
new file mode 100644
index 0000000000000000000000000000000000000000..cf8d855ceadbd90cd8d7c0e67083103ef2a450d3
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-79462-IntroduceSchedulerTaskToExecuteConsoleCommand.rst
@@ -0,0 +1,23 @@
+.. include:: ../../Includes.txt
+
+=====================================================================
+Feature: #79462 - Introduce scheduler task to execute console command
+=====================================================================
+
+See :issue:`79462`
+
+Description
+===========
+
+A scheduler task has been introduced to execute (symfony) console commands. In the past this was
+already possible for Extbase command controller commands but as the core migrates all command
+controllers to native symfony commands, the scheduler needs to be able to execute them.
+
+
+Impact
+======
+
+Symfony commands can be executed via the scheduler which provides a migration path away from
+command controllers to native symfony commands.
+
+.. index:: CLI, NotScanned
diff --git a/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php b/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php
index e348d305ee621b06028b0d69d724371e940e80f6..a6f7cd8983c23466525a7d6547e81792099788f6 100644
--- a/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php
+++ b/typo3/sysext/core/Tests/Unit/Console/CommandRegistryTest.php
@@ -16,9 +16,11 @@ namespace TYPO3\CMS\Core\Tests\Unit\Console;
  */
 
 use org\bovigo\vfs\vfsStream;
+use Prophecy\Prophecy\ObjectProphecy;
 use Symfony\Component\Console\Command\Command;
 use TYPO3\CMS\Core\Console\CommandNameAlreadyInUseException;
 use TYPO3\CMS\Core\Console\CommandRegistry;
+use TYPO3\CMS\Core\Console\UnknownCommandException;
 use TYPO3\CMS\Core\Package\PackageInterface;
 use TYPO3\CMS\Core\Package\PackageManager;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
@@ -113,4 +115,36 @@ class CommandRegistryTest extends UnitTestCase
         $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal());
         iterator_to_array($commandRegistry);
     }
+
+    /**
+     * @test
+     */
+    public function getCommandByIdentifierReturnsRegisteredCommand()
+    {
+        /** @var PackageInterface|ObjectProphecy $package */
+        $package = $this->prophesize(PackageInterface::class);
+        $package->getPackagePath()->willReturn($this->rootDirectory->getChild('package1')->url() . '/');
+        $package->getPackageKey()->willReturn('package1');
+
+        $this->packageManagerProphecy->getActivePackages()->willReturn([$package->reveal()]);
+
+        $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal());
+        $command = $commandRegistry->getCommandByIdentifier('first:command');
+
+        $this->assertInstanceOf(Command::class, $command);
+    }
+
+    /**
+     * @test
+     */
+    public function throwsUnknowCommandExceptionIfUnregisteredCommandIsRequested()
+    {
+        $this->packageManagerProphecy->getActivePackages()->willReturn([]);
+
+        $this->expectException(UnknownCommandException::class);
+        $this->expectExceptionCode(1510906768);
+
+        $commandRegistry = new CommandRegistry($this->packageManagerProphecy->reveal());
+        $commandRegistry->getCommandByIdentifier('foo');
+    }
 }
diff --git a/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandAdditionalFieldProvider.php b/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandAdditionalFieldProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..e2974504f768056cf4ae824ab71bae5299dff83f
--- /dev/null
+++ b/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandAdditionalFieldProvider.php
@@ -0,0 +1,331 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Scheduler\Task;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputDefinition;
+use TYPO3\CMS\Core\Console\CommandRegistry;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Lang\LanguageService;
+use TYPO3\CMS\Scheduler\AdditionalFieldProviderInterface;
+use TYPO3\CMS\Scheduler\Controller\SchedulerModuleController;
+use TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder;
+
+/**
+ * Class TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider
+ */
+class ExecuteSchedulableCommandAdditionalFieldProvider implements AdditionalFieldProviderInterface
+{
+    /**
+     * Commands that should not be schedulable, like scheduler:run,
+     * which would start a recursion.
+     *
+     * @var array
+     */
+    protected static $blacklistedCommands = [
+        \TYPO3\CMS\Scheduler\Command\SchedulerCommand::class, // scheduler:run
+        \TYPO3\CMS\Extbase\Command\CoreCommand::class,        // _core_command
+        \TYPO3\CMS\Extbase\Command\HelpCommand::class,        // _extbase_help
+    ];
+
+    /**
+     * @var array|Command[]
+     */
+    protected $schedulableCommands = [];
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Mvc\Cli\CommandManager
+     */
+    protected $commandManager;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \TYPO3\CMS\Extbase\Reflection\ReflectionService
+     */
+    protected $reflectionService;
+
+    /**
+     * @var ExecuteSchedulableCommandTask
+     */
+    protected $task;
+
+    public function __construct()
+    {
+        $commandRegistry = GeneralUtility::makeInstance(CommandRegistry::class);
+        foreach ($commandRegistry as $commandIdentifier => $command) {
+            if (in_array(get_class($command), static::$blacklistedCommands, true)) {
+                continue;
+            }
+            $this->schedulableCommands[$commandIdentifier] = $command;
+        }
+
+        ksort($this->schedulableCommands);
+    }
+
+    /**
+     * Render additional information fields within the scheduler backend.
+     *
+     * @param array &$taskInfo Array information of task to return
+     * @param mixed $task \TYPO3\CMS\Scheduler\Task\AbstractTask or \TYPO3\CMS\Scheduler\Execution instance
+     * @param SchedulerModuleController $schedulerModule Reference to the calling object (BE module of the Scheduler)
+     * @return array Additional fields
+     * @see \TYPO3\CMS\Scheduler\AdditionalFieldProvider#getAdditionalFields($taskInfo, $task, $schedulerModule)
+     */
+    public function getAdditionalFields(array &$taskInfo, $task, SchedulerModuleController $schedulerModule): array
+    {
+        $this->task = $task;
+        if ($this->task !== null) {
+            $this->task->setScheduler();
+        }
+
+        $fields = [];
+        $fields['action'] = $this->getActionField();
+
+        if ($this->task !== null && isset($this->schedulableCommands[$this->task->getCommandIdentifier()])) {
+            $command = $this->schedulableCommands[$this->task->getCommandIdentifier()];
+            $fields['description'] = $this->getCommandDescriptionField($command->getDescription());
+            $argumentFields = $this->getCommandArgumentFields($command->getDefinition());
+            $fields = array_merge($fields, $argumentFields);
+            $this->task->save(); // todo: this seems to be superfluous
+        }
+
+        return $fields;
+    }
+
+    /**
+     * Validates additional selected fields
+     *
+     * @param array &$submittedData
+     * @param SchedulerModuleController $schedulerModule
+     * @return bool
+     */
+    public function validateAdditionalFields(array &$submittedData, SchedulerModuleController $schedulerModule): bool
+    {
+        if (!isset($this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']])) {
+            return false;
+        }
+
+        $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']];
+
+        /** @var FlashMessageService $flashMessageService */
+        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+
+        $hasErrors = false;
+        foreach ($command->getDefinition()->getArguments() as $argument) {
+            foreach ((array)$submittedData['task_executeschedulablecommand']['arguments'] as $argumentName => $argumentValue) {
+                /** @var string $argumentName */
+                /** @var string $argumentValue */
+                if ($argument->getName() !== $argumentName) {
+                    continue;
+                }
+
+                if ($argument->isRequired() && trim($argumentValue) === '') {
+                    // Argument is required and argument value is empty0
+                    $flashMessageService->getMessageQueueByIdentifier()->addMessage(
+                        new FlashMessage(
+                            sprintf(
+                                $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.mandatoryArgumentMissing'),
+                                $argumentName
+                            ),
+                            $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.updateError'),
+                            FlashMessage::ERROR
+                        )
+                    );
+                    $hasErrors = true;
+                }
+            }
+        }
+        return $hasErrors === false;
+    }
+
+    /**
+     * Saves additional field values
+     *
+     * @param array $submittedData
+     * @param AbstractTask $task
+     * @return bool
+     */
+    public function saveAdditionalFields(array $submittedData, AbstractTask $task): bool
+    {
+        $command = $this->schedulableCommands[$submittedData['task_executeschedulablecommand']['command']];
+
+        /** @var ExecuteSchedulableCommandTask $task */
+        $task->setCommandIdentifier($submittedData['task_executeschedulablecommand']['command']);
+
+        $arguments = [];
+        foreach ((array)$submittedData['task_executeschedulablecommand']['arguments'] as $argumentName => $argumentValue) {
+            try {
+                $argumentDefinition = $command->getDefinition()->getArgument($argumentName);
+            } catch (InvalidArgumentException $e) {
+                continue;
+            }
+
+            if ($argumentDefinition->isArray()) {
+                $argumentValue = GeneralUtility::trimExplode(',', $argumentValue, true);
+            }
+
+            $arguments[$argumentName] = $argumentValue;
+        }
+
+        $task->setArguments($arguments);
+        return true;
+    }
+
+    /**
+     * Get description of selected command
+     *
+     * @param string $description
+     * @return array
+     */
+    protected function getCommandDescriptionField(string $description): array
+    {
+        return [
+            'code' => '',
+            'label' => '<strong>' . $description . '</strong>'
+        ];
+    }
+
+    /**
+     * Gets a select field containing all possible schedulable commands
+     *
+     * @return array
+     */
+    protected function getActionField(): array
+    {
+        $currentlySelectedCommand = $this->task !== null ? $this->task->getCommandIdentifier() : '';
+        $options = [];
+        foreach ($this->schedulableCommands as $commandIdentifier => $command) {
+            $options[$commandIdentifier] = $commandIdentifier . ': ' . $command->getDescription();
+        }
+        return [
+            'code' => $this->renderSelectField($options, $currentlySelectedCommand),
+            'label' => $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:label.schedulableCommandName')
+        ];
+    }
+
+    /**
+     * Gets a set of fields covering arguments which can or must be used.
+     * Also registers the default values of those fields with the Task, allowing
+     * them to be read upon execution.
+     *
+     * @param InputDefinition $inputDefinition
+     * @return array
+     */
+    protected function getCommandArgumentFields(InputDefinition $inputDefinition): array
+    {
+        $fields = [];
+        $argumentValues = $this->task->getArguments();
+        foreach ($inputDefinition->getArguments() as $argument) {
+            $name = $argument->getName();
+            $defaultValue = $argument->getDefault();
+            $this->task->addDefaultValue($name, $defaultValue);
+            $value = $argumentValues[$name] ?? $defaultValue;
+
+            if (is_array($value) && $argument->isArray()) {
+                $value = implode(',', $value);
+            }
+
+            $fields[$name] = [
+                'code' => $this->renderField($argument, (string)$value),
+                'label' => $this->getArgumentLabel($argument)
+            ];
+        }
+
+        return $fields;
+    }
+
+    /**
+     * Get a human-readable label for a command argument
+     *
+     * @param InputArgument $argument
+     * @return string
+     */
+    protected function getArgumentLabel(InputArgument $argument): string
+    {
+        return 'Argument: ' . $argument->getName() . '. <em>' . htmlspecialchars($argument->getDescription()) . '</em>';
+    }
+
+    /**
+     * @param array $options
+     * @param string $selectedOptionValue
+     * @return string
+     */
+    protected function renderSelectField(array $options, string $selectedOptionValue): string
+    {
+        $selectTag = new TagBuilder();
+        $selectTag->setTagName('select');
+        $selectTag->forceClosingTag(true);
+        $selectTag->addAttribute('class', 'form-control');
+        $selectTag->addAttribute('name', 'tx_scheduler[task_executeschedulablecommand][command]');
+
+        $optionsHtml = '';
+        foreach ($options as $value => $label) {
+            $optionTag = new TagBuilder();
+            $optionTag->setTagName('option');
+            $optionTag->forceClosingTag(true);
+            $optionTag->addAttribute('title', (string)$label);
+            $optionTag->addAttribute('value', (string)$value);
+            $optionTag->setContent($label);
+
+            if ($value === $selectedOptionValue) {
+                $optionTag->addAttribute('selected', 'selected');
+            }
+
+            $optionsHtml .= $optionTag->render();
+        }
+
+        $selectTag->setContent($optionsHtml);
+        return $selectTag->render();
+    }
+
+    /**
+     * Renders a field for defining an argument's value
+     *
+     * @param InputArgument $argument
+     * @param mixed $currentValue
+     * @return string
+     */
+    protected function renderField(InputArgument $argument, string $currentValue): string
+    {
+        $name = $argument->getName();
+        $fieldName = 'tx_scheduler[task_executeschedulablecommand][arguments][' . $name . ']';
+
+        $inputTag = new TagBuilder();
+        $inputTag->setTagName('input');
+        $inputTag->addAttribute('type', 'text');
+        $inputTag->addAttribute('name', $fieldName);
+        $inputTag->addAttribute('value', $currentValue);
+        $inputTag->addAttribute('class', 'form-control');
+
+        return $inputTag->render();
+    }
+
+    /**
+     * @return LanguageService
+     */
+    public function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandTask.php b/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandTask.php
new file mode 100644
index 0000000000000000000000000000000000000000..35edb58ccaaf9542ebbf7162aa2b0a90c8f71342
--- /dev/null
+++ b/typo3/sysext/scheduler/Classes/Task/ExecuteSchedulableCommandTask.php
@@ -0,0 +1,129 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\Scheduler\Task;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Output\NullOutput;
+use TYPO3\CMS\Core\Console\CommandRegistry;
+use TYPO3\CMS\Core\Console\UnknownCommandException;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * Class TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask
+ */
+class ExecuteSchedulableCommandTask extends AbstractTask
+{
+    /**
+     * @var string
+     */
+    protected $commandIdentifier = '';
+
+    /**
+     * @var array
+     */
+    protected $arguments = [];
+
+    /**
+     * @var array
+     */
+    protected $defaults = [];
+
+    /**
+     * @param string $commandIdentifier
+     */
+    public function setCommandIdentifier(string $commandIdentifier)
+    {
+        $this->commandIdentifier = $commandIdentifier;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCommandIdentifier(): string
+    {
+        return $this->commandIdentifier;
+    }
+
+    /**
+     * This is the main method that is called when a task is executed
+     * It MUST be implemented by all classes inheriting from this one
+     * Note that there is no error handling, errors and failures are expected
+     * to be handled and logged by the client implementations.
+     * Should return TRUE on successful execution, FALSE on error.
+     *
+     * @throws \Exception
+     *
+     * @return bool Returns TRUE on successful execution, FALSE on error
+     */
+    public function execute(): bool
+    {
+        try {
+            $commandRegistry = GeneralUtility::makeInstance(CommandRegistry::class);
+            $schedulableCommand = $commandRegistry->getCommandByIdentifier($this->commandIdentifier);
+        } catch (UnknownCommandException $e) {
+            throw new \RuntimeException(
+                sprintf(
+                    $this->getLanguageService()->sL('LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:msg.unregisteredCommand'),
+                    $this->commandIdentifier
+                ),
+                1505055445,
+                $e
+            );
+        }
+
+        $input = new ArrayInput($this->getArguments(), $schedulableCommand->getDefinition());
+        $output = new NullOutput();
+
+        return $schedulableCommand->run($input, $output) === 0;
+    }
+
+    /**
+     * @return array
+     */
+    public function getArguments(): array
+    {
+        return $this->arguments;
+    }
+
+    /**
+     * @param array $arguments
+     */
+    public function setArguments(array $arguments)
+    {
+        $this->arguments = $arguments;
+    }
+
+    /**
+     * @param string $argumentName
+     * @param mixed $argumentValue
+     */
+    public function addDefaultValue(string $argumentName, $argumentValue)
+    {
+        if (is_bool($argumentValue)) {
+            $argumentValue = (int)$argumentValue;
+        }
+        $this->defaults[$argumentName] = $argumentValue;
+    }
+
+    /**
+     * @return LanguageService
+     */
+    public function getLanguageService(): LanguageService
+    {
+        return $GLOBALS['LANG'];
+    }
+}
diff --git a/typo3/sysext/scheduler/Resources/Private/Language/locallang.xlf b/typo3/sysext/scheduler/Resources/Private/Language/locallang.xlf
index 9b359697cecfcadf8a75f45ec50b3a853a522f8d..9122e973616817c9feea2f70bc8aa9df29f9dc8e 100644
--- a/typo3/sysext/scheduler/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/scheduler/Resources/Private/Language/locallang.xlf
@@ -162,6 +162,9 @@
 			<trans-unit id="label.noGroup">
 				<source>(no task group defined)</source>
 			</trans-unit>
+			<trans-unit id="label.schedulableCommandName">
+				<source><![CDATA[Schedulable Command. <em>Save and reopen to define command arguments</em>]]></source>
+			</trans-unit>
 			<trans-unit id="msg.addError">
 				<source>The task could not be added.</source>
 			</trans-unit>
@@ -306,6 +309,12 @@
 			<trans-unit id="msg.noDatabaseTablesSelected">
 				<source>Please select at least one database table.</source>
 			</trans-unit>
+			<trans-unit id="msg.unregisteredCommand">
+				<source>Command with identifier "%s" has not been registered.</source>
+			</trans-unit>
+			<trans-unit id="msg.mandatoryArgumentMissing">
+				<source>Argument "%s" is mandatory</source>
+			</trans-unit>
 			<trans-unit id="none">
 				<source>None</source>
 			</trans-unit>
@@ -390,6 +399,12 @@
 			<trans-unit id="recyclerGarbageCollection.description">
 				<source>This task empties all "_recycler_" folders below fileadmin. This helps free some space in the file system.</source>
 			</trans-unit>
+			<trans-unit id="executeSchedulableCommandTask.name">
+				<source>Execute console commands</source>
+			</trans-unit>
+			<trans-unit id="executeSchedulableCommandTask.description">
+				<source>Allows regular console commands to be configured and executed through the scheduler framework.</source>
+			</trans-unit>
 			<trans-unit id="optimizeDatabaseTable.name">
 				<source>Optimize MySQL database tables</source>
 			</trans-unit>
diff --git a/typo3/sysext/scheduler/ext_localconf.php b/typo3/sysext/scheduler/ext_localconf.php
index b5f8badbd0901ceb50b8ca6f045b757366b021df..a8ec1ec7c4305e765ef52e25403106765f62c2a1 100644
--- a/typo3/sysext/scheduler/ext_localconf.php
+++ b/typo3/sysext/scheduler/ext_localconf.php
@@ -53,6 +53,14 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Sched
     'additionalFields' => \TYPO3\CMS\Scheduler\Task\RecyclerGarbageCollectionAdditionalFieldProvider::class
 ];
 
+// Add execute schedulable command task
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][\TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandTask::class] = [
+    'extension' => 'scheduler',
+    'title' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:executeSchedulableCommandTask.name',
+    'description' => 'LLL:EXT:scheduler/Resources/Private/Language/locallang.xlf:executeSchedulableCommandTask.name',
+    'additionalFields' => \TYPO3\CMS\Scheduler\Task\ExecuteSchedulableCommandAdditionalFieldProvider::class
+];
+
 // Save any previous option array for table garbage collection task
 // to temporary variable so it can be pre-populated by other
 // extensions and LocalConfiguration/AdditionalConfiguration