0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ファイル名先頭にフォルダ名追加して移動.ps1

Last updated at Posted at 2025-07-20

1. スクリプト概要

スクリプト名: ファイル名先頭にフォルダ名追加して移動.ps1
サブフォルダ内のファイルをサブフォルダ名をつけた名前に変更しつつ移動することで、ファイルを一つのフォルダにまとめます

2. 処理と目的

処理の流れ
 1. スクリプトの引数にフォルダが指定された場合、それを対象フォルダとします
 2. スクリプトの引数にフォルダが未指定の場合、対象フォルダをフルパスで指定します
 3. 指定されたフォルダのサブフォルダに含まれるファイルをすべて取得します
 4. 元のファイル名と「サブフォルダ名_ファイル名」の形式のグリッドで表示し、処理対象のファイルを選択できるようにします
 5. 手順4で選択したファイル名を変更し、手順1または2で指定したフォルダに移動します
 6. 指定されたフォルダ内の空のサブフォルダをすべて削除します

目的
 サブフォルダにファイルが一つだけ配置されているような状況におけるファイル整理を効率化します

3. 動作環境と要件

PowerShellのバージョン
7.0以上

OS
Windows10

必要なモジュール
特になし

必要な権限
特になし

その他の設定
特になし

4. 使用方法

基本的な実行方法
スクリプトコードを拡張子ps1で保存してPowershellで実行してください。
ファイルを保存する際は、文字コードをUTF8 BOM付にしてください。

パラメータ
なし

使用例

  1. コマンドラインでpwsh ファイル名先頭にフォルダ名追加して移動.ps1を実行
  2. 「検索対象フォルダ」の入力を求められたら、フォルダのフルパスを入力します
  3. ファイル選択グリッドが表示されるので、変更対象のファイルを選択して「OK」ボタンを押下します

5. スクリプトコード

# PowerShell 7.0以上で、pwshまたはpowershell以外のプロセスから実行された場合に画面をクリア
if ($PSVersionTable.PSVersion.Major -ge 7 -and ((ps -Id $PID | ?{$_.Parent.ProcessName -notin @('pwsh','powershell')}) -ne $null)) {
    cls
}

$host.UI.RawUI.WindowTitle = ([IO.Path]::GetFilenameWithoutExtension($PSCommandPath))
$ErrorActionPreference = 'Stop'

# スクリプトの目的をコンソールに表示
echo "------------------------------------------------------------------"
Write-Host "対象フォルダ内のファイル名の先頭にフォルダ名を追加&移動して" -ForegroundColor White -BackGroundColor Black
Write-Host "対象フォルダ内の空の子フォルダを削除します" -ForegroundColor White -BackGroundColor Black
echo "------------------------------------------------------------------"


echo $args

