diff --git a/op-mode-definitions/system-image.xml.in b/op-mode-definitions/system-image.xml.in
index 57aeb7bb4..463b985d6 100644
--- a/op-mode-definitions/system-image.xml.in
+++ b/op-mode-definitions/system-image.xml.in
@@ -1,189 +1,201 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interfaceDefinition>
   <node name="add">
     <properties>
       <help>Add an object</help>
     </properties>
     <children>
       <node name="system">
         <properties>
           <help>Add item to a system facility</help>
         </properties>
         <children>
           <tagNode name="image">
             <properties>
               <help>Add a new image to the system</help>
               <completionHelp>
                 <list>/path/to/vyos-image.iso "http://example.com/vyos-image.iso"</list>
               </completionHelp>
             </properties>
             <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}"</command>
             <children>
               <tagNode name="vrf">
                 <properties>
                   <help>Download image via specified VRF</help>
                   <completionHelp>
                     <path>vrf name</path>
                   </completionHelp>
                 </properties>
                 <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --vrf "${6}"</command>
                 <children>
                   <tagNode name="username">
                     <properties>
                       <help>Username for authentication</help>
                     </properties>
                     <children>
                       <tagNode name="password">
                         <properties>
                           <help>Password to use with authentication</help>
                         </properties>
                         <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --vrf "${6}" --username "${8}" --password "${10}"</command>
                       </tagNode>
                     </children>
                   </tagNode>
                 </children>
               </tagNode>
               <tagNode name="username">
                 <properties>
                   <help>Username for authentication</help>
                 </properties>
                 <children>
                   <tagNode name="password">
                     <properties>
                       <help>Password to use with authentication</help>
                     </properties>
                     <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action add --image_path "${4}" --username "${6}" --password "${8}"</command>
                   </tagNode>
                 </children>
               </tagNode>
             </children>
           </tagNode>
         </children>
       </node>
     </children>
   </node>
   <node name="set">
     <properties>
       <help>Install a new system</help>
     </properties>
     <children>
       <node name="system">
         <properties>
           <help>Set system operational parameters</help>
         </properties>
         <children>
           <node name="image">
             <properties>
               <help>Set system image parameters</help>
             </properties>
             <children>
+              <node name="default-boot">
+                <properties>
+                  <help>Set default image to boot.</help>
+                </properties>
+                <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set</command>
+              </node>
               <tagNode name="default-boot">
                 <properties>
                   <help>Set default image to boot.</help>
                   <completionHelp>
                     <script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list</script>
                   </completionHelp>
                 </properties>
                 <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action set --image_name "${5}"</command>
               </tagNode>
             </children>
           </node>
         </children>
       </node>
     </children>
   </node>
   <node name="install">
     <properties>
       <help>Install a new system</help>
     </properties>
     <children>
       <node name="image">
         <properties>
           <help>Install new system image to hard drive</help>
         </properties>
         <command>sudo ${vyos_op_scripts_dir}/image_installer.py --action install</command>
       </node>
     </children>
   </node>
   <node name="delete">
     <properties>
       <help>Delete an object</help>
     </properties>
     <children>
       <node name="system">
         <properties>
           <help>Delete system objects</help>
         </properties>
         <children>
+          <node name="image">
+            <properties>
+              <help>Remove an installed image from the system</help>
+            </properties>
+            <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action delete</command>
+          </node>
           <tagNode name="image">
             <properties>
               <help>Remove an installed image from the system</help>
               <completionHelp>
                 <script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list</script>
               </completionHelp>
             </properties>
             <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action delete --image_name "${4}"</command>
           </tagNode>
         </children>
       </node>
     </children>
   </node>
   <node name="rename">
     <properties>
       <help>Rename an object</help>
     </properties>
     <children>
       <node name="system">
         <properties>
           <help>Rename a system object</help>
         </properties>
         <children>
           <tagNode name="image">
             <properties>
               <help>System image to rename</help>
               <completionHelp>
                 <script>sudo ${vyos_op_scripts_dir}/image_manager.py --action list</script>
               </completionHelp>
             </properties>
             <children>
               <tagNode name="to">
                 <properties>
                   <help>A new name for an image</help>
                 </properties>
                 <command>sudo ${vyos_op_scripts_dir}/image_manager.py --action rename --image_name "${4}" --image_new_name "${6}"</command>
               </tagNode>
             </children>
           </tagNode>
         </children>
       </node>
     </children>
   </node>
   <node name="show">
     <properties>
       <help>Rename an object</help>
     </properties>
     <children>
       <node name="system">
         <properties>
           <help>Show system information</help>
         </properties>
         <children>
           <node name="image">
             <properties>
               <help>Show installed VyOS images</help>
             </properties>
             <command>sudo ${vyos_op_scripts_dir}/image_info.py show_images_summary</command>
             <children>
               <node name="details">
                 <properties>
                   <help>Show details about installed VyOS images</help>
                 </properties>
                 <command>sudo ${vyos_op_scripts_dir}/image_info.py show_images_details</command>
               </node>
             </children>
           </node>
         </children>
       </node>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/python/vyos/utils/io.py b/python/vyos/utils/io.py
