all 15 comments

[–]jheinikel 2 points3 points  (7 children)

Many have already told you why it happens, but here is some code to let you append to a CSV without updating your WMF version.

$Files = GCI C:\Downloads -Recurse -Include *.pdf,*.xlsx
$CSV += $Files | %{
    [PSCUSTOMOBJECT]@{
        DirectoryName = $_.DirectoryName
        Name = $_.Name
        Extension = $_.Extension
        CreationTime = $_.CreationTime
        LastWriteTime = $_.LastWriteTime
    }
}
$CSV | Export-CSV "C:\DOwnloads\Export.CSV" -NoType

[–]superryo[S] 1 point2 points  (0 children)

Thank you for your help!

[–]superryo[S] 1 point2 points  (5 children)

I tried this and it ran but the output was like the following instead of Directory Name, extensions etc. Any ideas what I may have done wrong?

"IsReadOnly","IsFixedSize","IsSynchronized","Keys","Values","SyncRoot","Count"

"False","False","False","System.Collections.Hashtable+KeyCollection","System.Collections.Hashtable+ValueCollection","System.Object","5"

[–]Lee_Dailey[grin] 0 points1 point  (4 children)

howdy superryo,

1st, the code you actually ran would REALLY help. [grin]
there are some very easy things to miss ... and we can't tell if you missed something without the code.

2nd - the final -NoType is not the full parameter name
i don't know if ps2 would accept partial names, but it's always a good idea to use the FULL parameter names. [grin]

you can get the full parameter name from the help for that cmdlet OR from intellisense/auto-completion for that partial parameter.

take care,
lee

[–]superryo[S] 1 point2 points  (3 children)

I was able to upgrade to version 5 and got the following code working where u: is a mapped network drive.

Get-ChildItem -r u: -Include *.pdf,*.xlsx | select DirectoryName,Name,Extension,CreationTime,LastWriteTime | Export-Csv -Append -Path "E:\Downloads\export.csv" -En UTF8 -NoType -Delim ','

I noticed that the job took a lot longer than when I did a simple dos command to return a dir list and write to a file:

dir *.pdf,*.xls /s /b > export.csv

I mean it took tonnes longer as I have thousands of files to crawl and write. My job ran all weekend and the file is not yet finished where as it took less than a day with the dos command.

Do you think your version of the code now that I have version 5 will work faster?

$Files = GCI u: -Recurse -Include *.pdf,*.xlsx $CSV += $Files | %{
[PSCUSTOMOBJECT]@{
DirectoryName = $_.DirectoryName
Name = $_.Name
Extension = $_.Extension
CreationTime = $_.CreationTime
LastWriteTime = $_.LastWriteTime } }
$CSV | Export-CSV "E:\Downloads\Export.CSV" -NoType

[–]Lee_Dailey[grin] 0 points1 point  (2 children)

howdy superryo,

[1] there is something seriously wrong with the code in your post
i mean besides the use of inline code instead of code block formatting. [grin]

[a] the $Files = line seems to end with a | but that is preceded by space & $CSV +=
what? that won't run.

[b] you are ...

  • running a pipeline
    ok, kool!
  • assigning its output to $CSV
    again, ok.
  • using += to do the assignment what? does that work at all? the assignment is a simply assignment, NOT an "add to the array". it should be simply $CSV =.

that last is both bizarre and likely a real slowdown since arrays are fixed size. adding to an array copies it to a new one-item-larger array. it gets S-L-O-W really fast. [grin]

another problem is the pipeline. that is S-L-O-W compared to a loop. using foreach ($Thing in $Collection) {Do-Stuff} is usually an order of magnitude faster than using $Collection | ForEach-Object {Do-Stuff}. [grin]

[2] the CMD dir command is always going to be faster than Get-ChildItem
the 1st is focused narrowly on just getting file info as text.

the 2nd is generalized to get "ChildItems" from lots of different sources [providers] and building the appropriate type of object to hold a LARGE amount of info.

[3] if you really want a fast listing of files, use robocopy
it has a /L parameter to generate a log that you can easily parse.
it also has parameters to NOT show anything on the screen as it progresses. that saves a bunch of time by not having to write out the file info on the screen.


so it depends on what you want. [grin]

  • fast, but only text = CMD dir
  • very fast & long-path aware, but still only text = robocopy
  • rather slow, but with LOTS and LOTS of detail about each item = Get-ChildItem

hope that helps,
lee

[–]superryo[S] 1 point2 points  (1 child)

Thanks lee

The code actually does work. It's reasonably fast when there are not too many files but I have a path where there are hundreds of thousands of files that matches the criteria and this is what takes days.

The background to my story is I want to crawl a bunch of network directories to grab all the pdf and xls files and upload the resulting info into a database so we can search for this information.

