# Buggy code
def _windows_os_release_grain(caption, product_type):
    """
    helper function for getting the osrelease grain
    :return:
    """
    # This creates the osrelease grain based on the Windows Operating
    # System Product Name. As long as Microsoft maintains a similar format
    # this should be future proof
    version = "Unknown"
    release = ""
    if "Server" in caption:
        for item in caption.split(" "):
            # If it's all digits, then it's version
            if re.match(r"\d+", item):
                version = item
            # If it starts with R and then numbers, it's the release
            # ie: R2
            if re.match(r"^R\d+$", item):
                release = item
        os_release = "{0}Server{1}".format(version, release)
    else:
        for item in caption.split(" "):
            # If it's a number, decimal number, Thin or Vista, then it's the
            # version
            if re.match(r"^(\d+(\.\d+)?)|Thin|Vista|XP$", item):
                version = item
        os_release = version

    # If the version is still Unknown, revert back to the old way of getting
    # the os_release
    # https://github.com/saltstack/salt/issues/52339
    if os_release in ["Unknown"]:
        os_release = platform.release()
        server = {
            "Vista": "2008Server",
            "7": "2008ServerR2",
            "8": "2012Server",
            "8.1": "2012ServerR2",
            "10": "2016Server",
        }

        # Starting with Python 2.7.12 and 3.5.2 the `platform.uname()`
        # function started reporting the Desktop version instead of the
        # Server version on # Server versions of Windows, so we need to look
        # those up. So, if you find a Server Platform that's a key in the
        # server dictionary, then lookup the actual Server Release.
        # (Product Type 1 is Desktop, Everything else is Server)
        if product_type > 1 and os_release in server:
            os_release = server[os_release]

    return os_release


# Traceback (TypeError)
PS C:\salt> .\salt-minion-debug.bat
The salt-minion service is not started.

More help is available by typing NET HELPMSG 3521.

[DEBUG   ] Reading configuration from c:\salt\conf\minion
[DEBUG   ] Multiprocessing queue logging configured for the process running under PID: 2360 at log level 10
[DEBUG   ] Marking 'is_ip' as a jinja filter
[DEBUG   ] Marking 'is_ipv4' as a jinja filter
[DEBUG   ] Marking 'is_ipv6' as a jinja filter
[DEBUG   ] Marking 'ipv4' as a jinja filter
[DEBUG   ] Marking 'ipv6' as a jinja filter
[DEBUG   ] Marking 'ipaddr' as a jinja filter
[DEBUG   ] Marking 'ip_host' as a jinja filter
[DEBUG   ] Marking 'network_hosts' as a jinja filter
[DEBUG   ] Marking 'network_size' as a jinja filter
[DEBUG   ] Marking 'gen_mac' as a jinja filter
[DEBUG   ] Marking 'mac_str_to_bytes' as a jinja filter
[DEBUG   ] Marking 'dns_check' as a jinja filter
[DEBUG   ] Multiprocessing queue logging configured for the process running under PID: 2360 at log level 10
[DEBUG   ] Configuration file path: c:\salt\conf\minion
[WARNING ] Insecure logging configuration detected! Sensitive data may be logged.
[INFO    ] Setting up the Salt Minion "MY-MINION-NAME"
[DEBUG   ] Marking 'base64_encode' as a jinja filter
[DEBUG   ] Marking 'base64_decode' as a jinja filter
[DEBUG   ] Marking 'md5' as a jinja filter
[DEBUG   ] Marking 'sha256' as a jinja filter
[DEBUG   ] Marking 'sha512' as a jinja filter
[DEBUG   ] Marking 'hmac' as a jinja filter
[DEBUG   ] Marking 'random_hash' as a jinja filter
[DEBUG   ] Marking 'rand_str' as a jinja filter
[DEBUG   ] Marking 'file_hashsum' as a jinja filter
[DEBUG   ] Marking 'http_query' as a jinja filter
[DEBUG   ] Marking 'strftime' as a jinja filter
[DEBUG   ] Marking 'date_format' as a jinja filter
[DEBUG   ] Marking 'yaml_dquote' as a jinja filter
[DEBUG   ] Marking 'yaml_squote' as a jinja filter
[DEBUG   ] Marking 'yaml_encode' as a jinja filter
[DEBUG   ] Marking 'raise' as a jinja global
[DEBUG   ] Marking 'match' as a jinja test
[DEBUG   ] Marking 'equalto' as a jinja test
[DEBUG   ] Marking 'skip' as a jinja filter
[DEBUG   ] Marking 'sequence' as a jinja filter
[DEBUG   ] Marking 'to_bool' as a jinja filter
[DEBUG   ] Marking 'tojson' as a jinja filter
[DEBUG   ] Marking 'quote' as a jinja filter
[DEBUG   ] Marking 'regex_escape' as a jinja filter
[DEBUG   ] Marking 'regex_search' as a jinja filter
[DEBUG   ] Marking 'regex_match' as a jinja filter
[DEBUG   ] Marking 'regex_replace' as a jinja filter
[DEBUG   ] Marking 'uuid' as a jinja filter
[DEBUG   ] Marking 'unique' as a jinja filter
[DEBUG   ] Marking 'min' as a jinja filter
[DEBUG   ] Marking 'max' as a jinja filter
[DEBUG   ] Marking 'avg' as a jinja filter
[DEBUG   ] Marking 'union' as a jinja filter
[DEBUG   ] Marking 'intersect' as a jinja filter
[DEBUG   ] Marking 'difference' as a jinja filter
[DEBUG   ] Marking 'symmetric_difference' as a jinja filter
[DEBUG   ] Created pidfile: c:\salt\var\run\salt-minion.pid
[INFO    ] Starting up the Salt Minion
[DEBUG   ] AsyncEventPublisher PUB socket URI: 4510
[DEBUG   ] AsyncEventPublisher PULL socket URI: 4511
[INFO    ] Starting pull socket on 4511
[DEBUG   ] SaltEvent PUB socket URI: 4510
[DEBUG   ] SaltEvent PULL socket URI: 4511
[DEBUG   ] Grains refresh requested. Refreshing grains.
[DEBUG   ] Reading configuration from c:\salt\conf\minion
[DEBUG   ] Motherboard info not available on this system
Traceback (most recent call last):
File "C:\salt\bin\Scripts\salt-minion", line 26, in <module>
[ERROR   ] An un-handled exception was caught by salt's global exception handler:
TypeError: argument of type 'NoneType' is not iterable
Traceback (most recent call last):
File "C:\salt\bin\Scripts\salt-minion", line 26, in <module>
salt_minion()
File "C:\salt\bin\lib\site-packages\salt\scripts.py", line 191, in salt_minion
minion.start()
File "C:\salt\bin\lib\site-packages\salt\cli\daemons.py", line 346, in start
self._real_start()
File "C:\salt\bin\lib\site-packages\salt\cli\daemons.py", line 358, in _real_start
self.minion.tune_in()
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1065, in tune_in
self._spawn_minions()
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1009, in _spawn_minions
jid_queue=self.jid_queue)
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 977, in _create_minion_object
jid_queue=jid_queue)
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1136, in __init__
self.opts['grains'] = salt.loader.grains(opts)
File "C:\salt\bin\lib\site-packages\salt\loader.py", line 784, in grains
ret = funcs[key]()
File "C:\salt\bin\lib\site-packages\salt\grains\core.py", line 1662, in os_data
if 'Server' in grains['osrelease']:
TypeError: argument of type 'NoneType' is not iterable    salt_minion()
File "C:\salt\bin\lib\site-packages\salt\scripts.py", line 191, in salt_minion

