¿Cómo puedo cambiar el nombre de un directorio reemplazando la primera letra de cada palabra en la cadena del nombre a mayúsculas?

¿Cómo puedo cambiar el nombre de un directorio reemplazando la primera letra de cada palabra en la cadena del nombre a mayúsculas?

En una computadora con Windows 10, he estado usando utilidades gratuitas como la herramienta PFrank y Power Toys PowerRenamer. Con PFrank pude cambiar el caso de cada palabra en el nombre de los archivos a mayúsculas, pero no cambiará los nombres de los directorios.

¿Conoce algún comando o script en Powershell, CMD o BASH (usando el subsistema Linux de Windows) para lograrlo? o una herramienta (preferiblemente de código abierto) que pueda hacer eso. Como ya cambio los nombres de los archivos, quiero hacer esto de forma recursiva solo en los nombres de los directorios.

Gracias.

Respuesta1

Ampliando desde mi comentario. Es simplemente esto.

Actualizar

Se eliminó la respuesta larga original y se reemplazó con lo siguiente para abordar su comentario:

(Get-ChildItem -Path 'D:\Temp' -Directory -Recurse) -match 'src|dest' | 
ForEach-Object {
    "Proccessing $($PSItem.FullName) to TitleCase"
    $renameItemTempSplat = @{
        Path     = $PSitem.FullName
        NewName  = "$((Get-Culture).Textinfo.ToTitleCase($PSitem.Name.ToLower()))1"
        #WhatIf   = $true 
    }
    Rename-Item @renameItemTempSplat -PassThru | 
    Rename-Item -NewName $($((Get-Culture).Textinfo.ToTitleCase($PSitem.Name.ToLower())) -replace '1')
}
(Get-ChildItem -Path 'D:\Temp' -Directory -Recurse) -match 'src|dest'
# Results
<#
Proccessing D:\Temp\dest to TitleCase
Proccessing D:\Temp\Destination to TitleCase
Proccessing D:\Temp\src to TitleCase


    Directory: D:\Temp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         12-Oct-20     14:27                Dest
d-----         24-Jan-21     22:24                Destination
d-----         12-Oct-20     13:27                Src
#>

Acerca de WhatIf/Confirmar

Respuesta2

Puede utilizar el Kernel32método MoveFilepara cambiar el nombre de archivos y directorios sin necesidad de cambiarlo dos veces.

El siguiente código cambia el nombre de archivos y directorios utilizando las propiedades respectivas para el nuevo nombre (según el tipo).

El método 'MoveFile' en realidad desencadena el mismo proceso que hacerlo de forma interactiva utilizando el Explorador de Windows.

# "MoveFile" works for files and folders

# only add type once
if ($null -eq ('Win32.Kernel32' -as [type])) {
    # add method 'MoveFile from' kernel32.dll
    # https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefile
    $signature = @'
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);
'@
    Add-Type -MemberDefinition $signature -Name 'Kernel32' -Namespace Win32
}

$dirPath = 'C:\temp\CaseTest'
Get-ChildItem -LiteralPath $dirPath -Recurse -Directory | ForEach-Object {
    $parentPath = $currentName = $fileExtension = $null

    if ($_ -is [System.IO.DirectoryInfo]) {
        # Directories
        $parentPath  = $_.Parent.FullName
        $currentName = $_.Name

    } elseif ($_ -is [System.IO.FileInfo]) {
        # Files
        $parentPath    = $_.Directory.FullName
        $currentName   = $_.BaseName
        $fileExtension = $_.Extension
    }

    if ($null -notin $currentName, $parentPath) {
        $newName =  @(
            [cultureinfo]::CurrentCulture.TextInfo.ToTitleCase($currentName.ToLower()),
            $fileExtension
        ) -join ''

        $newPath    = Join-Path -Path $parentPath -ChildPath $newName
        $moveResult = [Win32.Kernel32]::MoveFile($_.FullName, $newPath)

        if (-not $moveResult) {
            # 'MoveFile' returns only $false in case of errors, 
            # so we have to build the respective exception.
            # This requires "SetLastError = true" in signature
            $win32Error     = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
            $win32Exception = [System.ComponentModel.Win32Exception]$win32Error
            Write-Error -Exception $win32Exception `
                -Message "$($win32Exception.Message) `"$($_.FullName)`""
        }
    }
}

información relacionada