Search code examples
powershellpowershell-3.0

Rename-Item error: Cannot rename because item does not exist


I have the following powershell code, which is attempting to rename all SQL files in a folder, adding a unique prefix to each file e.g. the first prefix will be '1001 - sp - C - ':

gci -Path 'C:\FolderToLookIn' -Exclude "1*" | ForEach-Object {
    New-Object PSObject -Property @{
        'LineNumber' = $linenumber;
        'Name'       = $_.Name;
        'Extension'  = $_.Extension
    };
    $linenumber++
} | Where-Object {
    $_.Extension -eq ".sql"
} | Rename-Item -NewName {$_.LineNumber.ToString("1000") + ' - sp - C - ' + $_.Name}

However, this produces errors such as the following:

Rename-Item : Cannot rename because item at '@{Extension=.sql; LineNumber=22; Name=sp_Firm_GetAll.sql}' does not exist.

So, how can I add the LineNumber property and use it as a prefix in the Rename-Item command without losing the item itself?


Edit

I have also tried the following, passing through the FullName and using this in the Rename-Item:

gci -Path 'C:\FolderToSearch' -Exclude "1*" | ForEach-Object {
    New-Object psObject -Property @{
        'LineNumber' = $linenumber;
        'Name'       = $_.Name;
        'Extension'  = $_.Extension;
        'FullName'   = $_.FullName
    };
    $linenumber++
} | Where-Object {
    $_.Extension -eq ".sql"
} | Rename-Item -Path $_.FullName -NewName {$_.LineNumber.ToString("1000") + ' - sp - C - ' + $_.Name}

However, this errors also:

Rename-Item : Cannot bind argument to parameter 'Path' because it is null.
At line:3 char:19
+ Rename-Item -Path $_.FullName -NewName {$_.LineNumber.ToString("1000") + ' - sp

Solution

  • As

    • Rename-Item accepts piped input the ForEach isn't necessary and
    • with a [Ref] you can increment a counter inside the -NewName {scriptblock}

    $Folder = 'C:\FolderToLookIn'
    
    $Count = [ref] 0
    Get-ChildItem -Path $Folder -Filter *.sql -File |
      Where-Object Name -NotMatch '^\d{4} - sp - C - ' | 
        Rename-Item -Newname {"{0:1000} - sp - C - {1}" -f $Count.Value++,$_.Name}
    

    A sample folder with A.sql, B.sql, C.sql will have this result:

    > gci *.sql -name
    1000 - sp - C - A.sql
    1001 - sp - C - B.sql
    1002 - sp - C - C.sql
    

    A variant which first obtains the last/highest number from existing files or sets 1000 as the start.

    $Count = [Ref][math]::Max(1000,
        [int](Get-ChildItem -Path $Folder -Filter *.sql -File|
                Where-Object Name -match '^(\d{4}) - sp - C -' | 
                Select-Object @{n='Count';e={$Matches[1]}} -Last 1).Count)
    
    Get-ChildItem -Path $Folder -Filter *.sql -File |
      Where-Object Name -NotMatch '^\d{4} - sp - C - ' | 
        Rename-item -Newname {"{0:D4} - sp - C - {1}" -f ++$Count.Value,$_.Name}