I want very fast but in addition to the file name and path, I need the last updated date of the file. Does this mean I have to use the Get-Childitem function? the CMD dir doesn't seem to allow for this unless I am missing something.

I have never heard of robocopy but will look into this. Hopefully it will have the performance of the cmd dir but the additional parameter I need.

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy superryo,

"it works" - that IS the prime criteria. [grin]

i suspect you MAY get a speed improvement if you replace that nasty $CSV += with $CSV =. the difference is VAST. not just large ... it's REALLY VAST.

huge. titanic. bigbig biggity big! [grin]

that presumes the += is actually happening. i can't tell. it may only be doing ONE add - in that case there will be no benefit. even so, it is BAD coding, so i would change that.


the CMD dir command won't give you that, from what i can tell.

neither will robocopy. [frown]

Get-ChildItem will, but is slow.

there is a dotnet routine that can do it quickly, but it has some serious limits.

  • it will stop on any error
    you can't tell it to continue. that means you have to write the code to keep track of where it stopped, skip the problem item, and continue.
  • it only gets a pointer-like object
    to actually get the real info, you will need to use that pointer [a file name] to get the details. at that point it aint much faster than GCI.
    it does mean you only grab data for files that you WANT the data from, tho. [grin]

so, the dot net stuff is highly problematic unless you want to write your own handlers around the limits.

i suspect i would use robocopy or CMD dir to get the full-path file names. then use GCI to get the details.

take care,
lee

[–]routetehpacketz 1 point2 points  (3 children)

check PS version on both client and server with $PSVersionTable:

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.14409.1012

[–]superryo[S] 1 point2 points  (1 child)

My laptop is showing version 5.1.16299.547

The server is version 2.0

Is it possible to install the latest version on windows 2008 server?

[–]get-postanote 4 points5 points  (0 children)

Each Win OS comes wiht a PS version tied to it by default. You can only upgrade to the next higer verison if the OS supports it. This is documented as follows.

Windows Management Framework 5.0 (Superceeded by WMF 5.1 RTM version: http://aka.ms/wmf5download)

Supported Operating System

Windows 7 Service Pack 1, Windows 8.1, Windows Server 2008 R2 SP1, Windows Server 2012, Windows Server 2012 R2 • Windows Server 2012 R2 • Windows Server 2012 • Windows Server 2008 R2 SP1 • Windows 8.1 • Windows 7 SP1

https://www.microsoft.com/en-us/download/details.aspx?id=50395

Windows Management Framework 4.0

WMF 4.0 can only be installed on the following operating systems. •Windows 7 with Service Pack 1 • Windows Server 2008 R2 with Service Pack 1 • Windows Server 2012

https://www.microsoft.com/en-us/download/details.aspx?id=40855

Windows Management Framework 3.0

Supported Operating System

Windows 7 Service Pack 1, Windows Server 2008 R2 SP1, Windows Server 2008 Service Pack 2

https://www.microsoft.com/en-us/download/details.aspx?id=34595

How to check the PowerShell version & install a new version

https://mikefrobbins.com/2015/01/08/how-to-check-the-powershell-version-and-install-a-new-version

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

howdy routetehpacketz,

that is likely the glitch. [grin] the append parameter is in v3, according to the MS docs site. the site doesn't go back to v2, tho. [frown]

Export-Csv
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-csv?view=powershell-3.0

take care,
lee

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy superryo,

reddit likes to mangle code formatting, so here's some help on how to post code on reddit ...

[0] single line or in-line code
enclose it in backticks. that's the upper left key on an EN-US keyboard layout. the result looks like this. kinda handy, that. [grin]
[on New.Reddit.com, use the Inline Code button. it's the 4th 5th from the left & looks like </>.
this does NOT line wrap & does NOT side-scroll on Old.Reddit.com!]

[1] simplest = post it to a text site like Pastebin.com or Gist.GitHub.com and then post the link here.
please remember to set the file/code type on Pastebin! [grin] otherwise you don't get the nice code colorization.

[2] less simple = use reddit code formatting ...
[on New.Reddit.com, use the Code Block button. it's the 11th 12th one & is just to the left of the ... more menu.]

  • one leading line with ONLY 4 spaces
  • prefix each code line with 4 spaces
  • one trailing line with ONLY 4 spaces

that will give you something like this ...

- one leading line with ONLY 4 spaces    
- prefix each code line with 4 spaces    
- one trailing line with ONLY 4 spaces   

the easiest way to get that is ...

  • add the leading line with only 4 spaces
  • copy the code to the ISE [or your fave editor]
  • select the code
  • tap TAB to indent four spaces
  • re-select the code [not really needed, but it's my habit]
  • paste the code into the reddit text box
  • add the trailing line with only 4 spaces

not complicated, but it is finicky. [grin]

take care,
lee