1

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.

1 Answer 1

2

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] @{ ... }.

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.