# 引数にフォルダが指定されているか、かつそのパスが存在するかを確認
if ($args -and ($args.Length -ge 1) -and $args[0] -and (Test-Path -literal $args[0].Trim('"').Trim('\'))) {
    # 引数から対象フォルダを取得し、引用符と末尾の円マークを削除
    $taishoDir = $args[0].Trim('"').Trim('\')
} else {
    # 引数が指定されていない場合、ユーザーにフォルダの入力を促す
    do {
        $taishoDir = Read-Host "検索対象フォルダ"
        $taishoDir = $taishoDir.Trim('"').Trim('\')
    } while (-not ([IO.Directory]::Exists($taishoDir))) # フォルダが存在するまで入力を繰り返す
}

# 検索中であることをプログレスバーで表示
Write-Progress -Activity "Searching..." -Status $taishoDir
# 対象フォルダに移動(相対パスでの処理に備える)
cd -literal $taishoDir

# 対象フォルダのサブフォルダ内のファイルをすべて取得(対象フォルダ直下のファイルは除く)
$filelist = ls -LiteralPath $taishoDir -File -Recurse | ?{$_.DirectoryName -ne $taishoDir}
$fileCount = ($filelist|Measure).count
# プログレスバーを完了状態にする
Write-Progress -Activity "Searching..." -Completed
Write-Host "対象ファイル数:$($fileCount)個" -ForegroundColor Cyan

# --- ファイル名変更のためのデータ準備 ---
$paramList = @() # 処理対象のファイル情報を格納するリスト

# 取得したファイルごとにループ処理
foreach ($filedata in $filelist) {

    $baseDir = $taishoDir # 基点となる対象フォルダ

    # ファイルの親ディレクトリ名から対象フォルダのパスを除去し、円マークをアンダースコアに変換、先頭のアンダースコアを削除
    $dirName = $filedata.DirectoryName.replace($baseDir,'').replace('\','_').trimStart('_')

    # 新しいファイル名を生成
    if ($filedata.Name.StartsWith($dirName)) {
        # すでにサブフォルダ名がファイル名の先頭に含まれている場合、ファイル名は変更しない
        $newname = $filedata.Name
    } else {
        # サブフォルダ名_ファイル名 を新しいファイル名とする
        $newname = $dirName + '_' + $filedata.basename + $filedata.Extension
    }
    $extensionName = $filedata.Extension

    # ファイルの元のフルパスと新しいファイル名をオブジェクトとして格納
    $paramdata = New-Object -TypeName PSObject
    Add-Member -InputObject $paramdata -MemberType NoteProperty -Name "oldFullname" -Value $filedata.fullname
    Add-Member -InputObject $paramdata -MemberType NoteProperty -Name "newname"      -Value $newname
    Add-Member -InputObject $paramdata -MemberType NoteProperty -Name "extension"      -Value $extensionName # 現在は未使用だが、保持
    $paramList += $paramdata

}

# ユーザーにグリッドビューで処理対象ファイルを選択させる
$selectdata = $paramList | Out-GridView -Title "修正対象のファイルを選択して下さい" -PassThru

# 選択されたファイルがある場合のみ処理を実行
if ($selectdata -ne $null) {
    
    # 選択されたファイルごとにループ処理
    foreach ($paramdata in $selectdata) {
        # rename "元のファイルパス" → "新しいファイル名" の形式でコンソールに表示
        @( @("rename ",'White'), @($paramdata.oldFullname,'Cyan'), @(" → ", 'White'), @($paramdata.newname,'Green')) | %{Write-Host $_[0] -ForegroundColor $_[1] -NoNewline};Write-Host ""

        # ファイルを新しい名前に変更し、対象フォルダ直下に移動
        move-Item -literal $paramdata.oldFullname -dest $paramdata.newname
    }

    # --- 空のサブフォルダの削除 ---
    # 対象フォルダ内のすべてのサブフォルダを、パスの長さが長い順(深い階層から)に取得
    $dics = ls -literal $taishoDir -Directory -Recurse | sort -Descending -Property {$_.Fullname.Length}

    # フォルダがある場合のみ処理を実行
    if ($dics -ne $null) {
        # 各サブフォルダをループ処理
        foreach ($dicdata in $dics) {
            # サブフォルダ内のファイルを強制的にすべて取得
            $dicfiles = ls -literal $dicdata.fullname -File -Recurse -Force
            # サブフォルダ内にファイルが存在しない場合(空の場合)
            if ($dicfiles -eq $null) {
                # rmdir "フォルダ名" の形式でコンソールに表示
                @( @("rmdir", 'Yellow'), @("「",'White'),@($dicdata.fullname,'Cyan'), @("」",'White') ) | %{Write-Host $_[0] -ForegroundColor $_[1] -NoNewline};Write-Host ""
                # 空のサブフォルダを削除
                rmdir -literal $dicdata.fullname
            }
        }
    }
}
pause

6. 注意事項と既知の問題

制約事項
大量のファイルを処理する場合、完了までに時間がかかる可能性があります。

既知のバグ
もしバグを発見された場合は、コメントでご報告ください。

トラブルシューティング
・ps1ファイルのエンコーディングには注意してください。

7. 免責事項

本スクリプトにはいかなる保証もありません。使用は自己責任で行ってください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?