If I have a text file, C:\USER\Documents\Collections\collection.txt that has the following information:
collectionA.json
collectionB.json
collectionC.json
collectionD.json
I am wondering how, through Powershell, I am able to store each line in the text file as elements of an array such as..
array arrayFromFile = new Array;
foreach(line x in collection.txt)
{
arrayFromFile.Add(x);
}
..with the end goal of doing the following:
foreach(string x in arrayFromFile)
{
newman run x;
}
My apologies for the seemingly easy question - I have never dealt with Powershell before.
In PowerShell, we can use the split operator (-Split) to split a string text into array of strings or substrings. The split operator uses whitespace as the default delimiter, but you can specify other characters, strings, patterns as the delimiter. We can also use a regular expression (regex) in the delimiter.
To create and initialize an array, assign multiple values to a variable. The values stored in the array are delimited with a comma and separated from the variable name by the assignment operator ( = ). The comma can also be used to initialize a single item array by placing the comma before the single item.
The Get-Content
command returns each line from a text file as a separate string, so will give you an array (so long as you don't use the -Raw
parameter; which causes all lines to be combined to a single string).
[string[]]$arrayFromFile = Get-Content -Path 'C:\USER\Documents\Collections\collection.txt'
In his excellent answer, mklement0 gives a lot more detail on what's really going on when you call this command, as well as alternate approaches if you're concerned about performance over convenience. Definitely worth a read if you're interested in learning more about the language rather than just solving this one off requirement.
To complement JohnLBevan's helpful answer:
Get-Content
, as a cmdlet, outputs objects one by one to the pipeline, as they become available. (Note that a pipeline is involved even when invoking a cmdlet in the absence of the pipe symbol, |
, for chaining multiple commands).
In this case, the output objects are the individual lines of the input text file.
If you collect a pipeline's output objects, such as by assigning it to a variable such as $arrayFromFile
or by using the pipeline in the context of a larger expression with (...)
:
[object[]]
,However, it often isn't necessary to ensure that you always receive an array, because PowerShell treats scalars (single values that aren't collections) the same as arrays (collections) in many contexts, such as in foreach
statements or when outputting a value to be enumerated to the pipeline, to be processed via the ForEach-Object
cmdlet, for instance; therefore, the following commands work just fine, irrespective of how many lines the input file contains:
# OK - read all lines, then process them one by one in the loop.
# (No strict need to collect the Get-Content output in a variable first.)
foreach ($line in Get-Content C:\USER\Documents\Collections\collection.txt) {
newman run $line
}
# Alternative, using the pipeline:
# Read line by line, and pass each through the pipeline, as it is being
# read, to the ForEach-Object cmdlet.
# Note the use of automatic variable $_ to refer to the line at hand.
Get-Content C:\USER\Documents\Collections\collection.txt |
ForEach-Object { newman run $_ }
In order to ensure that a command's output is always an array, PowerShell offers @(...)
, the array-subexpression operator, which wraps even single-object output in an array.
Therefore, the PowerShell-idiomatic solution is:
$arrayFromFile = @(Get-Content C:\USER\Documents\Collections\collection.txt)
TheMadTechnician points out that you can also use [array]
to cast / type-constrain pipeline output as an alternative to @(...)
, which also creates [object[]]
arrays:
# Equivalent of the command above that additionally locks in the variable date type.
[array] $arrayFromFile = Get-Content C:\USER\Documents\Collections\collection.txt
By using [array] $arrayFromFile = ...
rather than $arrayFromFile = [array] (...)
, variable $arrayFromFile
becomes type-constrained, which means that its data type is locked in (whereas by default PowerShell allows you to change the type of a variable anytime).
[array]
is a command-independent alternative to the type-specific cast used in John's answer, [string[]]
; you may use the latter for enforcing use of a uniform type across the array's elements, but that is often not necessary in PowerShell[1]
.
Regular PowerShell arrays are of type [object[]]
, which allows mixing elements of different types, but any given element still has a specific type; e.g., even though the type of $arrayFromFile
after the command above is [object[]]
, the type of $arrayFromFile[0]
, i.e. the 1st element, for instance, is [string]
(assuming that the file contained at least 1 line; verify the type with $arrayFromFile[0].GetType().Name
).
Cmdlets and the pipeline offer high-level, potentially memory-throttling features that are expressive and convenient, but they can be slow.
When performance matters, direct use of .NET framework types is necessary, such as [System.IO.File]
in this case.
$arrayFromFile = [IO.File]::ReadAllLines('C:\USER\Documents\Collections\collection.txt')
Note how the System.
prefix can be omitted from the type name.
As in John's answer, this will return a [string[]]
array.
Caveats:
Be careful with relative paths, as .NET typically has a different current directory than PowerShell; to work around this, always pass absolute paths, in the simplest case with, e.g., "$PWD/collection.txt"
and most robustly with"$((Get-Location -PSProvider FileSystem).ProviderPath)/collection.txt"
.NET's default encoding is UTF-8, whereas Windows PowerShell defaults to "ANSI" encoding, i.e.the system locale's legacy code page; PowerShell Core (v6+), by contrast, also defaults to UTF-8. Use Get-Encoding
's -Encoding
parameter or the .ReadAllLines()
overload that accepts an encoding instance to specify the input file's character encoding explicitly.
[1] Generally, PowerShell's implicit, runtime type conversions cannot provide the same type safety you'd get in C#, for instance. E.g., [string[]] $a = 'one', 'two'; $a[0] = 42
does not cause an error: PowerShell simply quietly converts [int]
42
to a string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With