minion.start()
File "C:\salt\bin\lib\site-packages\salt\cli\daemons.py", line 346, in start
self._real_start()
File "C:\salt\bin\lib\site-packages\salt\cli\daemons.py", line 358, in _real_start
self.minion.tune_in()
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1065, in tune_in
self._spawn_minions()
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1009, in _spawn_minions
jid_queue=self.jid_queue)
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 977, in _create_minion_object
jid_queue=jid_queue)
File "C:\salt\bin\lib\site-packages\salt\minion.py", line 1136, in __init__
self.opts['grains'] = salt.loader.grains(opts)
File "C:\salt\bin\lib\site-packages\salt\loader.py", line 784, in grains
ret = funcs[key]()
File "C:\salt\bin\lib\site-packages\salt\grains\core.py", line 1662, in os_data
if 'Server' in grains['osrelease']:
TypeError: argument of type 'NoneType' is not iterable

# Fixed code
def _windows_os_release_grain(caption, product_type):
    """
    helper function for getting the osrelease grain
    :return:
    """
    # This creates the osrelease grain based on the Windows Operating
    # System Product Name. As long as Microsoft maintains a similar format
    # this should be future proof
    version = "Unknown"
    release = ""
    if "Server" in caption:
        # Edge case here to handle MS Product that doesn't contain a year
        if re.match(r"^Microsoft Hyper-V Server$", caption):
            version = "2019"
        else:
            for item in caption.split(" "):
                # If it's all digits, then it's version
                if re.match(r"\d+", item):
                    version = item
                # If it starts with R and then numbers, it's the release
                # ie: R2
                if re.match(r"^R\d+$", item):
                    release = item
        os_release = "{0}Server{1}".format(version, release)
    else:
        for item in caption.split(" "):
            # If it's a number, decimal number, Thin or Vista, then it's the
            # version
            if re.match(r"^(\d+(\.\d+)?)|Thin|Vista|XP$", item):
                version = item
        os_release = version

    # If the version is still Unknown, revert back to the old way of getting
    # the os_release
    # https://github.com/saltstack/salt/issues/52339
    if os_release in ["Unknown"]:
        os_release = platform.release()
        server = {
            "Vista": "2008Server",
            "7": "2008ServerR2",
            "8": "2012Server",
            "8.1": "2012ServerR2",
            "10": "2016Server",
        }

        # Starting with Python 2.7.12 and 3.5.2 the `platform.uname()`
        # function started reporting the Desktop version instead of the
        # Server version on # Server versions of Windows, so we need to look
        # those up. So, if you find a Server Platform that's a key in the
        # server dictionary, then lookup the actual Server Release.
        # (Product Type 1 is Desktop, Everything else is Server)
        if product_type > 1 and os_release in server:
            os_release = server[os_release]

    return os_release