question

JeffL-4062 avatar image
0 Votes"
JeffL-4062 asked JeffL-4062 answered

Need to output command results to file

Is there an easy way for me to pump the output of a series of file deletions using foreach?

Get-ChildItem -Path C:\Temp\Testing*\Beep* -Include * | foreach {$_.Delete()}

I know foreach doesn't support pipelining but I'm trying to keep this simple and am not well versed with the ForEach-Object command..

Thanks,

J

windows-server-powershell
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MotoX80 avatar image
0 Votes"
MotoX80 answered RichMatheisen-8856 commented

You can't reference .Fullname in the catch because "$ underscore" will be the error object.

Please use the Code Sample icon when posting code. The "101010" icon.

Try it like this. I highly recommend using -whatif on the Remove-Item when you are testing.

 $Folders = Get-ChildItem 'C:\Users\*\AppData\Roaming\Temp*' -Recurse
 ""
 "Folders contains {0} entries." -f $Folders.count 
 ""
 $csv = ForEach ($File in $folders) {
     Try {
         Remove-Item $File.FullName -ErrorAction Stop -whatif 
         [PSCustomObject]@{
             Path = $File.FullName
             Action = "Removed"
             Error = ""
             }
         }
     Catch {
         [PSCustomObject]@{
             Path = $File.FullName
             Action = "NotRemoved"
             Error = $_ 
         }
     }
 } 
    
 $csv | Export-Csv C:\Temp\RR_Cleanup_Output.csv -NoTypeInformation
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

You're right! I fixed the code example to use a variable that holds the full file path. The code still uses the pipelining.

0 Votes 0 ·
MotoX80 avatar image MotoX80 RichMatheisen-8856 ·

I'd also recommend adding -Whatif to the remove-item. Just to be safe during initial testing. I once had to rebuild a server, twice, because the app support admin discovered Powershell and wiped out System32. He didn't understand where "current directory" was and I couldn't revoke his admin access.

0 Votes 0 ·

That problem's been around since dirt was white -- even before Winows!

A donkey's years ago I worked supporting SCO Unix and a root user doing "rm -r *" was more common than you'd believe!

0 Votes 0 ·
yagmoth555 avatar image
0 Votes"
yagmoth555 answered

Hi

The foreach seem ok, did you tried without the | foreach {$_.Delete()} to see if the commandlet Get-ChildItem -Path C:\Temp\Testing*\Beep* -Include * return what you need ?

I tell that as the asterix in your path need a -Recurse to make it work, and the last asterix need a * if it's for the directory's content you search for.

Get-ChildItem -Path C:\Temp\Testing*\Beep* -Include * -Recurse

Thanks

Philippe

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JeffL-4062 avatar image
0 Votes"
JeffL-4062 answered JeffL-4062 edited

Hi Philippe,

Yep, the command works/does what I want it to, I don't need the recurse as I'm not doing subdirectories AFAIK.. All I need is to get output from the command (all the files that were deleted) and dump it to a file.

J

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RichMatheisen-8856 avatar image
1 Vote"
RichMatheisen-8856 answered RichMatheisen-8856 edited

A "ForEach" is a shortcut for the "ForEach-Object" cmdlet -- provided it's followed immediately by a block of code. Pipelining is usable.

On the other hand, a "ForEach" followed immediately by an expression is parsed as a PowerShell keyword. There is no pipeline.

This code should get you a report, and it will act in a predictable fashion if you encounter a file you can't remove. Also, the Get-ChildItem cmdlet will retrieve only files. The example you posted will also return directory names (but not the contents of the directory:

 Get-ChildItem C:\Temp\Testing*\Beep* -Include * -File | 
     ForEach-Object {
         $fn = $_.FullName
         Try {
             Remove-Item $_.FullName -ErrorAction Stop
             [PSCustomObject]@{
                 Path   = $_.FullName
                 Action = "Removed"
                 Error  = ""
             }
         }
         Catch {
             [PSCustomObject]@{
                 Path   = $fn
                 Action = "NotRemoved"
                 Error  = $_
             }
         }
     } | Export-Csv SomeFilePath -NoTypeInformation

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JeffL-4062 avatar image
0 Votes"
JeffL-4062 answered

Thanks Rich, that did it, appreciate your help.

J

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

JeffL-4062 avatar image
0 Votes"
JeffL-4062 answered RichMatheisen-8856 commented

So this worked fine in test with just a couple directories thrown in, but on Server 2019 with 100's of results, it doesn't delete anything just throws the below error: Any thoughts?

"Path","Action","Error"
,"NotRemoved","Cannot bind argument to parameter 'Path' because it is null."

The initial command pulls down all the folders/files properly, but it seems somewhere the logic loop is pulling back a null value? Any thoughts?

· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Verify that you can see the file names without getting an error.

 (Get-ChildItem C:\Temp\foo* -Include * -File).fullname
0 Votes 0 ·

To be clear -- you get 100's of these errors?

0 Votes 0 ·
JeffL-4062 avatar image JeffL-4062 RichMatheisen-8856 ·

TOnly 1 error, the get-childitem command outputs all the desired folders/files without errors, and the output file shows the above pasted error when the script is executed in full.. Not sure if it's PS version related? Unfortunately I can't update it to verify right now as some in house apps are reliant on .Net and it would need updating as well..

I've tried with and without the Stop action and it does the same thing. The goal here is to delete all data within a subdirectory of all user profiles on the server if that helps.

Get-ChildItem 'C:\Users*\AppData\Roaming\Blah\Blah2\Blah3*' -Recurse
ForEach-Object {
Try {
Remove-Item $.FullName -ErrorAction Stop
[PSCustomObject]@{
Path = $
.FullName
Action = "Removed"
Error = ""
}
}
Catch {
[PSCustomObject]@{
Path = $.FullName
Action = "NotRemoved"
Error = $

}
}
} | Export-Csv C:\Temp\RR_Cleanup_Output.csv -NoTypeInformation

Thanks,

Jeff

0 Votes 0 ·

I'm not sure your problem is with the Get-ChildItem. Even if it did return a $null result it would NOT be passed through the pipeline!

It may be that there's a file in one of the folders that has a problem. A bad ACL? A path that's too long (i.e. greater than 260 characters -- including a binary zero at the end that you never see)?

Check the CSV for the previous and next file that was removed. That should locate the problem in the directory hierarchy.

A too long path can still be used. You just have to precede it with "\\?\".

0 Votes 0 ·
JeffL-4062 avatar image
0 Votes"
JeffL-4062 answered

Looks like it's working based on the Whatif run, thanks guys. Appreciate all the help!

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.