6
$a = {aa
bb
cc}
$a = $a -split "`n"
$a -contains "aa"

This returns false, when the string "aa" is seemingly part of the list. Why is this?

Robert Overmyer
  • 182
  • 1
  • 1
  • 8
  • Even though your question seem obvious, it will be of help you do edit it so as to elaborate further; what are you trying to achieve, etc. – nyedidikeke Feb 14 '17 at 00:18
  • 3
    Why on earth are you splitting a scriptblock? (And hint: you're a programmer in an interactive shell. PowerShell is not lying when it returns false, which means `aa` is not part of the list, which means you should be poking at what the list contains. `($a -split "\`n")[0].Length` => `3` for example) – TessellatingHeckler Feb 14 '17 at 01:49
  • -Contains is a list operator (does the list contain an item). You want -like, -match, or .Contains() (a string method) to do what you're looking for. – Mike Shepard Feb 14 '17 at 03:58
  • @MikeShepard: The OP's use of a _script block_ that is converted to a _multi-line string_ is unusual, but the code does work as-is if the script block is defined in the regular console (which uses LF-only line endings) - paste it and execute it to see. By contrast, it won't work if the code is defined in a script that uses CRLF line endings. – mklement0 Feb 14 '17 at 12:22
  • 1
    @mklement0 - I should learn to read people's code closer. I saw string and -contains and jumped to the conclusion (which is usually correct) that they were using the wrong operator. – Mike Shepard Feb 14 '17 at 15:47
  • @TessellatingHeckler Didn't have the knowledge I needed to poke around. A colleague pointed me towards the "| clip" command, which showed the extra newline character. Thanks for the comment, you nailed the root cause. – Robert Overmyer Feb 14 '17 at 20:22

3 Answers3

13

To complement Kory Gill's helpful answer, which suggests that the problem may be that the input has CRLF ("`r`n") line endings, in which case -split "`n" (splitting by LF only) would leave the resulting array elements with a trailing CR ("`r"), causing "aa" not to be found with -contains, because the actual value is "aa`r".

The generic way to handle input with Windows- or Unix-style line endings is to use:

$a -split '\r?\n' # split $a into lines, whether it has CRLF or LF-only line endings

The -split operator uses regexes (regular expressions), and regex \r?\n matches any LF (\n) possibly (?) preceded by a CR (\r). To also match (rare) CR-only newlines, use \r?\n|\r
Regex escape sequences \r and \n correspond to PowerShell escape sequences `r and `n (which work in double-quoted strings only).

Note that PowerShell itself is quite flexible when it comes to line endings:

  • Even on Windows interactive input in the regular console uses LF-only line endings (\n) (except in the obsolescent ISE).

  • Scripts are allowed to have CRLF (\r\n) or LF (\n) line endings, and PowerShell preserves the source file's line endings in any multi-line string literals defined in the file.

    • Note that this applies even to multi-line script blocks, as in the question: when you convert such a script block to a string later - which simply returns everything between the script-block delimiters, { and } - the source file's line endings are reflected in the resulting string.

As an aside: [Environment]::NewLine contains the platform-appropriate newline (line-ending) sequence: "`r`n" on Windows, "`n" on Unix-like platforms, but, as discussed above, there's no guarantee that all input encountered will have platform-appropriate newlines.

mklement0
  • 382,024
  • 64
  • 607
  • 775
6

a solution cross Platform:

$a = $a -split [System.Environment]::NewLine
Esperento57
  • 16,521
  • 3
  • 39
  • 45
  • 1
    While knowing about `[Environment]::NewLine` is helpful, using it with `-split` is not a true cross-platform solution, because you need to be prepared to handle _either_ type of line ending, given that it is not guaranteed that you'll only encounter platform-native ones. For instance, if you define a multi-line string in the regular PowerShell console _on Windows_, it will have _LF-only_ line endings, and `-split [Environment]::NewLine` will find no lines and return the entire input string as a one-element array. – mklement0 Feb 14 '17 at 16:08
4

Every time I see a `n in code, I always question whether it should be `r`n on Windows.

Change your code to this:

$a = $a -split "`r`n"
Kory Gill
  • 6,993
  • 1
  • 25
  • 33