Atis
Atis

Reputation: 93

powershell compare file names and rename

I have two directories with files in both of them. File count is different but file names are somewhat equal. For example:

C:\dwg 
AR-01-12 - file name0.dwg
AR-01-13 - file name1.dwg
AR-01-14 - file name2.dwg

C:\pdf 
AR-01-11 - file name_.pdf
AR-01-12-R1 - file name0.pdf
AR-01-13 - file name1.pdf
AR-01-14-R5 - file name2.pdf
AR-01-15-R4 - file name3.pdf

Using powershell, how to rename files in C:\dwg folder so that they have this R abbreviation (from Revision) suffix added to name from file names in C:\pdf folder ? The result would be:

C:\dwg 
AR-01-12-R1 - file name0.dwg
AR-01-13 - file name1.dwg
AR-01-14-R5 - file name2.dwg

My logic would be to check if the first part of the filename is in the pdf directory, if it exists rename file, leaving the extencion.

Upvotes: 1

Views: 1865

Answers (2)

postanote
postanote

Reputation: 16076

Continuing from my comment.

Of course, PowerShell allows several ways to do this. Here is a bit different approach. I show the step-thru to show how I came to the result.

# Create a file set
'AR-01-12 - file name0.dwg',
'AR-01-13 - file name1.dwg',
'AR-01-14 - file name2.dwg' | 
ForEach {New-Item -Path "d:\temp\dwg\$PSItem" -ItemType File -Force}
Get-ChildItem -Path 'd:\temp\dwg'


'AR-01-11 - file name_.pdf',
'AR-01-12-R1 - file name0.pdf',
'AR-01-13 - file name1.pdf',
'AR-01-14-R5 - file name2.pdf',
'AR-01-15-R4 - file name3.pdf' | 
ForEach {New-Item -Path "d:\temp\pdf\$PSItem" -ItemType File -Force}
Get-ChildItem -Path 'd:\temp\pdf'

# Get only needed files
Clear-Host
(
$DifferenceFiles = Get-ChildItem -Path 'd:\temp\pdf' | 
Where-Object -Property Name -Match '-R\d'
)
# Results
<#
    Directory: D:\temp\pdf

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         31-Mar-21     13:30              0 AR-01-12-R1 - file name0.pdf
-a----         31-Mar-21     13:30              0 AR-01-14-R5 - file name2.pdf
-a----         31-Mar-21     13:30              0 AR-01-15-R4 - file name3.pdf
#>

($ReferenceFiles = Get-ChildItem -Path 'd:\temp\dwg')
# Results
<#
    Directory: D:\temp\dwg

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         31-Mar-21     13:30              0 AR-01-12 - file name0.dwg   
-a----         31-Mar-21     13:30              0 AR-01-13 - file name1.dwg   
-a----         31-Mar-21     13:30              0 AR-01-14 - file name2.dwg 
#>


# Validate via string matching
Clear-Host
Get-ChildItem -Path 'd:\temp\pdf' | 
Where-Object -Property Name -Match '-R\d' | 
ForEach{
    ((Get-ChildItem -Path 'd:\temp\dwg').FullName -match ([regex]::Matches($PSItem.BaseName,$BaseNameString))) -replace $BaseNameString, ($PSItem.BaseName -replace '-R.*')
}
# Results
<#
D:\temp\dwg\AR-01-12 - file name0.dwg
D:\temp\dwg\AR-01-14 - file name2.dwg
#>

# Validate rename
Clear-Host
Get-ChildItem -Path 'd:\temp\pdf' | 
Where-Object -Property Name -Match '-R\d' | 
ForEach{
    If (($FilePath = (Get-ChildItem -Path 'd:\temp\dwg').FullName -match ([regex]::Matches($PSItem.BaseName,'..-\d+.-\d+'))))
    {
        $FileUnc = Get-ChildItem -Path $FilePath
        Rename-Item -Path $FileUnc -NewName "$($PSItem.BaseName)$($FileUnc.Extension)" -WhatIf
    }
}
# Results
<#
What if: Performing the operation "Rename File" on target "Item: D:\temp\dwg\AR-01-12 - file name0.dwg Destination: D:\temp\dwg\AR-01-12-R1 - file name0.dwg".
What if: Performing the operation "Rename File" on target "Item: D:\temp\dwg\AR-01-14 - file name2.dwg Destination: D:\temp\dwg\AR-01-14-R5 - file name2.dwg".
#>

