5

My GitHub Actions workflow "runs-on" windows-latest. I want a custom Action which executes a PowerShell (core or legacy is fine) script. I have a parallel action that runs on Linux and MacOS. So, my .github/actions/install-tf-win directory contains this action.yml

name: install_tf_win
description: installs Terraform/TerraGrunt for Windows
runs:
  using: "composite"
  steps:
    - run: install-tf-win\install-tf-win.ps1
      shell: pwsh

The directory also contains install-tf-win.ps1. I have tried all sorts of variations on that run statement. Starting with "&" and without, variations in paths used with forwards and backwards slashes. I originally started with $GITHUB_ACTION_PATH/install-tf-win.ps1 (works for Linux/MacOS), however it seemed that GITHUB_ACTION_PATH was getting evaluated to be an empty string and then there were complaints about /install-tf-win.ps1 not being found. I tried both pwsh and powershell for the shell key value.

The form shown above results in this error:

Run ./.github/actions/install-tf-win
install-tf-win\install-tf-win.ps1: D:\a\_temp\c1d3d7fa-074b-4f90-ade0-799dcebd84ec.ps1:2
Line |
   2 |  install-tf-win\install-tf-win.ps1
     |  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The module 'install-tf-win' could not be loaded. For more information, run 'Import-Module
     | install-tf-win'.

I can obviously code my way around this by just putting the PowerShell statements in a step. But, the documentation suggests this should work. https://docs.github.com/en/free-pro-team@latest/actions/creating-actions/metadata-syntax-for-github-actions#runsstepsshell .

So, how do I get this to work, please?

0

1 Answer 1

7

The error message implies that you cannot refer to your script with a relative path:

The command is passed to pwsh, PowerShell [Core]'s CLI, via its -Command (-c) parameter, which interprets the install-tf-win part of
install-tf-win\install-tf-win.ps1 as a module name
rather than as a subdirectory in the absence of an actual subdirectory by that name on Windows[1], so the implication is that such a path doesn't exist.

The linked documentation, suggests that you need an absolute path, based on the GITHUB_ACTION_PATH environment variable, which in PowerShell must be referenced as $env:GITHUB_ACTION_PATH (untested):

# ...
    - run: '& $env:GITHUB_ACTION_PATH/install-tf-win/install-tf-win.ps1'
      shell: pwsh

Note:

  • The need to use &, the call operator, which is a syntactic necessity due to the script path containing a(n environment-)variable reference; the same would apply if the path were quoted - see this answer for background information.

  • Since & is a metacharacter in YAML when used unquoted at the start of a value, the entire string is quoted. Single-quoting ('...') is employed in this case, so that YAML doesn't interpret the contents of the string up front.

    • As an aside: The implication of '...'-quoting working (as confirmed by Kevin, the OP) is that when pwsh -c is ultimately called on Windows, the string's content is (properly) double-quoted ("..."), because PowerShell's CLI only recognizes " as having syntactic function for command-line argument parsing. By contrast, a '...'-quoted -c argument would be interpreted as a verbatim string rather than as a command, causing its content to be simply echoed.

[1] How PowerShell interprets a path such as foo\bar.ps1 when executed as a command, as of PowerShell 7.1

Interpreted as a command - both inside a PowerShell session and via the -Command / -c parameter of the PowerShell CLI, as used by GitHub Actions - the form foo\bar.ps1 is ambiguous:

  • It could refer to a module named foo, and its bar.ps1 command (even though module commands don't have .ps1 name extensions).

  • It could refer to a subdirectory foo and file bar.ps1 in it.

    • This applies to Windows only:

      • PowerShell first interprets the path as a file-system path.
      • If the path doesn't exist, it falls back to interpreting it as a module-command reference.
    • On Unix-like platforms - even though PowerShell generally allows you to use \ and / interchangeably as the path separator on all supported platforms - this particular path form is always interpreted as a module reference; in other words: you cannot use this syntax form to invoke a script this way (see below).

    • This surprising inconsistency is discussed in GitHub issue #14307.

There are two ways to avoid this ambiguity, which work on all supported platforms; the following cause PowerShell to unequivocally treat the path as file-system script path:

  • Use / instead of \: foo/bar.ps1

  • Prefix the path with .\ (or ./): .\foo\bar.ps1

(Of course, you could also use a full path.)

Note that when the -File parameter of PowerShell's is used (rather than -Command / -c), this ambiguity doesn't arise, as the argument is then always considered a (potentially relative) file-system path, even on Unix-like platforms, irrespective of whether you use \ or /.

Sign up to request clarification or add additional context in comments.

1 Comment

The form - run: '& $env:GITHUB_ACTION_PATH/install-tf-win/install-tf-win.ps1' shell: pwsh worked. It is important to note that the additional path segment "/install-tf-win/" is not required for the equivalent for Linux or MacOS.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.