diff --git a/Kernel/System/Console/Command/Admin/DynamicField/Add.pm b/Kernel/System/Console/Command/Admin/DynamicField/Add.pm
new file mode 100644
index 0000000..f3230e9
--- /dev/null
+++ b/Kernel/System/Console/Command/Admin/DynamicField/Add.pm
@@ -0,0 +1,174 @@
+# --
+# OTOBO is a web-based ticketing system for service organisations.
+# --
+# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
+# Copyright (C) 2019-2023 Rother OSS GmbH, https://otobo.de/
+# --
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+# --
+
+package Kernel::System::Console::Command::Admin::DynamicField::Add;
+
+use strict;
+use warnings;
+
+# core modules
+use List::Util qw(max);
+
+# CPAN modules
+
+# OTOBO modules
+
+use parent qw(Kernel::System::Console::BaseCommand);
+
+our @ObjectDependencies = (
+ 'Kernel::System::DynamicField',
+ 'Kernel::System::YAML',
+ 'Kernel::System::JSON',
+);
+
+sub Configure {
+ my ( $Self, %Param ) = @_;
+
+ $Self->Description('Create a new dynamic field.');
+ $Self->AddOption(
+ Name => 'name',
+ Description => 'Name for the new field.',
+ Required => 1,
+ HasValue => 1,
+ ValueRegex => qr/[A-Za-z0-9]+/smx,
+ );
+ $Self->AddOption(
+ Name => 'label',
+ Description => 'Label which will be displayed alongside the field.',
+ Required => 1,
+ HasValue => 1,
+ ValueRegex => qr/.*/smx,
+ );
+ $Self->AddOption(
+ Name => 'field-type',
+ Description => 'Dynamic field type.',
+ Required => 1,
+ HasValue => 1,
+ ValueRegex => qr/[A-Za-z0-9]/smx,
+ );
+ $Self->AddOption(
+ Name => 'object-type',
+ Description => 'Object type for the new field.',
+ Required => 1,
+ HasValue => 1,
+ ValueRegex => qr/[A-Za-z0-9]/smx,
+ );
+ $Self->AddOption(
+ Name => 'config',
+ Description => 'Config for dynamic field. Takes either an YAML or JSON string. See also Admin::DynamicField::ConfigDump and Admin::DynamicField::ConfigBuild.',
+ Required => 1,
+ HasValue => 1,
+ ValueRegex => qr/.*/smx,
+ );
+ $Self->AddOption(
+ Name => 'namespace',
+ Description => 'Namespace to place the new field into.',
+ Required => 0,
+ HasValue => 1,
+ ValueRegex => qr/[A-Za-z0-9]+/smx,
+ );
+ $Self->AddOption(
+ Name => 'field-order',
+ Description => 'Field order to place the field at. Defaults to hightest order plus 1. Per default, other fields are reordered if an occupied order number is chosen.',
+ Required => 0,
+ HasValue => 1,
+ ValueRegex => qr/\d+/smx,
+ );
+ $Self->AddOption(
+ Name => 'reorder',
+ Description => 'Whether to reorder other fields if an occupied order number is chosen. Defaults to 1.',
+ Required => 0,
+ HasValue => 1,
+ ValueRegex => qr/\d/smx,
+ );
+ $Self->AddOption(
+ Name => 'valid',
+ Description => 'Whether the field to add is valid or invalid. Defaults to 1.',
+ Required => 0,
+ HasValue => 1,
+ ValueRegex => qr/\d/smx,
+ );
+
+ return;
+}
+
+sub Run {
+ my ( $Self, %Param ) = @_;
+
+ $Self->Print("Adding a new dynamic field...\n");
+
+ # get necessary objects
+ my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
+
+ # check field order
+ my $DynamicFieldList = $DynamicFieldObject->DynamicFieldListGet(
+ ObjectType => 'All',
+ Valid => 0,
+ );
+ my $FieldOrder = $Self->GetOption('field-order') || max map { $_->{FieldOrder} } $DynamicFieldList->@*;
+
+ # check config string
+ # trying to parse as yaml and as json - if both fails, not valid
+ my $PlainConfig = $Self->GetOption('config');
+
+ $Self->Print("Trying to parse config as YAML...\n");
+ my $ConfigHashRef = $Kernel::OM->Get('Kernel::System::YAML')->Load(
+ Data => $PlainConfig,
+ );
+
+ if ( !defined $ConfigHashRef ) {
+ $Self->Print("Parsing config as YAML failed. Trying JSON now...\n");
+ $ConfigHashRef = $Kernel::OM->Get('Kernel::System::JSON')->Decode(
+ Data => $PlainConfig,
+ );
+ if ( !defined $ConfigHashRef ) {
+ $Self->Print("Parsing config as JSON failed also. Aborting.\n");
+ return $Self->ExitCodeError();
+ }
+ };
+
+ # check namespace
+ my $Namespace = $Self->GetOption('namespace');
+ my $Name = $Self->GetOption('name');
+ if ( $Namespace ) {
+ $Name = "$Namespace-$Name";
+ }
+
+ # add queue
+ my $Success = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldAdd(
+ Name => $Name,
+ Label => $Self->GetOption('label'),
+ FieldOrder => $FieldOrder,
+ FieldType => $Self->GetOption('field-type'),
+ ObjectType => $Self->GetOption('object-type'),
+ Config => $ConfigHashRef,
+ Reorder => $Self->GetOption('reorder') || 1,
+ ValidID => $Self->GetOption('valid') || 1,
+ UserID => 1,
+ );
+
+ # error handling
+ if ( !$Success ) {
+ $Self->PrintError("Can't create dynamic field.\n");
+ return $Self->ExitCodeError();
+ }
+
+ $Self->Print("Done.\n");
+
+ return $Self->ExitCodeOk();
+}
+
+1;