Home > other >  Powershell - Rename files preserving part of the name checksum
Powershell - Rename files preserving part of the name checksum

Time:01-26

I have some long filenames that potensially can cause issues with Windows path max chars, and I would like to rename them preserving part of it - and also adding a RNG 4 letter/digit combination.

Filename example: 478432_1400_79834_SomeKindofText_UserInputSoItCanBeReallyLongCombinedWithANetworkPath.jpg Wanted rename outcome:
478432_1400_79834_SomeKindofText_abc1.jpg
Where 'abc1' represents the 4 letter/digit combination of a checksum

This is the code I have so far:

$search_folder = "C:\PS\Test\"

Get-ChildItem $search_folder -File | ForEach-Object {
    $checksum = Get-FileHash -Path $_
    $checksum = $checksum.substring(0,3)
    Rename-Item -NewName { $search_folder $_.BaseName.Split('_')[0..3]   $checksum   $_.Extension }
}

My first problem is that Get-FileHash does not support substring method, generating a error message:

Method invocation failed because [Microsoft.Powershell.Utility.FileHash] does not contain a method named 'substring'.

My second problem is that it tries to do a Resolve-Path in my current PS shell directory instead of $search_folder

My third problem is that the underscores in the filename is not preserved, so a -WhatIf tag on the Rename-Item method yields a result like "478432 1400 79834 SomeKindofText"

Tips or suggestions would be most welcomed!

CodePudding user response:

My first problem is that Get-FileHash does not support substring method, generating a error message:

Method invocation failed because [Microsoft.Powershell.Utility.FileHash] does not contain a method named 'substring'.

$checksum does not store the hash string, it stores an object that has a property named Hash, which in turn stores the string you want, so change this line:

$checksum = $checksum.substring(0,3)

To:

$checksum = $checksum.Hash.Substring(0,3)

My second problem is that it tries to do a Resolve-Path in my current PS shell directory instead of $search_folder

Two general solutions to this problem:

  1. Pass the absolute path to the file explicitly:

    Rename-Item -LiteralPath $_.FullName -NewName { ... }
    
  2. Or pipe the output from Get-ChildItem directly to Rename-Item and let PowerShell bind the path correctly:

    $_ |Rename-Item -NewName { ... }
    

My third problem is that the underscores in the filename is not preserved, so a -WhatIf tag on the Rename-Item method yields a result like "478432 1400 79834 SomeKindofText"

Splitting a string on '_' will also remove the underscores - to reverse this, use '_' as a delimiter in a -join operation:

$firstFourPartsOfBaseName = $_.BaseName.Split('_')[0..3] -join '_'

Putting this all together, we get:

$search_folder = "C:\PS\Test\"

Get-ChildItem $search_folder -File | ForEach-Object {
    $checksum = Get-FileHash -Path $_
    $checksum = $checksum.hash.substring(0,3)
    $_ |Rename-Item -NewName { 
        # calculate new base name ("478432_1400_79834_SomeKindofText_abc1")
        $newBasename = @($_.BaseName.Split('_')[0..3]; $checksum) -join ''
        # add extension and output
        $newBasename,$_.Extension -join '.'
    }
}

CodePudding user response:

Please see your script adjusted below:

$search_folder = "C:\PS\Test\"

Get-ChildItem $search_folder -File | ForEach-Object {
    $checksum = Get-FileHash -Path $_
    $checksum = $checksum.hash.substring(0,3)
    Rename-Item -Path $_ -NewName ($search_folder   $_.BaseName.Split('_')[0..3]   $checksum   $_.Extension)
}

You were trying to get a sub string of an object, using the property hash on $Checksum will allow you to create a substring.

I have also added -path to the rename-item request and changed the parenthesis on the string construction (it could be either of these that were causing you an issue, unfortunately I haven't tested this.)

  •  Tags:  
  • Related