6

I have thousands of files like the following in a directory called D:\queries\

#TIM_DV_ORDERINQUERY.SQL
#TIM_QA_ORDERINQUERY.SQL
#TIM_P1_ORDERINQUERY.SQL
#JACK_DV_SALESQUERY.SQL
#JACK_P1_PRODUCTQUERY.SQL
#ERIK_P1_EMPLOYEE-NY.SQL
#ERIK_P1_EMPLOYEE-TX.SQL

: :

I need a script to move them to folders

G:\queries\#TIM\DV\ORDERINQUERY.SQL
G:\queries\#TIM\QA\ORDERINQUERY.SQL
G:\queries\#TIM\P1\ORDERINQUERY.SQL
G:\queries\#JACK\DV\SALESQUERY.SQL
G:\queries\#JACK\P1\PRODUCTQUERY.SQL
G:\queries\#ERIK\P1\EMPLOYEE-NY.SQL
G:\queries\#ERIK\P1\EMPLOYEE-TX.SQL

In other words the characters before the first _ are the sub-directories under G:\queries, the characters between the first and the second _ are sub-sub-directories and then the rest of the name is the file name.

I searched a lot on the web and I can't figure it out. I am new to powershell or any kind of scripting. Any help is appreciated.

3 Answers 3

6

This makes use of the FileInfo class, to get information pertaining to the directory.

$SourceFolder = "G:\queries\"
$targetFolder = "G:\queries\"

# Find all files matching *.sql in the folder specified
Get-ChildItem -Path $SourceFolder -Filter *.sql | ForEach-Object {

    # Combine the source filename and target directory
    # The source filename has all instances of _ replaced with \
    # Cast the resulting string to a FileInfo object to take advantage of extra methods
    [System.IO.FileInfo]$destination = (Join-Path -Path $targetFolder -ChildPath $_.Name.replace("_","\"))

    # Create the directory if it doesn't already exits
    if (!(Test-Path) $destination.Directory.FullName)
    { 
        New-item -Path $destination.Directory.FullName -ItemType Directory 
    }

    # Copy the source to the target directory
    copy-item -Path $_.FullName -Destination $Destination.FullName 
}
Sign up to request clarification or add additional context in comments.

4 Comments

David..it worked like a charm. However, it threw errors saying the directory already exists. Anyway to suppress that ?
David...just so that I can learn and understand the script. Will you be kind enough to explain the script ?
David...i was able to modify the script to handle the directory already exists warning: $SourceFolder = "D:\query\" $targetFolder = "G:\query\" Get-ChildItem -Path $SourceFolder -Filter *.TXT | %{ [System.IO.FileInfo]$destination = (Join-Path -Path $targetFolder -ChildPath $_.Name.replace("","\")) if(!(Test-Path -Path $destination.Directory )){ New-item -Path $destination.Directory.FullName -ItemType Directory } copy-item -Path $.FullName -Destination $Destination.FullName } once again thanks a lot for your help
@user3019391 I have added comments and updated with the test-path that you pointed out was required. I have also linked to FileInfo class so you can understand where the extra directory methods came from.
5

You'll probably want to use a regular expression for this. That will help to ensure that only files that match the specified pattern get moved, and you don't have any "accidents."

# 1. Get a list of files in the d:\queries folder
$FileList = Get-ChildItem -Path d:\queries;

# 2. Parse file names, create folder structure, and move files
foreach ($File in $FileList) {
    $File.Name -match '(?<folder>.*?)(?:_)(?<subfolder>\w{2})(?:_)(?<filename>.*)';
    if ($matches) {
        $Destination = 'd:\queries\{0}\{1}\{2}' -f $matches.folder, $matches.subfolder, $matches.filename;
        mkdir -Path (Split-Path -Path $Destination -Parent) -ErrorAction SilentlyContinue;
        Move-Item -Path $File.FullName -Destination $Destination -WhatIf;
    }
    $matches = $null
}

1 Comment

If another newbie like myself is reading this useful answer, here is a commented version explaining what I think the code is doing, in case it helps. Thanks to @devavret for reformatting it! gist.github.com/devavret/1ea5b32cdc759244125a2ccbd6e472d7
3

I modified David's version a bit and this works like I wanted. Thanks David for your help.

$SourceFolder = "D:\queries\"
$targetFolder = "G:\queries\"
$numFiles = (Get-ChildItem -Path $SourceFolder -Filter *.TXT).Count
$i=0

clear-host;
Write-Host 'This script will copy ' $numFiles ' files from ' $SourceFolder ' to ' $targetFolder
Read-host -prompt 'Press enter to start copying the files'

Get-ChildItem -Path $SourceFolder -Filter *.TXT | %{ 
    [System.IO.FileInfo]$destination = (Join-Path -Path $targetFolder -ChildPath $_.Name.replace("_","\"))

   if(!(Test-Path -Path $destination.Directory )){
    New-item -Path $destination.Directory.FullName -ItemType Directory 
    }
    [int]$percent = $i / $numFiles * 100

    copy-item -Path $_.FullName -Destination $Destination.FullName
    Write-Progress -Activity "Copying ... ($percent %)" -status $_  -PercentComplete $percent -verbose
    $i++
}
Write-Host 'Total number of files read from directory '$SourceFolder ' is ' $numFiles
Write-Host 'Total number of files that was copied to '$targetFolder ' is ' $i
Read-host -prompt "Press enter to complete..."
clear-host;

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.