diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py
index 340ed10436..adefdb5732 100755
--- a/lib/python/qmk/cli/generate/config_h.py
+++ b/lib/python/qmk/cli/generate/config_h.py
@@ -9,7 +9,9 @@ from qmk.info import info_json
 from qmk.json_schema import json_load, validate
 from qmk.keyboard import keyboard_completer, keyboard_folder
 from qmk.keymap import locate_keymap
+from qmk.commands import dump_lines
 from qmk.path import normpath
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
 
 
 def direct_pins(direct_pins, postfix):
@@ -186,7 +188,7 @@ def generate_config_h(cli):
         kb_info_json = dotty(info_json(cli.args.keyboard))
 
     # Build the info_config.h file.
-    config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.', ' */', '', '#pragma once']
+    config_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
 
     generate_config_items(kb_info_json, config_h_lines)
 
@@ -199,16 +201,4 @@ def generate_config_h(cli):
         generate_split_config(kb_info_json, config_h_lines)
 
     # Show the results
-    config_h = '\n'.join(config_h_lines)
-
-    if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(config_h, encoding='utf-8')
-
-        if not cli.args.quiet:
-            cli.log.info('Wrote info_config.h to %s.', cli.args.output)
-
-    else:
-        print(config_h)
+    dump_lines(cli.args.output, config_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/generate/dfu_header.py b/lib/python/qmk/cli/generate/dfu_header.py
index 7fb585fc7d..e873117387 100644
--- a/lib/python/qmk/cli/generate/dfu_header.py
+++ b/lib/python/qmk/cli/generate/dfu_header.py
@@ -7,6 +7,8 @@ from qmk.decorators import automagic_keyboard
 from qmk.info import info_json
 from qmk.path import is_keyboard, normpath
 from qmk.keyboard import keyboard_completer
+from qmk.commands import dump_lines
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
 
 
 @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@@ -30,7 +32,7 @@ def generate_dfu_header(cli):
     # Build the Keyboard.h file.
     kb_info_json = dotty(info_json(cli.config.generate_dfu_header.keyboard))
 
-    keyboard_h_lines = ['/* This file was generated by `qmk generate-dfu-header`. Do not edit or copy.', ' */', '', '#pragma once']
+    keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
     keyboard_h_lines.append(f'#define MANUFACTURER {kb_info_json["manufacturer"]}')
     keyboard_h_lines.append(f'#define PRODUCT {kb_info_json["keyboard_name"]} Bootloader')
 
@@ -45,16 +47,4 @@ def generate_dfu_header(cli):
         keyboard_h_lines.append(f'#define QMK_SPEAKER {kb_info_json["qmk_lufa_bootloader.speaker"]}')
 
     # Show the results
-    keyboard_h = '\n'.join(keyboard_h_lines)
-
-    if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(keyboard_h)
-
-        if not cli.args.quiet:
-            cli.log.info('Wrote Keyboard.h to %s.', cli.args.output)
-
-    else:
-        print(keyboard_h)
+    dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/generate/keyboard_h.py b/lib/python/qmk/cli/generate/keyboard_h.py
index f05178cede..2058865cbf 100755
--- a/lib/python/qmk/cli/generate/keyboard_h.py
+++ b/lib/python/qmk/cli/generate/keyboard_h.py
@@ -3,8 +3,10 @@
 from milc import cli
 
 from qmk.info import info_json
+from qmk.commands import dump_lines
 from qmk.keyboard import keyboard_completer, keyboard_folder
 from qmk.path import normpath
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
 
 
 def would_populate_layout_h(keyboard):
@@ -36,22 +38,10 @@ def generate_keyboard_h(cli):
     has_layout_h = would_populate_layout_h(cli.args.keyboard)
 
     # Build the layouts.h file.
-    keyboard_h_lines = ['/* This file was generated by `qmk generate-keyboard-h`. Do not edit or copy.', ' */', '', '#pragma once', '#include "quantum.h"']
+    keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "quantum.h"']
 
     if not has_layout_h:
         keyboard_h_lines.append('#pragma error("<keyboard>.h is only optional for data driven keyboards - kb.h == bad times")')
 
     # Show the results
-    keyboard_h = '\n'.join(keyboard_h_lines) + '\n'
-
-    if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(keyboard_h)
-
-        if not cli.args.quiet:
-            cli.log.info('Wrote keyboard_h to %s.', cli.args.output)
-
-    else:
-        print(keyboard_h)
+    dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/generate/layouts.py b/lib/python/qmk/cli/generate/layouts.py
index a21311bd49..193633baf6 100755
--- a/lib/python/qmk/cli/generate/layouts.py
+++ b/lib/python/qmk/cli/generate/layouts.py
@@ -2,11 +2,12 @@
 """
 from milc import cli
 
-from qmk.constants import COL_LETTERS, ROW_LETTERS
+from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
 from qmk.decorators import automagic_keyboard, automagic_keymap
 from qmk.info import info_json
 from qmk.keyboard import keyboard_completer, keyboard_folder
 from qmk.path import is_keyboard, normpath
+from qmk.commands import dump_lines
 
 usb_properties = {
     'vid': 'VENDOR_ID',
@@ -38,7 +39,7 @@ def generate_layouts(cli):
     kb_info_json = info_json(cli.config.generate_layouts.keyboard)
 
     # Build the layouts.h file.
-    layouts_h_lines = ['/* This file was generated by `qmk generate-layouts`. Do not edit or copy.', ' */', '', '#pragma once']
+    layouts_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
 
     if 'matrix_size' not in kb_info_json:
         cli.log.error('%s: Invalid matrix config.', cli.config.generate_layouts.keyboard)
@@ -86,16 +87,4 @@ def generate_layouts(cli):
         layouts_h_lines.append('#endif')
 
     # Show the results
-    layouts_h = '\n'.join(layouts_h_lines) + '\n'
-
-    if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(layouts_h)
-
-        if not cli.args.quiet:
-            cli.log.info('Wrote info_config.h to %s.', cli.args.output)
-
-    else:
-        print(layouts_h)
+    dump_lines(cli.args.output, layouts_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py
index a1b10cc945..6f342c6567 100755
--- a/lib/python/qmk/cli/generate/rules_mk.py
+++ b/lib/python/qmk/cli/generate/rules_mk.py
@@ -9,7 +9,9 @@ from qmk.info import info_json
 from qmk.json_schema import json_load, validate
 from qmk.keyboard import keyboard_completer, keyboard_folder
 from qmk.keymap import locate_keymap
+from qmk.commands import dump_lines
 from qmk.path import normpath
+from qmk.constants import GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE
 
 
 def process_mapping_rule(kb_info_json, rules_key, info_dict):
@@ -57,7 +59,7 @@ def generate_rules_mk(cli):
         kb_info_json = dotty(info_json(cli.args.keyboard))
 
     info_rules_map = json_load(Path('data/mappings/info_rules.json'))
-    rules_mk_lines = ['# This file was generated by `qmk generate-rules-mk`. Do not edit or copy.', '']
+    rules_mk_lines = [GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE]
 
     # Iterate through the info_rules map to generate basic rules
     for rules_key, info_dict in info_rules_map.items():
@@ -85,14 +87,9 @@ def generate_rules_mk(cli):
             rules_mk_lines.append('CUSTOM_MATRIX ?= yes')
 
     # Show the results
-    rules_mk = '\n'.join(rules_mk_lines) + '\n'
+    dump_lines(cli.args.output, rules_mk_lines)
 
     if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(rules_mk)
-
         if cli.args.quiet:
             if cli.args.escape:
                 print(cli.args.output.as_posix().replace(' ', '\\ '))
@@ -100,6 +97,3 @@ def generate_rules_mk(cli):
                 print(cli.args.output)
         else:
             cli.log.info('Wrote rules.mk to %s.', cli.args.output)
-
-    else:
-        print(rules_mk)
diff --git a/lib/python/qmk/cli/generate/version_h.py b/lib/python/qmk/cli/generate/version_h.py
index 69341e36f0..be9646748e 100644
--- a/lib/python/qmk/cli/generate/version_h.py
+++ b/lib/python/qmk/cli/generate/version_h.py
@@ -1,9 +1,15 @@
 """Used by the make system to generate version.h for use in code.
 """
+from time import strftime
+
 from milc import cli
 
-from qmk.commands import create_version_h
 from qmk.path import normpath
+from qmk.commands import dump_lines
+from qmk.commands import get_git_version
+from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
+
+TIME_FMT = '%Y-%m-%d-%H:%M:%S'
 
 
 @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@@ -17,15 +23,29 @@ def generate_version_h(cli):
     if cli.args.skip_all:
         cli.args.skip_git = True
 
-    version_h = create_version_h(cli.args.skip_git, cli.args.skip_all)
-
-    if cli.args.output:
-        cli.args.output.parent.mkdir(parents=True, exist_ok=True)
-        if cli.args.output.exists():
-            cli.args.output.replace(cli.args.output.parent / (cli.args.output.name + '.bak'))
-        cli.args.output.write_text(version_h)
-
-        if not cli.args.quiet:
-            cli.log.info('Wrote version.h to %s.', cli.args.output)
+    if cli.args.skip_all:
+        current_time = "1970-01-01-00:00:00"
     else:
-        print(version_h)
+        current_time = strftime(TIME_FMT)
+
+    if cli.args.skip_git:
+        git_version = "NA"
+        chibios_version = "NA"
+        chibios_contrib_version = "NA"
+    else:
+        git_version = get_git_version(current_time)
+        chibios_version = get_git_version(current_time, "chibios", "os")
+        chibios_contrib_version = get_git_version(current_time, "chibios-contrib", "os")
+
+    # Build the version.h file.
+    version_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
+
+    version_h_lines.append(f"""
+#define QMK_VERSION "{git_version}"
+#define QMK_BUILDDATE "{current_time}"
+#define CHIBIOS_VERSION "{chibios_version}"
+#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"
+""")
+
+    # Show the results
+    dump_lines(cli.args.output, version_h_lines, cli.args.quiet)
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py
index e38f17156a..49a344bab4 100644
--- a/lib/python/qmk/commands.py
+++ b/lib/python/qmk/commands.py
@@ -5,7 +5,6 @@ import sys
 import shutil
 from pathlib import Path
 from subprocess import DEVNULL
-from time import strftime
 
 from milc import cli
 import jsonschema
@@ -14,8 +13,6 @@ import qmk.keymap
 from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
 from qmk.json_schema import json_load, validate
 
-time_fmt = '%Y-%m-%d-%H:%M:%S'
-
 
 def _find_make():
     """Returns the correct make command for this environment.
@@ -136,37 +133,6 @@ def get_make_parallel_args(parallel=1):
     return parallel_args
 
 
-def create_version_h(skip_git=False, skip_all=False):
-    """Generate version.h contents
-    """
-    if skip_all:
-        current_time = "1970-01-01-00:00:00"
-    else:
-        current_time = strftime(time_fmt)
-
-    if skip_git:
-        git_version = "NA"
-        chibios_version = "NA"
-        chibios_contrib_version = "NA"
-    else:
-        git_version = get_git_version(current_time)
-        chibios_version = get_git_version(current_time, "chibios", "os")
-        chibios_contrib_version = get_git_version(current_time, "chibios-contrib", "os")
-
-    version_h_lines = f"""/* This file was automatically generated. Do not edit or copy.
- */
-
-#pragma once
-
-#define QMK_VERSION "{git_version}"
-#define QMK_BUILDDATE "{current_time}"
-#define CHIBIOS_VERSION "{chibios_version}"
-#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"
-"""
-
-    return version_h_lines
-
-
 def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_vars):
     """Convert a configurator export JSON file into a C file and then compile it.
 
@@ -201,9 +167,6 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va
     keymap_dir.mkdir(exist_ok=True, parents=True)
     keymap_c.write_text(c_text)
 
-    version_h = Path('quantum/version.h')
-    version_h.write_text(create_version_h())
-
     # Return a command that can be run to make the keymap and flash if given
     verbose = 'true' if cli.config.general.verbose else 'false'
     color = 'true' if cli.config.general.color else 'false'
@@ -357,3 +320,20 @@ def in_virtualenv():
     """
     active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
     return active_prefix != sys.prefix
