Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can I use newlines (line breaks) in my Powershell commands to improve readability

How do I know when I can use a New Lines/Carriage returns in my Powershell scripts? All of the search results when searching for this answer all point to the Output. I don't care about the output in this case. I am more interested in my ability to format my Powershell scripts for readability.

For Example. Two versions of a Powershell command line below. One works and one doesn't. What the command does is unimportant in this case. The point is I am needing to know when I'm allowed to create a new line and when I am not.

This command line Works as it's just one long single line:

& 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe' --file 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json' --type json --collection users --progress true --overwrite true --server.username root --server.password password

This command line does NOT work due to the fact that there is a New Line in the middle of the script.

& 'C:\Program Files\ArangoDB3 3.3.3\usr\bin\arangoimp.exe' --file 
'C:\Program Files\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json'
--type json --collection users --progress true --overwrite true
--server.username root --server.password password

In my case I'm just running different versions of the same command line after adding line breaks to see if they work or not. I know that I can begin a New Line when using an IF statement. I can also use New Lines when piping an object |. My assumption is that somewhere there is a list of Powershell scripting rules. I thought I had seen them somewhere once upon a time when I originally began getting into Powershell but no clue where it is now.

like image 954
Code Novice Avatar asked Oct 14 '25 14:10

Code Novice


2 Answers

You can use ` as the line-continuation character[1] at the very end of a line (not even whitespace is allowed after it) in order to spread it across multiple lines.

Here's a simplified example:

& cmd.exe /c echo `
 hi `
 there

This is the equivalent of & cmd.exe /c echo hi there and yields hi there.

Note:

  • Since the ` character is both visually subtle and the syntax is easy to break by accidentally placing characters after it, consider using an array as an alternative - see below.

  • Individual commands must be on a single line and therefore need ` if you want to spread them across multiple lines, as shown above.

  • However, in a pipeline you may end the line with | and continue on the next line, without needing the `; e.g.:

      Get-Date | # Because the line ends with |, parsing continues on the next line.
        Select-Object Day
    
    • In PowerShell [Core] v7+, you may alternatively place the | at the start of the (very) next line:

          Get-Date  # PS v7+ only
          | Select-Object Day
      
  • Additionally, if individual arguments create a new parsing context in expression mode - such as an inherently multi-line capable (...) expression or a script block ({...}) passed to a cmdlet - you're also free to spread the expression across multiple lines; e.g.:

      1, 2, 3 | ForEach-Object { # { starts a multiline-aware context
        $_ + 1
      }
    
  • A hybrid case is an array-literal argument, which allows you to break a command after an interior element's , separator:

      Get-Date | Select-Object -Property Day,
                                         Year
    
  • Statements that start in expression mode always allow spreading across multiple lines (though embedded command-mode statements are subject to the usual limitations):

      $foo =         # an assignment is parsed in expression mode
              'bar'  
    

Alternatively, consider the use of an array[2] to pass the arguments, which allows you to use multiline expression-mode syntax to define the arguments as individual array elements beforehand:

# Construct the array of arguments (using multiline expression syntax)...
$arguments = '/c',
             'echo',
             'hi there'

# ... and pass it to cmd.exe
& cmd.exe $arguments 

Note: Array element hi there is passed as "hi there" by PowerShell: it employs automatic double-quoting to ensure that the argument is recognized as a single argument by the target program.

As an aside: for calling PowerShell commands (as opposed to external programs, as in the case at hand), consider constructing the arguments in a hashtable for use with splatting, where each entry key specifies a target parameter name and the corresponding value the parameter value (argument); e.g.:

# Define the hashtable representing the named arguments.
$argsHash = @{
  Filter = 'T*'
  File = $true
}
# Note the use of "@" instead of "$"
# Equivalent of:
#    Get-ChildItem -Filter T* -File
Get-ChildItem @argsHash

[1] ` is PowerShell's general-purpose escape character. Placed at the very end of a line, its function is subtly different: instead of escaping the newline that follows (which would mean retaining it as a literal), it effectively tells PowerShell to remove it and treat the next line as the continuation of the current one.

[2] An earlier form of this answer recommended array-based splatting, before PetSerAl pointed out that for invoking external programs it's sufficient to use an array as-is.
While splatting can be used too, its semantics are subtly different if one of the array element is --%, the stop-parsing symbol (in short: only when splatting does --% have its special meaning).
Splatting is a useful technique when calling PowerShell commands, however, primarily in its hash-table form (see previous link).

like image 146
mklement0 Avatar answered Oct 17 '25 10:10

mklement0


The standard way of formatting PowerShell arguments for readability is through splatting, which consists of assigning a hash table to a named splatting variable carrying the options, and using the At symbol to dereference the arguments when needed.

Your specific example of running an application with arguments would be written like below, in idiomatic PowerShell.

$arangoImpOptions = @{
    FilePath = "$env:ProgramFiles\ArangoDB3 3.3.3\usr\bin\arangoimp.exe"
    Arguments = @{
        file = "$env:ProgramFiles\ArangoDB3 3.3.3\usr\bin\tstImportJSON.json"
        type = 'json'
        collection = 'users'
        progress = 'true'
        overwrite = 'true'
        'server.username' = 'root'
        'server.password' = 'password'
    }.GetEnumerator().ForEach({ '--{0} "{1}"' -f @($_.Key, $_.Value) }) -join ' '
}
Start-Process @arangoImpOptions
like image 41
Diti Avatar answered Oct 17 '25 09:10

Diti