【powershell】Rename-Item を使いやすくする

powershell の `Rename-Item` って使いにくくありませんか？ `-whatif` パラメータをつけ忘れて暴発したことは数知れず、つけたらつけたで出力が冗長になり読みにくい……。少なくとも私は不便に感じたので安全かつ簡単な一括リネーム用のコマンドレットを作ってみました。

## プレビューを見やすくする

![renf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501098/d1b402ab-28ab-87cb-79bc-191cb662512a.png)


```powershell
function Rename-Functionally {
    param (
        [scriptblock]$renameBlock,
        [switch]$execute
    )
    $procTarget = $input | Where-Object {$_.GetType().Name -in @("FileInfo", "DirectoryInfo")}
    
    $shiftJIS = [System.Text.Encoding]::GetEncoding("Shift_JIS")
    $longestName = $procTarget.Name | Sort-Object {$shiftJIS.GetByteCount($_)} -Descending | Select-Object -First 1
    $fill = $shiftJIS.GetByteCount($longestName) + 1

    if ($execute) {
        $col = "Green"
    }
    else {
        $col = "White"
    }

    $procTarget | ForEach-Object {
        $itemName = $_.Name
        Write-Host $itemName -NoNewline -ForegroundColor DarkGray
        $leftIndent = $shiftJIS.GetByteCount($itemName)
        " {0}=> " -f ("=" * ($fill - $leftIndent)) | Write-Host -NoNewline
        $afterName = & $renameBlock
        Write-Host $afterName -ForegroundColor $col
        if ($execute) {
            try {
                $_ | Rename-Item -NewName $afterName -ErrorAction Stop
            }
            catch {
                Write-Host ("ERROR!: failed to rename '{0}'!" -f $itemName) -ForegroundColor Magenta
                if (Test-Path $afterName) {
                    Write-Host "(same name exists in directory)" -ForegroundColor Magenta
                }
                else {
                    Write-Host "(other process may opening file)" -ForegroundColor Magenta
                }
            }
        }
    }
}
```

リネーム結果をプレビューして、 `-execute` スイッチを指定した場合のみリネームを実行します。日本語が混じっていても桁が揃うように shiftJIS でバイト数をカウントしました。

## 置換リネームを簡単に

![repn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501098/ee3d264d-9f77-afeb-3b08-78fad400cbfc.png)

```powershell
function Rename-Replace {
    param (
        [string]$from,
        [string]$to,
        [switch]$case,
        [switch]$execute
    )

    if ($case) {
        $reg = [regex]$from
    }
    else {
        $reg = [regex]"(?i)$from"
    }

    $procTarget = $input | Where-Object {$reg.IsMatch($_.Name)}
    if ($procTarget.Count -lt 1) {
        return
    }

    $shiftJIS = [System.Text.Encoding]::GetEncoding("Shift_JIS")
    $longestName = $procTarget.Name | Sort-Object {$shiftJIS.GetByteCount($_)} -Descending | Select-Object -First 1
    $fill = $shiftJIS.GetByteCount($longestName) + 1

    if ($execute) {
        $color = "Cyan"
    }
    else {
        $color = "White"
    }

    $procTarget | ForEach-Object {
        $itemName = $_.Name
        $replacedName = $reg.Replace($itemName, $to)
        $itemName | hilight -pattern $from -plainColor "DarkGray" -color "White" -continuous
        $leftIndent = $shiftJIS.GetByteCount($_.Name)
        " {0}=> " -f ("=" * ($fill - $leftIndent)) | Write-Host -NoNewline -ForegroundColor Gray
        Write-Host $replacedName -ForegroundColor $color

        if ($execute) {
            try {
                $_ | Rename-Item -NewName $replacedName -ErrorAction Stop
            }
            catch {
                Write-Host ("ERROR: failed to rename '{0}'!" -f $itemName) -ForegroundColor Magenta
                if (Test-Path $replacedName) {
                    Write-Host "(same name exists in directory)" -ForegroundColor Magenta
                }
                else {
                    Write-Host "(other process may opening file)" -ForegroundColor Magenta
                }
            }
        }
    }
}
```

単純に文字列を置換するだけであればパラメータ指定ももう少し楽にできます。
`hilight` は [自作コマンドレット](https://qiita.com/AWtnb/items/954e32ed86f3663e777b) のエイリアスです。

## 挿入リネームを簡単に

![rins1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501098/d7ad0933-9d48-f007-e19b-1e8b5abebbea.png)
![rins2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501098/dbc7a533-5f3b-2599-b099-a3ec49f219ac.png)


```powershell
function Rename-Insert {
    param (
        [string]$insert,
        [int]$position = -1,
        [switch]$execute
    )
    if ($position -eq 0) {
        Write-Host "parameter '-position' do not accept 0!" -ForegroundColor Magenta
        return
    }

    $shiftJIS = [System.Text.Encoding]::GetEncoding("Shift_JIS")
    $procTarget = $input | Where-Object {$_.GetType().Name -in @("FileInfo", "DirectoryInfo")}

    if ($position -lt 0) {
        $longestBaseName = $procTarget.Basename | Sort-Object {$shiftJIS.GetByteCount($_)} -Descending | Select-Object -First 1
        $width = $shiftJIS.GetByteCount($longestBaseName)
    }

    if ($execute) {
        $color = "Green"
    }
    else {
        $color = "White"
    }

    $procTarget | ForEach-Object {
        $itemName = $_.Name
        try{
            if ($position -lt 0) {
                $pre  = ($_.Basename).substring(0, ($_.Basename).length + $position + 1)
                $post = ($_.Basename).substring(   ($_.Basename).length + $position + 1)
                $newName = $pre + $insert + $post + $_.Extension
                
                $fill = $width - $shiftJIS.GetByteCount($_.Basename) + 1
                Write-Host -NoNewline (" " * $fill)
                Write-Host $pre -NoNewline -ForegroundColor DarkGray
                Write-Host $insert -NoNewline -ForegroundColor $color
                Write-Host ($post + $_.Extension) -ForegroundColor DarkGray
            }
            else {
                $newName = ($itemName).Insert($position - 1, $insert)
                Write-Host ($itemName).substring(0, $position - 1) -NoNewline -ForegroundColor DarkGray
                Write-Host $insert -ForegroundColor $color -NoNewline
                Write-Host ($itemName).substring($position - 1) -ForegroundColor DarkGray
            }

            if ($execute) {
                $_ | Rename-Item -NewName $newName -ErrorAction Stop
            }
        }
        catch {
            Write-Host ("ERROR: failed to insert '{0}' to position {1} of '{2}'." -f $insert, $position, $itemName) -ForegroundColor Magenta
        }
    }
}
```

プレビューで末尾に挿入する場合に右揃えになるように工夫してみました。