Michael McIntyre
Michael McIntyre

Reputation: 225

Piping Powershell output to a text file

I have the following powershell script that renames files from one location to another with a sequential filename. Ultimately, these file changes need to be mapped, as in original - new. Currently, I just have a Write-Host cmdlet and I just copy the cmd windows output into a txt file then run through a python script I wrote to spit out the original and renamed files into an excel file. I was wondering if there was an easier way to do this in the initial ps script. Even something tab delimited would be easily copy-pasteable into an excel file.

Set-Location -Path "C:\Users\mmcintyre\Desktop\grail_new"
$destLoc = "C:\Users\mmcintyre\Desktop\renamed"
$countRef = [ref] 0
Get-ChildItem -Filter *.pdf -Recurse |
   Copy-Item -WhatIf -Destination { '{0}\{1}.pdf' -f $destLoc,++$countRef.Value }

Any help would be greatly appreciated.

Edit: I am currently using PS 2.0.

Upvotes: 1

Views: 444

Answers (1)

mklement0
mklement0

Reputation: 437698

The following outputting old-name/new-name pairs to a TSV file in addition to the copy operation (PSv3+ syntax):

$countRef = [ref] 0
Get-ChildItem -Filter *.pdf -Recurse | ForEach-Object {
  $newFullName = '{0}\{1}.pdf' -f $destLoc, ++$countRef.Value
  Copy-Item -WhatIf -LiteralPath $_.FullName -Destination $newFullName
  [pscustomobject] @{
    Old = $_.FullName
    New = $newFullName
  }
} | Export-Csv -Delimiter "`t" NameMappings.tsv

This creates a TSV (tab-separated values) file with columns named Old and New that contain the old and new full filenames, respectively.


PSv2: The [pscustomobject] @{ ... } syntactic sugar for creating custom objects from hashtables is not available in v2, so New-Object must be used:

$countRef = [ref] 0
Get-ChildItem -Filter *.pdf -Recurse | ForEach-Object {
  $newFullName = '{0}\{1}.pdf' -f $destLoc, ++$countRef.Value
  Copy-Item -WhatIf -LiteralPath $_.FullName -Destination $newFullName
  New-Object PSCustomObject -Property @{
    Old = $_.FullName
    New = $newFullName
  }
} | Export-Csv -Delimiter "`t" NameMappings.tsv

Caveat: -Property accepts a hashtable[1] , which means that its key ordering is not guaranteed, so the ordering of properties of the resulting object will typically not reflect the input order - in this case it just happens to do so.

If the resulting property order is undesired, you have two options:

  • Slow, but convenient: insert a Select-Object call with the properties in the desired order (e.g., Select-Object Old, New).

  • More cumbersome: Construct the object empty at first New-Object PSCustomObject, and then attach properties one by one in the desired order with individual Add-Member calls.


[1] The PSv3+ [pscustomobject] @{ ... } syntax is seemingly also hashtable-based, but it is parsed in a way that preserves the key order; i.e., as if you had implicitly used [ordered] @{ ... }.

Upvotes: 2

Related Questions