salt icon indicating copy to clipboard operation
salt copied to clipboard

[BUG] Upgrade to 3006.9 breaks PowerShell cmd.run/shell commands

Open hammondrm opened this issue 1 year ago • 3 comments

Description After upgrading from version 2006.8 to 3006.9 running cmd.run or cmd.shell with PowerShell on Windows servers will result in errors.

Setup Minions are running on Windows 2016, 2019 and 2022 servers.

  • [X] on-prem machine
  • [X] VM (Virtualbox, KVM, etc. please specify)
  • [X] onedir packaging

Steps to Reproduce the behavior This is one of the commands run that now error:

salt * cmd.shell '(Get-Date(Get-Date).ToUniversalTime() -UFormat %s)' shell=PowerShell

Here is the error from a minion running version 3006.9:

    & : The term '1737567164.15532' is not recognized as the name of a cmdlet, function, script file, or operable program.
    Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:3
    + & (Get-Date(Get-Date).ToUniversalTime() -UFormat %s)
    +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (1737567164.15532:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException

Expected Behavior On minions running with version 3006.8 the same command will return a number:

1737568937.15566

Versions Report Master:

Salt Version:
          Salt: 3006.9
Python Version:
        Python: 3.10.14 (main, Jun 26 2024, 11:44:37) [GCC 11.2.0]
Dependency Versions:
          cffi: 1.14.6
      cherrypy: unknown
  cryptography: 42.0.5
      dateutil: 2.8.1
     docker-py: Not Installed
         gitdb: Not Installed
     gitpython: Not Installed
        Jinja2: 3.1.4
       libgit2: 1.3.0
  looseversion: 1.0.2
      M2Crypto: Not Installed
          Mako: Not Installed
       msgpack: 1.0.2
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     packaging: 22.0
     pycparser: 2.21
      pycrypto: Not Installed
  pycryptodome: 3.19.1
        pygit2: 1.7.1
  python-gnupg: 0.4.8
        PyYAML: 6.0.1
         PyZMQ: 23.2.0
        relenv: 0.17.0
         smmap: Not Installed
       timelib: 0.2.4
       Tornado: 4.5.3
           ZMQ: 4.3.4
System Versions:
          dist: rhel 9.5 Plow
        locale: utf-8
       machine: x86_64
       release: 5.14.0-503.15.1.el9_5.x86_64
        system: Linux
       version: Red Hat Enterprise Linux 9.5 Plow

Versions Report Minion:

Salt Version:
          Salt: 3006.9

Python Version:
        Python: 3.10.14 (heads/main:9f7d197, Jun 26 2024, 11:42:40) [MSC v.1940 64 bit (AMD64)]

Dependency Versions:
          cffi: 1.14.6
      cherrypy: 18.6.1
  cryptography: 42.0.5
      dateutil: 2.8.1
     docker-py: Not Installed
         gitdb: 4.0.7
     gitpython: Not Installed
        Jinja2: 3.1.4
       libgit2: Not Installed
  looseversion: 1.0.2
      M2Crypto: Not Installed
          Mako: Not Installed
       msgpack: 1.0.2
  msgpack-pure: Not Installed
  mysql-python: Not Installed
     packaging: 22.0
     pycparser: 2.21
      pycrypto: Not Installed
  pycryptodome: 3.19.1
        pygit2: Not Installed
  python-gnupg: 0.4.8
        PyYAML: 6.0.1
         PyZMQ: 25.0.2
        relenv: 0.17.0
         smmap: 4.0.0
       timelib: 0.2.4
       Tornado: 4.5.3
           ZMQ: 4.3.4

System Versions:
          dist:
        locale: utf-8
       machine: AMD64
       release: 2022Server
        system: Windows
       version: 2022Server 10.0.20348 SP0 Multiprocessor Free

hammondrm avatar Jan 22 '25 18:01 hammondrm

Hi there! Welcome to the Salt Community! Thank you for making your first contribution. We have a lengthy process for issues and PRs. Someone from the Core Team will follow up as soon as possible. In the meantime, here’s some information that may help as you continue your Salt journey. Please be sure to review our Code of Conduct. Also, check out some of our community resources including:

There are lots of ways to get involved in our community. Every month, there are around a dozen opportunities to meet with other contributors and the Salt Core team and collaborate in real time. The best way to keep track is by subscribing to the Salt Community Events Calendar. If you have additional questions, email us at [email protected]. We’re glad you’ve joined our community and look forward to doing awesome things with you!

welcome[bot] avatar Jan 22 '25 18:01 welcome[bot]

Also running into this to after moving to 3006.10 from minions with 3006.2 to 3006.6

Appears to stem from PR #66447 where the "&" is prepended to the command passed to powershell -- there's been additional PRs after that to add some exceptions to not prepend the "&" on some things, but it's a pretty limited list.

@twangboy - Isn't the "&" operator primarily needed if you're running a code block (something wrapped in {}) or an script file (which seemed to be the initial problem in #61166)/EXE? Would it be easier to only prepend for those cases versus trying to manage all the possible exceptions? Maybe it is a similar scale problem either way and there are just as many times you'd want to prepend the "&" above and beyond those instances.

Playing with this patch in our environment, but don't know if it breaks how someone else is doing something. "Works for us." This basically checks if the cmd is a script block (starts with '{') or a path (i.e. starting with a drive letter), but might need to handle non-qualified paths and UNC paths as well...

--- /tmp/cmdmod.py.3006.10      2025-06-04 09:34:29.132338638 -0500
+++ /tmp/cmdmod.py.3006.10.mine 2025-06-04 11:11:01.769053856 -0500
@@ -294,16 +294,12 @@
         if isinstance(cmd, list):
             cmd = " ".join(cmd)

-        # Commands that are a specific keyword behave differently. They fail if
-        # you add a "&" to the front. Add those here as we find them:
-        keywords = ["$", "&", ".", "Configuration", "try"]
-
-        for keyword in keywords:
-            if cmd.lower().startswith(keyword.lower()):
-                new_cmd.extend(["-Command", f"{cmd.strip()}"])
-                break
-        else:
+        if re.match(r'["\']{0,1}[a-zA-Z]{1}:', cmd.strip()):
+            new_cmd.extend(["-Command", f"& {cmd.strip()}"])
+        elif re.match(r'\{', cmd.strip()):
             new_cmd.extend(["-Command", f"& {cmd.strip()}"])
+        else:
+            new_cmd.extend(["-Command", f"{cmd.strip()}"])

     log.debug(new_cmd)
     return new_cmd

lomeroe avatar Jun 04 '25 19:06 lomeroe

Looking at this now... As a workaround you can add "Write-Host" to the front of your command. You can also drop the parenthesis from the entire command.

twangboy avatar Jun 06 '25 15:06 twangboy

If exceptions are being managed, "if" is another one (also do and while). We use a lot of if powershell statements, in requisites or just directly via the cmd module:

$salt 'node' cmd.run_all 'if (1 -eq 1) { exit 0 } else { exit 1}' shell=powershell
node:
    ----------
    pid:
        5068
    retcode:
        1
    stderr:
        & : The term 'if' is not recognized as the name of a cmdlet, function, script
        file, or operable program. Check the spelling of the name, or if a path was
        included, verify that the path is correct and try again.
        At line:1 char:3
        + & if (1 -eq 1) { exit 0 } else { exit 1}
        +   ~~
            + CategoryInfo          : ObjectNotFound: (if:String) [], CommandNotFoundE
           xception
            + FullyQualifiedErrorId : CommandNotFoundException
    stdout:

lomeroe avatar Jun 18 '25 18:06 lomeroe

@lomeroe Thanks. I added those and a few more to that list.

twangboy avatar Jun 18 '25 20:06 twangboy

I think this has been addressed by #68056

twangboy avatar Jun 30 '25 21:06 twangboy

Sorry for the slow response on this. Had to find a window I could test. This is now working as expected. I upgraded to 3006.14 Thank for the great work!

hammondrm avatar Jul 30 '25 18:07 hammondrm