index 8790cbaac..e34a1ba32 100644
--- a/python/vyos/utils/io.py
+++ b/python/vyos/utils/io.py
@@ -1,74 +1,93 @@
 # Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # License as published by the Free Software Foundation; either
 # version 2.1 of the License, or (at your option) any later version.
 #
 # This library 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
 # Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 def print_error(str='', end='\n'):
     """
     Print `str` to stderr, terminated with `end`.
     Used for warnings and out-of-band messages to avoid mangling precious
      stdout output.
     """
     import sys
     sys.stderr.write(str)
     sys.stderr.write(end)
     sys.stderr.flush()
 
 def ask_input(question, default='', numeric_only=False, valid_responses=[]):
     question_out = question
     if default:
         question_out += f' (Default: {default})'
     response = ''
     while True:
         response = input(question_out + ' ').strip()
         if not response and default:
             return default
         if numeric_only:
             if not response.isnumeric():
                 print("Invalid value, try again.")
                 continue
             response = int(response)
         if valid_responses and response not in valid_responses:
             print("Invalid value, try again.")
             continue
         break
     return response
 
 def ask_yes_no(question, default=False) -> bool:
     """Ask a yes/no question via input() and return their answer."""
     from sys import stdout
     default_msg = "[Y/n]" if default else "[y/N]"
     while True:
         try:
             stdout.write("%s %s " % (question, default_msg))
             c = input().lower()
             if c == '':
                 return default
             elif c in ("y", "ye", "yes"):
                 return True
             elif c in ("n", "no"):
                 return False
             else:
                 stdout.write("Please respond with yes/y or no/n\n")
         except EOFError:
             stdout.write("\nPlease respond with yes/y or no/n\n")
 
 def is_interactive():
     """Try to determine if the routine was called from an interactive shell."""
     import os, sys
     return os.getenv('TERM', default=False) and sys.stderr.isatty() and sys.stdout.isatty()
 
 def is_dumb_terminal():
     """Check if the current TTY is dumb, so that we can disable advanced terminal features."""
     import os
     return os.getenv('TERM') in ['vt100', 'dumb']
+
+def select_entry(l: list, list_msg: str = '', prompt_msg: str = '') -> str:
+    """Select an entry from a list
+
+    Args:
+        l (list): a list of entries
+        list_msg (str): a message to print before listing the entries
+        prompt_msg (str): a message to print as prompt for selection
+
+    Returns:
+        str: a selected entry
+    """
+    en = list(enumerate(l, 1))
+    print(list_msg)
+    for i, e in en:
+        print(f'\t{i}: {e}')
+    select = ask_input(prompt_msg, numeric_only=True,
+                       valid_responses=range(1, len(l)+1))
+    return next(filter(lambda x: x[0] == select, en))[1]
diff --git a/src/op_mode/image_manager.py b/src/op_mode/image_manager.py
index 55fd5c07d..de53c4cf0 100755
--- a/src/op_mode/image_manager.py
+++ b/src/op_mode/image_manager.py
@@ -1,187 +1,207 @@
 #!/usr/bin/env python3
 #
 # Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This file is part of VyOS.
 #
 # VyOS 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.
 #
 # VyOS 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
 # VyOS. If not, see <https://www.gnu.org/licenses/>.
 
 from argparse import ArgumentParser, Namespace
 from pathlib import Path
 from shutil import rmtree
 from sys import exit
+from typing import Optional
 
 from vyos.system import disk, grub, image, compat
-from vyos.utils.io import ask_yes_no
+from vyos.utils.io import ask_yes_no, select_entry
+
+SET_IMAGE_LIST_MSG: str = 'The following images are available:'
+SET_IMAGE_PROMPT_MSG: str = 'Select an image to set as default:'
+DELETE_IMAGE_LIST_MSG: str = 'The following images are installed:'
+DELETE_IMAGE_PROMPT_MSG: str = 'Select an image to delete:'
+MSG_DELETE_IMAGE_RUNNING: str = 'Currently running image cannot be deleted; reboot into another image first'
+MSG_DELETE_IMAGE_DEFAULT: str = 'Default image cannot be deleted; set another image as default first'
 
 
 @compat.grub_cfg_update
-def delete_image(image_name: str) -> None:
+def delete_image(image_name: Optional[str] = None,
+                 prompt: bool = True) -> None:
     """Remove installed image files and boot entry
 
     Args:
         image_name (str): a name of image to delete
     """
+    available_images: list[str] = grub.version_list()
+    if image_name is None:
+        if not prompt:
+            exit('An image name is required for delete action')
+        else:
+            image_name = select_entry(available_images,
+                                      DELETE_IMAGE_LIST_MSG,
+                                      DELETE_IMAGE_PROMPT_MSG)
     if image_name == image.get_running_image():
-        exit('Currently running image cannot be deleted')
+        exit(MSG_DELETE_IMAGE_RUNNING)
     if image_name == image.get_default_image():
