Search code examples
powershellscriptingrenamefile-handling

Removing parts of filenames in Powershell from a file list


I have a bunch of directories with files in them and my goal is to loop through a directory structure and write each of the files one by one to a new location. The files on disk look like this:

    - DATAFILE1_DATE_20210101_RUNDATE_20210101.csv
    - DATAFILE1_DATE_20210102_RUNDATE_20210102.csv
    - DATEFILE2_DATE_20210103_RUNDATE_20210103.json
    - DATEFILE2_DATE_20210104_RUNDATE_20210104.json

I'm trying to pass the contents of the directory to a variable $fileSystemItems and then to remove everything after _DATE so that I could build a new directory structure in the target as:

    - /target/DATAFILE1/DATAFILE1_DATE_20210101_RUNDATE_20210101.csv
    - /target/DATAFILE1/DATAFILE1_DATE_20210102_RUNDATE_20210102.csv
    - /target/DATAFILE2/DATEFILE2_DATE_20210103_RUNDATE_20210103.json
    - /target/DATAFILE2/DATEFILE2_DATE_20210104_RUNDATE_20210104.json

The PS code I have so far takes the files from a specified directory and outputs them:

    $sourcePath = "\\files\data"
    $fileSystemItems = Get-ChildItem $sourcePath -Recurse | Where { ! $_.PSIsContainer }

    foreach ($file in $fileSystemItems) {
    Write-Host "Writing name of the file is $($file.BaseName)"
    }

I have tried using the Rename-Item and regex but renaming the files the source is not an option as other programs are accessing the same data, for example:

    Get-ChildItem $sourcePath -Recurse | Rename-Item -NewName { $_.Name -replace "^_DATE+","" }

How do I modify the filename in the $file variable in the foreach loop to output both a edited version of the file name (e.g. DATEFILE1) and also the full file name DATAFILE1_DATE_20210101_RUNDATE_20210101.csv ?


Solution

  • Rename-Item is a great tool to begin with! First, let's optimize your code snippet a little bit:

    Instead of piping Get-ChildItems output to Where { ! $_.PSIsContainer }, we'll use the -File switch.

    Let's also change your regex from ^_DATE+ to _DATE.* and use a pipeline with ForEach-Object:

    Get-ChildItem $sourcePath -Recurse -File | ForEach-Object {
        Rename-Item -Path $_.Fullname -NewName (($_.Name -replace "_DATE.*","") + $_.Extension)
    }
    

    Looking at your destination structure it looks like you might also want to move files to a target directory.