0

I wish to send file and folder attributes to either a csv file or to the screen depending on the boolean value of $debug. I have tried to accomplish this by including a ternary operator in the end of the following pipeline:

Get-ChildItem $directory -Recurse -File |
    Select-Object @{name='Folder_Name';expression={$($_.directoryname)}},
                  @{name='File_type';expression={$($_.extension)}},
                  @{name='File_name';expression={$($_.name)}},
                  @{name='File_size_bytes';expression={$($_.length)}},
                  @{name='Creation_datetime';expression={$($_.creationtime)}},
                  @{name='Last_update_datetime';expression={$($_.lastwritetime)}},
                  @{name='Last_read_datetime';expression={$($_.lastaccesstime)}} |
                  (&{if ($debug) {Write-Host} else {Export-Csv -path $outpath -NoTypeInformation -force -Delimiter ';'}})

Is this a bad approach, and which approach is recommended?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Gustav Rasmussen
  • 3,720
  • 4
  • 23
  • 53
  • 1
    using `Write-Host` sends stuff to the screen directly, not to "stdout" as such. that would use `Write-Output`. also, you are not sending any thing other than a newline to the screen. ///// most importantly, `Expressions are only allowed as the first element of a pipeline.` so your last line means the code will never run. – Lee_Dailey Oct 24 '19 at 10:47
  • 1
    is there a reason to NOT simply save to a $Var and then decide where to send the output? – Lee_Dailey Oct 24 '19 at 10:55
  • Thanks for your feedback @Lee_Dailey . I updated the description now wrt. Write-Host / stdout. Could you please provide an answer to show the assignment of the pipeline to a variable which I can then use inside the control flow subsequently? Something like this? | -outvariable variable – Gustav Rasmussen Oct 24 '19 at 10:57
  • please see my answer ... it is far less than optimal, but you don't seem to want to hear that. [*sigh ...*] – Lee_Dailey Oct 24 '19 at 11:15
  • @Lee_Dailey thank you for the answer which I have accepted. Not sure what you mean with "but you don't seem to want to hear that.". On the contrary, I would very much appreciate to see your suggestion for a better solution.The thing is, I do need to write a file for each folder looked down into recursively, so I do need several file-writes. – Gustav Rasmussen Oct 24 '19 at 11:28
  • 1
    thanks! [*grin*] one idea would be to put it into a function that accepts the top dir as a parameter, add any other parameters you need, gather all the info into one $Var, then send that $Var out to the caller. let the caller decide how to use that info. it's the "tool versus controller" idea. – Lee_Dailey Oct 24 '19 at 11:58
  • 1
    another idea would be to just save the output of your pipeline to a $Var. then use that as needed. – Lee_Dailey Oct 24 '19 at 11:59
  • Thank you for these suggestions @Lee_dailey . Is one of these two methods better than the other? I need to ultimately produce a file in each folder listing the statistics of files and subfolders – Gustav Rasmussen Oct 24 '19 at 12:02
  • 1
    the 2nd is simpler, the 1st is more flexible. if you have already written advanced functions and are comfy with them, then the 1st is the way to go. i would likely start off with just the 2nd, tho. [*grin*] – Lee_Dailey Oct 24 '19 at 12:38
  • 1
    For a ternary operator you would need powershell 7: `1 ? 'yes' : 'no'` – js2010 Oct 25 '19 at 12:54

1 Answers1

1

this will do what you seem to want. however, it is a REALLY strange way to handle the problem. it is SLOW since it does a file write for every item OR a screen write for each item if that is enabled. saving to a $Var and then writing to file and/or screen would be much faster. [grin]

this code expands your last line into a ForEach-Object call with an if to test the output destination. it also adds an -ErrorAction to the Get-ChildItem call to handle "inaccessible file" errors.

it also removes the unneeded $() in the expression = lines.

$directory = $env:TEMP
$outpath = "$env:TEMP\GustavRasmussen.csv"

# uncomment the 2nd line to test the negative
$ToScreen = $True
#$ToScreen = $False

Get-ChildItem $directory -Recurse -File -ErrorAction SilentlyContinue |
    Select-Object @{name='Folder_Name';expression={$_.directoryname}},
                  @{name='File_type';expression={$_.extension}},
                  @{name='File_name';expression={$_.name}},
                  @{name='File_size_bytes';expression={$_.length}},
                  @{name='Creation_datetime';expression={$_.creationtime}},
                  @{name='Last_update_datetime';expression={$_.lastwritetime}},
                  @{name='Last_read_datetime';expression={$_.lastaccesstime}} |
    ForEach-Object {
        if ($ToScreen)
            {
            $_
            }
            else
            {
            Export-Csv -InputObject $_ -path $outpath -NoTypeInformation -force -Delimiter ';' -Append
            }
        }

1st three lines of the CSV ...

"Folder_Name";"File_type";"File_name";"File_size_bytes";"Creation_datetime";"Last_update_datetime";"Last_read_datetime"
"C:\Temp";".tmp";"DELCD3A.tmp";"861968";"2019-07-13 11:43:18 PM";"2019-07-13 11:42:36 PM";"2019-07-13 11:43:18 PM"
"C:\Temp";".txt";"FXSAPIDebugLogFile.txt";"0";"2015-11-03 6:54:02 PM";"2015-11-03 6:54:02 PM";"2015-11-03 6:54:02 PM"
"C:\Temp";".log";"Genre-List_2019-10-01.log";"178";"2019-10-01 12:33:47 PM";"2019-10-01 12:33:47 PM";"2019-10-01 12:33:47 PM"

the 1st three items of the screen output ...

Folder_Name          : C:\Temp
File_type            : .tmp
File_name            : DELCD3A.tmp
File_size_bytes      : 861968
Creation_datetime    : 2019-07-13 11:43:18 PM
Last_update_datetime : 2019-07-13 11:42:36 PM
Last_read_datetime   : 2019-07-13 11:43:18 PM

Folder_Name          : C:\Temp
File_type            : .txt
File_name            : FXSAPIDebugLogFile.txt
File_size_bytes      : 0
Creation_datetime    : 2015-11-03 6:54:02 PM
Last_update_datetime : 2015-11-03 6:54:02 PM
Last_read_datetime   : 2015-11-03 6:54:02 PM

Folder_Name          : C:\Temp
File_type            : .log
File_name            : Genre-List_2019-10-01.log
File_size_bytes      : 178
Creation_datetime    : 2019-10-01 12:33:47 PM
Last_update_datetime : 2019-10-01 12:33:47 PM
Last_read_datetime   : 2019-10-01 12:33:47 PM
Lee_Dailey
  • 7,292
  • 2
  • 22
  • 26
  • 1
    This is **not** a "strange way", this **the** PowerShell way and is most efficient with regards to memory usage and *could* be even faster in some (practical) scenario's, e.g. where your running out of physical memory or when the input stream is slow (e.g. a remote directory), see: [Advocating native PowerShell](https://stackoverflow.com/a/58357033/1701026) – iRon Oct 24 '19 at 14:33
  • 1
    @iRon - you and i seem to differ on "strange way". the better-to-me way is the simplest, most direct method ... and - to me - it is achieved by accumulating the data and THEN outputting it. from my point of view, writing to a file line-by-line-by-line is woefully inefficient and is a bad design choice _unless it is needed_. ///// however, the world is a varied place and it would be boring if we all agreed on everything. [*grin*] – Lee_Dailey Oct 24 '19 at 18:29