-        exit('Default image cannot be deleted')
-    available_images: list[str] = grub.version_list()
+        exit(MSG_DELETE_IMAGE_DEFAULT)
     if image_name not in available_images:
         exit(f'The image "{image_name}" cannot be found')
     presistence_storage: str = disk.find_persistence()
     if not presistence_storage:
         exit('Persistence storage cannot be found')
 
     if not ask_yes_no(f'Do you really want to delete the image {image_name}?',
                       default=False):
         exit()
 
     # remove files and menu entry
     version_path: Path = Path(f'{presistence_storage}/boot/{image_name}')
     try:
         rmtree(version_path)
         grub.version_del(image_name, presistence_storage)
         print(f'The image "{image_name}" was successfully deleted')
     except Exception as err:
         exit(f'Unable to remove the image "{image_name}": {err}')
 
 
 @compat.grub_cfg_update
-def set_image(image_name: str) -> None:
+def set_image(image_name: Optional[str] = None,
+              prompt: bool = True) -> None:
     """Set default boot image
 
     Args:
         image_name (str): an image name
     """
+    available_images: list[str] = grub.version_list()
+    if image_name is None:
+        if not prompt:
+            exit('An image name is required for set action')
+        else:
+            image_name = select_entry(available_images,
+                                      SET_IMAGE_LIST_MSG,
+                                      SET_IMAGE_PROMPT_MSG)
     if image_name == image.get_default_image():
         exit(f'The image "{image_name}" already configured as default')
-    available_images: list[str] = grub.version_list()
     if image_name not in available_images:
         exit(f'The image "{image_name}" cannot be found')
     presistence_storage: str = disk.find_persistence()
     if not presistence_storage:
         exit('Persistence storage cannot be found')
 
     # set default boot image
     try:
         grub.set_default(image_name, presistence_storage)
         print(f'The image "{image_name}" is now default boot image')
     except Exception as err:
         exit(f'Unable to set default image "{image_name}": {err}')
 
 
 @compat.grub_cfg_update
 def rename_image(name_old: str, name_new: str) -> None:
     """Rename installed image
 
     Args:
         name_old (str): old name
         name_new (str): new name
     """
     if name_old == image.get_running_image():
         exit('Currently running image cannot be renamed')
     available_images: list[str] = grub.version_list()
     if name_old not in available_images:
         exit(f'The image "{name_old}" cannot be found')
     if name_new in available_images:
         exit(f'The image "{name_new}" already exists')
     if not image.validate_name(name_new):
         exit(f'The image name "{name_new}" is not allowed')
 
     presistence_storage: str = disk.find_persistence()
     if not presistence_storage:
         exit('Persistence storage cannot be found')
 
     if not ask_yes_no(
             f'Do you really want to rename the image {name_old} '
             f'to the {name_new}?',
             default=False):
         exit()
 
     try:
         # replace default boot item
         if name_old == image.get_default_image():
             grub.set_default(name_new, presistence_storage)
 
         # rename files and dirs
         old_path: Path = Path(f'{presistence_storage}/boot/{name_old}')
         new_path: Path = Path(f'{presistence_storage}/boot/{name_new}')
         old_path.rename(new_path)
 
         # replace boot item
         grub.version_del(name_old, presistence_storage)
         grub.version_add(name_new, presistence_storage)
 
         print(f'The image "{name_old}" was renamed to "{name_new}"')
     except Exception as err:
         exit(f'Unable to rename image "{name_old}" to "{name_new}": {err}')
 
 
 def list_images() -> None:
     """Print list of available images for CLI hints"""
     images_list: list[str] = grub.version_list()
     for image_name in images_list:
         print(image_name)
 
 
 def parse_arguments() -> Namespace:
     """Parse arguments
 
     Returns:
         Namespace: a namespace with parsed arguments
     """
     parser: ArgumentParser = ArgumentParser(description='Manage system images')
     parser.add_argument('--action',
                         choices=['delete', 'set', 'rename', 'list'],
                         required=True,
                         help='action to perform with an image')
     parser.add_argument(
         '--image_name',
         help=
         'a name of an image to add, delete, install, rename, or set as default')
     parser.add_argument('--image_new_name', help='a new name for image')
     args: Namespace = parser.parse_args()
     # Validate arguments
-    if args.action == 'delete' and not args.image_name:
-        exit('An image name is required for delete action')
-    if args.action == 'set' and not args.image_name:
-        exit('An image name is required for set action')
     if args.action == 'rename' and (not args.image_name or
                                     not args.image_new_name):
         exit('Both old and new image names are required for rename action')
 
     return args
 
 
 if __name__ == '__main__':
     try:
         args: Namespace = parse_arguments()
         if args.action == 'delete':
             delete_image(args.image_name)
         if args.action == 'set':
             set_image(args.image_name)
         if args.action == 'rename':
             rename_image(args.image_name, args.image_new_name)
         if args.action == 'list':
             list_images()
 
         exit()
 
     except KeyboardInterrupt:
         print('Stopped by Ctrl+C')
         exit()
 
     except Exception as err:
         exit(f'{err}')