3

I am creating PowerShell script to automatically build Angular CLI project. When I use this command in my .ps1 file:

Start-Process -FilePath ng build -WorkingDirectory D:\pathToAngularProject -Wait

it works perfectly but create not uglified javascript build. To be able to create production build I need to add '--prod' argument. But when I change example above on :

Start-Process -FilePath ng build -ArgumentList '--prod' -WorkingDirectory D:\pathToAngularProject -Wait

I am getting the error: enter image description here

Does anyone have a suggestion how can I add an argument to 'ng build' command in PowerShell script?

Andrei
  • 341
  • 7
  • 23
  • 4
    What is `ng build`? If it is a file, surround it in quotes `"ng build"` if it is an argument, add it to the argument list `-ArgumentList '--prod', 'build'` – Nico Nekoru Jul 07 '20 at 20:27

2 Answers2

5

Neko Musume's helpful answer provides a solution to your immediate problem.

However, it's worth taking a step back:

To synchronously execute console applications or batch files, call them directly (ng build ... or & ng build ...), do not use Start-Process - see this answer and this GitHub docs issue detailing appropriate vs. non-appropriate use cases and requesting that guidance be added to the Start-Process help topic.

Therefore:

# Execute ng synchronously, with its output streams connected to PowerShell's
ng build --prod D:\pathToAngularProject

As for what you tried:

To add to Neko's answer:

The reason that your first command worked is that the following:

Start-Process -FilePath ng build

is equivalent to:

Start-Process -FilePath -FilePath ng -ArgumentList build

That is, the build argument was bound positionally, without the need to name its target parameter, -ArgumentList, explicitly.

Taking advantage of this, and also that -FilePath is implied for the first positional argument, the immediate solution to your problem could be simplified to:

# The 1st positional argument, 'ng', binds to -FilePath
# The 2nd positional argument, the *array* of arguments to pass to 'ng',
# 'build' and '--prod', binds to -ArgumentList
Start-Process ng  build, --prod

That said, Start-Process has a long-standing bug that causes it to pass arguments with embedded spaces incorrectly - see GitHub issue #5576. To preserve backward compatibility, this bug will likely not get fixed (except perhaps by introducing a new parameter).

It is therefore preferable to pass the arguments as a single array element, effectively as a command line (without the executable) encoding all arguments, where the boundaries between the arguments can properly be signaled with embedded double-quoting ("..."), if necessary:

# Pass the arguments for 'ng' *as a single string*, potentially
# with embedded "..." quoting (not needed here).
Start-Process ng  'build --prod'

An example with embedded quoting:

# Project path needs embedded "..." quoting, because it contains spaces.
Start-Process ng  'build --prod "D:\Work Projects\Foo"' ...

An example that uses an expandable (double-quoted) string ("...") in order to embed the values of variables / subexpressions (the embedded " chars. must then be escaped as `" (or "")):

$projDir = 'D:\Work Projects'
Start-Process ng  "build --prod `"$projDir\Foo`"" ...

A general note on quoting array elements:

Because command arguments in PowerShell are parsed using the so-called argument (parsing) mode (shell-like), the (string) elements of the (implied) -ArgumentList do not generally require quoting.

That is, array build, --prod in argument mode is the equivalent of 'build', '--prod' in expression mode (programming-language-like).

See this answer for an overview of PowerShell's parsing modes.

However, you may use the quoted form in argument mode too, and - depending on the element values - you may have to quote, such as when elements contain spaces or other shell metacharacter; additionally, if the first element looks like a PowerShell parameter name (e.g., -prod rather than --prod), it must be quoted too.

A few examples:

Note: For simplicity, Write-Output is used in the examples, which simply echoes each array element on its own line. An array passed to any cmdlet is parsed in argument mode.

# No quoting needed.
# Elements contain no PowerShell metacharacters.
Write-Output one, two

# Quoting needed for the 2nd array element, due to containing
# PowerShell metacharacters (space, parentheses)
Write-Output one, 'two (2)'

# Quoting needed for the 1st array element, because it looks
# like a PowerShell parameter name.
# (Of course, you may choose to quote *both* elements in this case,
# for consistency).
Write-Output '-one', two

# If the parameter-like argument isn't the *first* array element,
# the need for quoting goes away
Write-Output one, -two
mklement0
  • 382,024
  • 64
  • 607
  • 775
3

Add build to the -argumentlist if it is an argument like:

Start-Process -FilePath ng -ArgumentList 'build', '--prod' -WorkingDirectory D:\pathToAngularProject -Wait 

If it is part of the path quote it in the -path parameter because there are spaces:

Start-Process -FilePath "ng build" -ArgumentList '--prod' -WorkingDirectory D:\pathToAngularProject -Wait
mklement0
  • 382,024
  • 64
  • 607
  • 775
Nico Nekoru
  • 2,840
  • 2
  • 17
  • 38
  • 2
    The executable is `ng` by itself, which is the [Angular CLI](https://cli.angular.io/). However, it's worth pointing out that `Start-Process` is usually the wrong tool for invoking CLIs (console applications). – mklement0 Jul 07 '20 at 22:12
  • 1
    Also, while `-ArgumentList` _should_ be the proper way to pass arguments through individually, it unfortunately isn't in the general case, due to a longstanding bug (see [this GitHub issue](https://github.com/PowerShell/PowerShell/issues/5576)) - since the arguments in this particular case contain no spaces, the command works, however. – mklement0 Jul 08 '20 at 13:59