diff --git a/Changelog.md b/Changelog.md
index 7300e570c30194f361316b08700133eefa8354fd..b613678bb97b126c573cee17bf94d1f53be693ab 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,9 @@
 # Changelog
 
+# [3.5] - 2025-05-12
+- Add a new CLI command for interacting with the task scheduler.
+- Fix a bug in the subscription validation task.
+
 # [3.4] - 2025-05-08
 - Fix some bugs in the nightly validation schedule.
 
diff --git a/gso/__init__.py b/gso/__init__.py
index 8ed08f8e1716e9f6e04d6cd244253b43f01875d8..99f1d386081a807a5c7b34527ba890cafe7aab1e 100644
--- a/gso/__init__.py
+++ b/gso/__init__.py
@@ -65,10 +65,11 @@ def init_gso_app() -> OrchestratorCore:
 
 def init_cli_app() -> typer.Typer:
     """Initialise GSO as a CLI application."""
-    from gso.cli import imports, netbox  # noqa: PLC0415
+    from gso.cli import imports, netbox, schedule  # noqa: PLC0415
 
     cli_app.add_typer(imports.app, name="import-cli")
     cli_app.add_typer(netbox.app, name="netbox-cli")
+    cli_app.add_typer(schedule.app, name="schedule-cli")
     return cli_app()
 
 
diff --git a/gso/cli/schedule.py b/gso/cli/schedule.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0a29c0560948cb75bb5a00572751c32d667f265
--- /dev/null
+++ b/gso/cli/schedule.py
@@ -0,0 +1,46 @@
+"""CLI for interacting with the task scheduler. Only supports running a single task."""
+
+# <!-- vale off -->
+# Copyright 2019-2020 SURF.
+# Copyright 2025 GÉANT Vereniging.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# <!-- vale on -->
+
+import logging
+from collections.abc import Callable
+
+import typer
+
+from gso.schedules.clean_old_tasks import clean_old_tasks
+from gso.schedules.send_email_notifications import send_email_notifications
+from gso.schedules.validate_products import validate_products
+from gso.schedules.validate_subscriptions import validate_subscriptions
+
+logger = logging.getLogger(__name__)
+
+app: typer.Typer = typer.Typer()
+
+ALL_SCHEDULES: list[Callable] = [
+    clean_old_tasks,
+    send_email_notifications,
+    validate_products,
+    validate_subscriptions,
+]
+
+
+@app.command()
+def run_task(task_name: str) -> None:
+    """Force the execution of a task by name."""
+    for s in ALL_SCHEDULES:
+        if task_name == s.__name__:
+            s()
diff --git a/gso/schedules/validate_subscriptions.py b/gso/schedules/validate_subscriptions.py
index 7323b6086b948201da4a0f5b0ee1574030646076..db3573802cd6d9fb29438068fa3737a57f0b4bf9 100644
--- a/gso/schedules/validate_subscriptions.py
+++ b/gso/schedules/validate_subscriptions.py
@@ -37,26 +37,43 @@ def validate_subscriptions() -> None:
         return
 
     for subscription in subscriptions:
-        validation_workflow = None
-
+        found_a_validation_workflow = False
         for workflow in subscription.product.workflows:
             if workflow.target == Target.SYSTEM and workflow.name.startswith("validate_"):
                 validation_workflow = workflow.name
-
-            if validation_workflow:
+                found_a_validation_workflow = True
                 validation_workflow_usable = (subscription.status in TARGET_DEFAULT_USABLE_MAP[Target.SYSTEM]) and (
-                    subscription.insync or (workflow in WF_USABLE_WHILE_OUT_OF_SYNC)
+                    subscription.insync or (validation_workflow in WF_USABLE_WHILE_OUT_OF_SYNC)
                 )
 
                 if validation_workflow_usable:
-                    json = [{"subscription_id": str(subscription.subscription_id)}]
+                    logger.info(
+                        "Found a usable validation workflow, scheduling task.",
+                        product=subscription.product.name,
+                        subscription_id=subscription.subscription_id,
+                        subscription_description=subscription.description,
+                        workflow=validation_workflow,
+                    )
 
+                    json = [{"subscription_id": str(subscription.subscription_id)}]
                     validate_func = get_execution_context()["validate"]
                     validate_func(validation_workflow, json=json)
 
-        if not validation_workflow:
+                else:
+                    logger.info(
+                        "Validation workflow is not usable on this subscription instance",
+                        product=subscription.product.name,
+                        subscription_id=subscription.subscription_id,
+                        subscription_description=subscription.description,
+                        status=subscription.status,
+                        insync=subscription.insync,
+                        workflow=validation_workflow,
+                    )
+
+        if not found_a_validation_workflow:
             logger.warning(
                 "SubscriptionTable has no validation workflow",
-                subscription=subscription,
                 product=subscription.product.name,
+                subscription_id=subscription.subscription_id,
+                subscription_description=subscription.description,
             )
diff --git a/setup.py b/setup.py
index 58344ee060832df1d14ea56f7d86e56d1ab824a0..9cdc16edc8f47b2b6890bb3cd488a566c5315529 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
 
 setup(
     name="geant-service-orchestrator",
-    version="3.4",
+    version="3.5",
     author="GÉANT Orchestration and Automation Team",
     author_email="goat@geant.org",
     description="GÉANT Service Orchestrator",