I'm trying to sort my files into unique dictionaries based on the file name and delimiters.
File names follow this structure: LocationName-DP-Category-S-L
Where... - is the delimiter
- Location name is a variable length, never has spaces
- DP is the two-letter department code
- Category is a variable length, never has spaces
- S is a single-letter size code
- L is length
Everything after category is irrelevant, as there is often some extra garble at the end of the filename to ignore.
I'd like to have a folder structure created and sorted for every found variation of just the LocationName-DP-Category portion of the filepath that looks something like this:
- Parent Folder: LocationName
- SubFolder: DP
- SubSubFolder: Category
Trying to keep it less rigid as this runs often on various batches of files. Here's what I have:
##GET USER INPUT FROM DIALOG
Add-Type -AssemblyName System.Windows.Forms
$browser = New-Object System.Windows.Forms.FolderBrowserDialog
$null = $browser.ShowDialog()
$path = $browser.SelectedPath "\"
##SORT ALL FILES
Get-ChildItem -Path $path *-*-*-*-*.* |
Where-Object BaseName -match '(?<store>\w )\- (?<dept>\w )\- (?<category>\w )*.*'|
Group-Object {$Matches["store"] '-' $Matches["dept"] '-' $Matches["Category"]}|
ForEach-Object{mkdir $_.Name;$_.Group|Move-Item -Dest $_.Name}
Would really appreciate the help, been scratching my head on and off for a couple months.
Thanks
CodePudding user response:
...initially I also thought about group-object but I think that is not necessary, this is simpler:
#Get Source Files
$files = get-childitem -Path [path]
#Set target root path
$targetPathRoot = "C:\tmp\"
#Loop through array of files
foreach ($file in $files){
#Split the filename
$split = $file.name -split "-"
#Build the target path
$newFullPath = $targetPathRoot $split[0] '\' $split[1] '\' $split[2]
#If path exists move item, otherwise create path and move item
If (Test-Path $newFullPath){
$null = move-item -Path $file.psPath -Destination $newFullPath
}
Else {
$null = new-item -ItemType Directory -Path $newFullPath -Force
$null = move-item -Path $file.psPath -Destination $newFullPath
}
}
CodePudding user response:
Assuming none of the parts 'LocationName', 'DP' or 'Category' contain a hyphen, you could create the new path for the file like this:
# 'LocationName-DP-Category-S-L-blah.ext' --> LocationName\DP\Category
$_.BaseName -replace '^(\w -\w{2}-\w ).*', '$1' -replace '-', '\'
Your code can then become
Add-Type -AssemblyName System.Windows.Forms
$browser = New-Object System.Windows.Forms.FolderBrowserDialog
$null = $browser.ShowDialog()
$path = $browser.SelectedPath
$browser.Dispose() # remove from memory when done
# the root path for the (new) subfolders and files
$destination = 'X:\SomeWhere'
if (![string]::IsNullOrWhiteSpace($path)) {
Get-ChildItem -Path $path -Filter '*-*-*-*-*.*' -File | ForEach-Object {
$subPath = $_.BaseName -replace '^(\w -\w{2}-\w ).*', '$1' -replace '-', '\'
$targetDir = Join-Path -Path $destination -ChildPath $subPath
# create the new path if it does not already exist
$null = New-Item -Path $targetDir -ItemType Directory -Force
# move the file
$_ | Move-Item -Destination $targetDir
}
}
else {
Write-Host "Folder dialog cancelled"
}
Note: On the File System, the New-Item -Path $targetDir -ItemType Directory -Force
will either create the new folder, OR return a reference to an existing folder. The -Force
switch in this case allows you not to have to use Test-Path
in this case.
Mind you, you should NOT use that technique when dealing with other systems like on registry keys for instance