# Execute actions
Clear-Host
Get-ChildItem -Path 'd:\temp\pdf' | 
Where-Object -Property Name -Match '-R\d' | 
ForEach{
    If (($FilePath = (Get-ChildItem -Path 'd:\temp\dwg').FullName -match ([regex]::Matches($PSItem.BaseName,'..-\d+.-\d+'))))
    {
        $FileUnc = Get-ChildItem -Path $FilePath
        Rename-Item -Path $FileUnc -NewName "$($PSItem.BaseName)$($FileUnc.Extension)" -Verbose
    }
}
# Results
<#
VERBOSE: Performing the operation "Rename File" on target "Item: D:\temp\dwg\AR-01-12 - file name0.dwg Destination: D:\temp\dwg\AR-01-12-R1 - file name0.dwg".
VERBOSE: Performing the operation "Rename File" on target "Item: D:\temp\dwg\AR-01-14 - file name2.dwg Destination: D:\temp\dwg\AR-01-14-R5 - file name2.dwg"
#>

# Review results
Get-ChildItem -Path 'd:\temp\dwg'
# Results
<#
    Directory: D:\temp\dwg

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         31-Mar-21     13:30              0 AR-01-12-R1 - file name0.dwg
-a----         31-Mar-21     13:30              0 AR-01-13 - file name1.dwg
-a----         31-Mar-21     13:30              0 AR-01-14-R5 - file name2.dwg
#>

One could have taken the Compare-Object route as well, then work with those results.

Clear-Host

$ReferenceFiles = Get-ChildItem -Path 'd:\temp\pdf' | 
                  Where-Object -Property Name -Match '-R\d'

$DifferenceFiles = Get-ChildItem -Path 'd:\temp\dwg'

$CompareObjectSplat = @{
    ReferenceObject  = ($ReferenceFiles -replace '-R.*.*')
    DifferenceObject = ($DifferenceFiles -replace ' - *.*') 
    IncludeEqual     = $true
}
Compare-Object @CompareObjectSplat | 
Where-Object -Property SideIndicator -eq '=='
# Results
<#
AR-01-12    ==           
AR-01-14    == 
#>

Upvotes: 1

Steven
Steven

Reputation: 7057

I hope I have this correct. To rephrase:

For each file in c:\dwg look for a similarly named pdf file with a revision number in c:\pdf. If the file is found rename the file in c:\dwg to have the same base name as the PDF file. Per comments, there may be 1 or zero files matching this criterion in the C:\PDF folder. Obviously, the rename should only occur if a match is found.

$RefFiles = @(Get-ChildItem 'C:\pdf' -File)

Get-ChildItem 'C:\dwg' -File |
ForEach-Object{
    # Calculate a regex to match for in the reference folder.
    $RegEx = $_.BaseName -replace " - ", '-r\d{1,} - '
    $NewName = ($RefFiles.Name -match $RegEx)[0]
    
    If( $NewName ) 
    {
        # Replace extension:
        $NewName = $NewName.SubString( 0, $NewName.LastIndexOf('.') ) + $_.Extension
        Rename-Item $_.FullName $NewName -WhatIf
    }
}

Explanation:

  1. For each file in C:dwg we calculate a regular expression to match against file names in c:\pdf.
  2. Use the -match operator against the array with the previously calculated RegEx. Note: the Get-ChildItem command is wrapped in an array subexpression @(...). This is to ensure consistent behavior of the -match operator later on. Otherwise, on the off chance only 1 object was returned -match would return a Boolean instead of an array of matches...
  3. Swap out the extension so we get the new name correct.
  4. Then finally execute the Rename-Item command.

If there were potential for multiple revisions in the c:\pdf folder, you could add Sort-Object & Select-Object to say get the latest revision, etc...

Note: The RegEx could be perfected. Right now it looks for any number of digits after the -r. If you know the maximum possible revision number you might limit that like -r\d{1,2} which would allow 100 possible revision #s from 0 -99.

Upvotes: 2

Related Questions