1

first time asking a question here. I am new to Powershell and trying to use it to get the last write time of several files with paths I have saved in a .txt file. I have to do this for ~9000 CAD files and am currently practicing. Below is what I have gotten to work, but when I try and write it to a file it gives me an error and I don't know how to fix it.

This is what I have working:

> foreach($line in get-content
> c:\users\jcuthbertson\desktop\filesforgettingdate.txt) {
> if($line -match $regex){
> -join((get-item $line).lastwritetime,",", (get-item $line).name)}}
6/24/2020 11:38:42 AM,Book1.xlsx
6/30/2020 4:16:47 PM,Book2.xlsx
7/10/2020 7:37:31 AM,dwg_vwx_mcd files.xlsx
7/7/2020 9:43:30 AM,Program cleaning flow sequences.xlsx
7/9/2020 8:49:14 AM,vxw paths commas.xlsx

But when I add the "out-file" command it gives me and error saying there is an empty pipe

> foreach($line in get-content
> c:\users\jcuthbertson\desktop\filesforgettingdate.txt) {
> if($line -match $regex){
> -join((get-item $line).lastwritetime,",", (get-item $line).name)}} | out-file c:\users\jcuthbertson\desktop\testdatawrite.txt
At line:3 char:68
+ ... get-item $line).lastwritetime,",", (get-item $line).name)}} | out-fil ...
+                                                                 ~
An empty pipe element is not allowed.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : EmptyPipeElement

Any help is greatly appreciated! Thank you!

2
  • 2
    This is because your foreach script block is not actually sending anything to the pipeline. It is the code inside that has that capability. You either need to move your Out-File command with -Append to inside of your foreach or capture the output before sending to Out-File. You can use a variable or sub-expression operator $(). Variable -> $var = foreach ($line in ...) {...}; $var | out-file. Sub-expression -> $(foreach ($line in ..) {..}) | Out-File. Commented Jul 10, 2020 at 17:51
  • Also check out PowerShell ISE. You dont need to develop on the Powershell Console Commented Jul 10, 2020 at 18:18

2 Answers 2

3

This is in addition to AdminOfThings good answer. If you're new to PowerShell I thought you might like to see another option. You can use the ForEach-Object cmdlet Which allows you to leverage the pipeline straight through.

$File = 'c:\temp\Test_Input.txt'

Get-Content $File |
ForEach-Object{
    If( $_ -match $RegEx ) {
        $Item = Get-Item $_
        $Item.LastWriteTime, $Item.Name -join ','
    }
} |
Out-File c:\temp\test_output.txt -Append

Maybe it's a matter of preference and circumstance but by embracing the pipeline it's going to be more memory efficient. Don't get me wrong memory isn't usually an issue, but there is a difference between collecting objects up front either by sub-expression $(...) or by storing in a variable. Options 2 & 3 in the previous answer store the whole output before writing it to the file. Also, Option 1 from the previous answer is opening and closing the file repeatedly.

It's also unnecessary to run Get-Item multiple times, hence I introduced $Item. But, that could've been adapted in any example.

Let me know if that's helpful.

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

1 Comment

That was very helpful thanks! Examples for me to reference later are always beneficial.
0

This behavior occurs because the foreach script block is not actually outputting anything to the pipeline. The pipeline capable output occurs from the -join operator inside the foreach loop. This leaves you with a few options for piping data into Out-File.

Option 1: Pipe the results of -join into Out-File

foreach($line in get-content c:\users\jcuthbertson\desktop\filesforgettingdate.txt) {
    if($line -match $regex){
        -join ((get-item $line).lastwritetime,",",(get-item $line).name) |
            Out-File c:\users\jcuthbertson\desktop\testdatawrite.txt -Append
    }
}

Note the use of the -Append switch to not overwrite the file with each iteration.

Option 2: Capture the outputs in a variable and pipe the variable contents

$output = foreach($line in get-content c:\users\jcuthbertson\desktop\filesforgettingdate.txt) {
    if($line -match $regex){
        -join ((get-item $line).lastwritetime,",",(get-item $line).name)
    }
}
$output | Out-File c:\users\jcuthbertson\desktop\testdatawrite.txt

Option 3: Force the foreach script block to be an expression using subexpression operator $()

$(foreach($line in get-content c:\users\jcuthbertson\desktop\filesforgettingdate.txt) {
    if($line -match $regex){
        -join ((get-item $line).lastwritetime,",",(get-item $line).name)
    }
}) | Out-File c:\users\jcuthbertson\desktop\testdatawrite.txt

1 Comment

Thank you for explaining! I went with option 2 and it worked perfectly! I will remember that in the future:)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.