+
+
+def dump_lines(output_file, lines, quiet=True):
+    """Handle dumping to stdout or file
+    Creates parent folders if required
+    """
+    generated = '\n'.join(lines) + '\n'
+    if output_file and output_file.name != '-':
+        output_file.parent.mkdir(parents=True, exist_ok=True)
+        if output_file.exists():
+            output_file.replace(output_file.parent / (output_file.name + '.bak'))
+        output_file.write_text(generated, encoding='utf-8')
+
+        if not quiet:
+            cli.log.info(f'Wrote {output_file.name} to {output_file}.')
+    else:
+        print(generated)
diff --git a/lib/python/qmk/constants.py b/lib/python/qmk/constants.py
index e4b699cdb1..6956b70772 100644
--- a/lib/python/qmk/constants.py
+++ b/lib/python/qmk/constants.py
@@ -1,6 +1,7 @@
 """Information that should be available to the python library.
 """
 from os import environ
+from datetime import date
 from pathlib import Path
 
 # The root of the qmk_firmware tree.
@@ -75,3 +76,65 @@ LED_INDICATORS = {
 # Constants that should match their counterparts in make
 BUILD_DIR = environ.get('BUILD_DIR', '.build')
 KEYBOARD_OUTPUT_PREFIX = f'{BUILD_DIR}/obj_'
+
+# Headers for generated files
+GPL2_HEADER_C_LIKE = f'''\
+// Copyright {date.today().year} QMK
+// SPDX-License-Identifier: GPL-2.0-or-later
+'''
+
+GPL2_HEADER_SH_LIKE = f'''\
+# Copyright {date.today().year} QMK
+# SPDX-License-Identifier: GPL-2.0-or-later
+'''
+
+GENERATED_HEADER_C_LIKE = '''\
+/*******************************************************************************
+  88888888888 888      d8b                .d888 d8b 888               d8b
+      888     888      Y8P               d88P"  Y8P 888               Y8P
+      888     888                        888        888
+      888     88888b.  888 .d8888b       888888 888 888  .d88b.       888 .d8888b
+      888     888 "88b 888 88K           888    888 888 d8P  Y8b      888 88K
+      888     888  888 888 "Y8888b.      888    888 888 88888888      888 "Y8888b.
+      888     888  888 888      X88      888    888 888 Y8b.          888      X88
+      888     888  888 888  88888P'      888    888 888  "Y8888       888  88888P'
+                                                        888                 888
+                                                        888                 888
+                                                        888                 888
+     .d88b.   .d88b.  88888b.   .d88b.  888d888 8888b.  888888 .d88b.   .d88888
+    d88P"88b d8P  Y8b 888 "88b d8P  Y8b 888P"      "88b 888   d8P  Y8b d88" 888
+    888  888 88888888 888  888 88888888 888    .d888888 888   88888888 888  888
+    Y88b 888 Y8b.     888  888 Y8b.     888    888  888 Y88b. Y8b.     Y88b 888
+     "Y88888  "Y8888  888  888  "Y8888  888    "Y888888  "Y888 "Y8888   "Y88888
+         888
+    Y8b d88P
+     "Y88P"
+*******************************************************************************/
+'''
+
+GENERATED_HEADER_SH_LIKE = '''\
+################################################################################
+#
+# 88888888888 888      d8b                .d888 d8b 888               d8b
+#     888     888      Y8P               d88P"  Y8P 888               Y8P
+#     888     888                        888        888
+#     888     88888b.  888 .d8888b       888888 888 888  .d88b.       888 .d8888b
+#     888     888 "88b 888 88K           888    888 888 d8P  Y8b      888 88K
+#     888     888  888 888 "Y8888b.      888    888 888 88888888      888 "Y8888b.
+#     888     888  888 888      X88      888    888 888 Y8b.          888      X88
+#     888     888  888 888  88888P'      888    888 888  "Y8888       888  88888P'
+#
+#                                                       888                 888
+#                                                       888                 888
+#                                                       888                 888
+#    .d88b.   .d88b.  88888b.   .d88b.  888d888 8888b.  888888 .d88b.   .d88888
+#   d88P"88b d8P  Y8b 888 "88b d8P  Y8b 888P"      "88b 888   d8P  Y8b d88" 888
+#   888  888 88888888 888  888 88888888 888    .d888888 888   88888888 888  888
+#   Y88b 888 Y8b.     888  888 Y8b.     888    888  888 Y88b. Y8b.     Y88b 888
+#    "Y88888  "Y8888  888  888  "Y8888  888    "Y888888  "Y888 "Y8888   "Y88888
+#        888
+#   Y8b d88P
+#    "Y88P"
+#
+################################################################################
+'''