5

From powershell, ls -R *.txt will list files recursively by directory, or, even better:

PS> Get-ChildItem -Path C:\Test -Name

logs

anotherfile.txt
Command.txt
CreateTestFile.ps1
ReadOnlyFile.txt

but how do I feed this into an array? I would like an array of the file (?) object itself, looking at:

Get-ChildItem "C:\WINDOWS\System32" *.txt -Recurse | Select-Object FullName

https://stackoverflow.com/a/24468733/262852

I'm looking for an array of "file" objects with powershell from these types of commands.

probably better syntax:

Copy-Item -Filter *.txt -Path c:\data -Recurse -Destination C:\temp\text

but rather than copy the items, I just want an object, or rather, array of objects. Not the path to a file, not the file, but, presumably, a powershell reference or pointer to a file.

(Reading the fine manual now.)

3
  • 5
    get-ChildItem "C:\windows\system32" -include "*.txt" -Recurse produces an array of objects. Commented Apr 19, 2019 at 16:47
  • 4
    I am not sure what you are getting at here. But powershell automatically returns an object. All you have to do is assign it to a variable. $txtfiles = Get-ChildItem "C:\WINDOWS\System32" *.txt -Recurse | Select-Object FullName. In this case, $txtfiles will be an array object. Commented Apr 19, 2019 at 16:50
  • @AdminOfThings the array will contain objects of type System.IO.FileSystemInfo? Okay, that was what I needed to know. Commented Apr 19, 2019 at 23:03

2 Answers 2

10

tl;dr

  • When you capture a PowerShell statement's output in a variable (e.g.,
    $output = Get-ChildItem ...), it is automatically collected in an array if there are two or more output objects.

  • To ensure that an array is always used - even with only a single or no output object - use @(...) (e.g.,
    $output = @(Get-ChildItem ...))


  • PowerShell cmdlets, such as Get-ChildItem, can output any number of objects.

    • Get-ChildItem outputs [System.IO.FileInfo] and/or [System.IO.DirectoryInfo] objects, depending on whether information about files and/or directories is being output.

    • To determine a given cmdlet's output-object types:

      • Run, e.g., (Get-Command Get-ChildItem).OutputType
      • If that doesn't work, or to see what types are output for a specific invocation, use
        Get-ChildItem | Get-Member.
      • Get-Help -Full Get-ChildItem should show an OUTPUTS section as well, as does the online help, though not that in the case of Get-ChildItem it is less specific, since Get-ChildItem also works with providers other than the filesystem.
  • When output to the pipeline, each output object is passed individually to the next command in the pipeline for typically immediate processing.

  • When output is captured in a variable ($var = ...), the following logic applies:

    • If two or more objects are output, they are collected in a regular PowerShell array, which is of type [object[]] (even though the actual elements have specific types).
    • If one object is output, it is output as-is; that is, it is not wrapped in an array.
    • If no objects are output, an "array-valued null" is output (sometimes called "AutomationNull" for its type name), which in expression contexts behaves like $null and in enumeration contexts like an empty collection; it results in no visible output - see this answer for details.

Therefore, when captured in a variable, a given command may situationally return:

  • an array of objects
  • a single object
  • "nothing" ([System.Management.Automation.Internal.AutomationNull]::Value)

To ensure that a given command's output is always treated as an array, you have two options:

  • Use @(...), the array subexpression operator; e.g.

    • $fileSystemObjects = @(Get-ChildItem -Recurse -Filter *.txt)
  • Type-constrain the target variable with [array] (which is equivalent to, and easier to type than, [object[]]).

    • [array] $fileSystemObjects = Get-ChildItem -Recurse -Filter *.txt

That said, in PSv3+ you often need not worry about whether a given variable contains a scalar (single value) or an array, because scalars can implicitly be treated like arrays: you can call .Count even on scalars, and use indexing ([0], [-1]) - see this answer for details.

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

3 Comments

okay, and thanks for the pointers about how to handle types and arrays. I like the Get-Member commandlet.
@Thufir; my pleasure. The answer you accepted tells you what specific types Get-ChildItem returns, which may be what you meant to ask, but it is not what you did ask. Please consider the perspective of future readers.
TL;DR Use @(...) to ensure output is always treated as an array!
3

Get-ChildItem "C:\test" -Recurse will return an array of FileInfo and DirectoryInfo objects inside an array

We can see an a example showing that here

Get-ChildItem "C:\test" -Recurse | %{
    $_.gettype()
}

Returns

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DirectoryInfo                            System.IO.FileSystemInfo
True     True     DirectoryInfo                            System.IO.FileSystemInfo
True     True     FileInfo                                 System.IO.FileSystemInfo
True     True     DirectoryInfo                            System.IO.FileSystemInfo

6 Comments

Exactly what I needed to know, thanks. This is a standard idiom for getting the type?
this answer is misleading, because Get-ChildItem -Recurse sometimes does not return an array. see mklement0's answer.
@orionelenzil Misleading is a strong word. He asked for a answer and I gave him one. My answer works for what he wanted. He even replied below stating thanks but it was "over his head". Sometimes in-depth explanations are not always needed or wanted.
I dunno. if c:\test contains only a single file, the resulting type is System.IO.FileSystemInfo.
You may be right that 'misleading' is too strong a word. I'm picking this nit because this particular behavior has tripped me up several times - I write my script against a search that returns many files and all is well, $x.Length equals the number of items, etc, but then my script runs somewhere the search returns only a single item and now my code breaks. $x.Length is the filesize of the one file returned, etc.
|

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.