Create multiple directories in different folders - powershell

I want to create one folder for each preselected *.mkv-file in the corresponding subfolder, named after that *.mkv-file, e.g.:
Z:\1\1.mkv; Z:\2\2.mp4; Z:\3\3.mkv --> Z:\1\1 (additional folder);
Z:\1\1.mkv; Z:\2\2.mp4; Z:\3\3 (additional folder); Z:\3\3.mkv
$inputfiles = gci *.mkv -recurse
foreach ($file in $inputfiles)
{
new-item -path Z:\* -name "$($file.BaseName)" -itemtype directory
}
Problem here is, that in each subfolder all of the directories are created, not just the corresponding one.
I also tried -path $inputfiles but got an error message.
Any help is appreciated

The main problem is that you have added \* after the path for the New-Item.
Try:
Get-ChildItem -Filter '*.mkv' -File -Recurse | ForEach-Object {
# construct the path for the (new) subfolder
$targetFolder = Join-Path -Path 'Z:\' -ChildPath $_.BaseName
# create a new directory if not already existed
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# if you want the .mkv file to be moved to that new directory, uncomment the line below
# $_ | Move-Item -Destination $targetFolder
}
The -Force switch on the New-Item line ensures it either creates a new directory or returns the folder object of an existing one without error messages.

Related

Powershell: Moving named files to their corresponding folder

enter image description hereI have a folder which has a bunch of files named: WBF123456, WBF135464, etc. These files need to be moved to the corresponding folder. At the moment I am using the commandline to manually enter the numbers of each file so they get moved, using this code:
$files = $args[0]
mv O:\SCAN\SecSur\*$files.pdf O:\SPG\G*\*\*$files
How can I automate this process?
It needs to identify the number in the filename, then move it to the folder containing the same number.
Any help would be great. Thanks.
I need to get the files on the left, inside the corresponding folders on the right.
Maybe the below solution will help you. You should change $origin_path and $destination_path
$origin_path= "C:\Users\geralexgr\Desktop\kati\files"
$destination_path = "C:\Users\geralexgr\Desktop\kati\folders"
Get-ChildItem $origin_path -Recurse -Include *.txt | ForEach-Object {
$folder = [regex]::Matches($_.Name, "\d+(?!.*\d+)").value
Move-Item $_.FullName $destination_path\$folder
}
The example will place files under the folders that match the numeric regex.
After powershell execution file WBF12 gets inside 12 folder
Apparently the files to move are .pdf files, so what you can do is get a list of those files in the source folder and then loop over that list to create (if needed) the destination subfolder and move the file there.
Try:
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# create the target path for the file
$targetFolder = Join-Path -Path $destinationRoot -ChildPath $numName
# create that subfolder if it does not already exist
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# now, move the file
$file | Move-Item -Destination $targetFolder
}
Seeing your screenshots, this might be a better approach for you.
$destinationRoot = 'O:\SPG\G\SomeWhere' # enter the root folder destination path here
# get a list of target folders for the files to be moved to and create a lookupHashtable from their names
$targets = #{}
Get-ChildItem -Path $destinationRoot -Directory | Where-Object {$_.Name -match '(\d+)'} | ForEach-Object {
$targets[$matches[1]] = $_.FullName # key is the number, value is the directory fullname
}
# get a list of files to move
$filesToMove = Get-ChildItem -Path 'O:\SCAN\SecSur' -Filter '*.pdf' -File | Where-Object {$_.Name -match '\d+'}
foreach ($file in $filesToMove) {
$numName = $file.BaseName -replace '\D+' # leaving only the numbers
# see if we have a target folder with that same number in its name
if ($targets.ContainsKey($numName)) {
$targetFolder = $targets[$numName]
Write-Host "Moving file $($file.Name) to $targetFolder"
$file | Move-Item -Destination $targetFolder
}
else {
Write-Warning "Could not find a destination folder for file $($file.Name).."
}
}

Powershell: Copy files to another folder by appending filenames as parent folder

I am trying to copy a bunch of files from a folder to another remote folder by renaming the files as the source folder name. The script I wrote works, but it is creating folders by appending the folder name as the parent, instead of copying the actual files itself.
$source = 'C:\Users\testserver\Desktop\WSVC1'
$destination = 'C:\Users\testserver\Documents\Powershell test'
$files = Get-ChildItem -File $source -Filter *.txt -Recurse -Force
foreach ($file in $files) {
$newPath = Join-Path -Path $destination -ChildPath $file-$(Split-Path -Path $source -Leaf)
Copy-Item -Path $source -Destination $newPath
}

PowerShell script to copy jpg files from one folder to another by creating two subfolders with the same name

I am in need of some assistance, I am new to PowerShell and am trying to use it to make some of my work easier. I am writing a PowerShell script to copy JPG files from one location (C:\Pictures\People\People) and moving them to a new location.
The issue is that in this new location I need to create a folder with the same name as the JPG and then another subfolder with the same name again as the JPG.
So I need to move images from C:\Pictures\People\People which I will call JPG_Image to C:\Pictures\JPG_Name\JPG_Name\'JPG_Image'
So far I found and have been working with this:
$SourceFolder = "C:\Pictures\People\People"
$TargetFolder = "C:\Pictures\"
# Find all files matching *.JPG in the folder specified
Get-ChildItem -Path $SourceFolder -Filter *.jpg |
ForEach-Object {
$ChildPath = Join-Path -Path $_.Name.Replace('.jpg','') -ChildPath $_.Name
[System.IO.FileInfo]$Destination = Join-Path -Path $TargetFolder -ChildPath $ChildPath
# Create the directory if it doesn't already exits
if( -not ( Test-Path -Path $Destination.Directory.FullName ) ){
New-Item -ItemType Directory -Path $Destination.Directory.FullName
}
Copy-Item -Path $_.FullName -Destination $Destination.FullName
}
You are making this harder on yourself than needs be.
Some enhancements to your code:
Add switch -File to the Get-ChildItem cmd so you do not also get DirectoryInfo objects
To get the filename without extension, there is a property .BaseName
Join-Path returns a string, no need to cast that into a [System.IO.FileInfo] object
If you add -Force to the New-Item cmd, there is no need to check if a folder already exists, because that will make the cmdlet either create a new folder or return the existing DirectoryInfo object.
Because we don't need that object (and the console output from it), we can just throw that away using $null = New-Item ...
Putting it all together:
$SourceFolder = "C:\Pictures\People\People"
$TargetFolder = "C:\Pictures"
# Find all files matching *.JPG in the folder specified
Get-ChildItem -Path $SourceFolder -Filter '*.jpg' -File |
ForEach-Object {
# Join-Path simply returns a string containing the combined path
# The BaseName property is the filename without extension
$ChildPath = Join-Path -Path $_.BaseName -ChildPath $_.BaseName
$Destination = Join-Path -Path $TargetFolder -ChildPath $ChildPath
# Create the directory if it doesn't already exits
# Using -Force will not give an error if the folder already exists
$null = New-Item -Path $Destination -ItemType Directory -Force
$_ | Copy-Item -Destination $Destination
}

Renaming/Copying file with complicated name requirements

I have to create a script that searches for file, takes part of the folder name and move the file to a new location with that new name.
I am planning to use powershell for this but would be up willing to look for other options. This used for millions of files.
Example 1
sourcefolder\a\b\test_123456\example.txt -> \destinationfolder\example_123456.txt
Problem is I don't know how many folders deep the file is and the amount of folder name changes, I need everything after the last _
Example 2
sourcefolder\a\b\c\test_test_1234\example.txt -> \destinationfolder\example_1234.txt
I am researching how to script and will update question when I when I have some progress
FileInfo objects include many properties. One of these is the .Directory property which returns the directory (as DirectoryInfo object) that represents the parent folder the file is in. This Directory also has properties, like .Name.
You can use this like below:
$sourceFolder = 'D:\Test' # the root folder to search through
$destinationFolder = 'X:\Archive' # the destinationpath for the moved files
# make sure the destination folder exists
$null = New-Item -Path $destinationFolder -ItemType Directory -Force
# get a collection of FileInfo objects
# if you need more file extensions like both .txt and .log files, replace -Filter '*.txt' with -Include '*.txt', '*.log'
# this will be slower than using -Filter though..
$filesToMove = Get-ChildItem -Path $sourceFolder -File -Filter '*.txt' -Recurse | Where-Object {$_.Directory.Name -like '*_*'}
# using a foreach(..) is a bit faster than 'ForEach-Object'
foreach ($file in $filesToMove) {
# get the last part after '_' of the parent directory name
$suffix = ($file.Directory.Name -split '_')[-1]
# combine to create the new path and filename
$target = Join-Path -Path $destinationFolder -ChildPath ('{0}_{1}{2}' -f $file.BaseName, $suffix, $file.Extension)
$file | Move-Item -Destination $target -Force -WhatIf
}
Take off the WhatIf safety switch if you are satisfied what is displayed on screen about what would be moved is correct.
You don't even need the foreach loop because Move-Item can handle a scriptblock as parameter for the Destination like this:
$sourceFolder = 'D:\Test' # the root folder to search through
$destinationFolder = 'X:\Archive' # the destinationpath for the moved files
# make sure the destination folder exists
$null = New-Item -Path $destinationFolder -ItemType Directory -Force
# get a collection of FileInfo objects
# if you need more file extensions like both .txt and .log files, replace -Filter '*.txt' with -Include '*.txt', '*.log'
# this will be slower than using -Filter though..
$filesToMove = Get-ChildItem -Path $sourceFolder -File -Filter '*.log' -Recurse |
Where-Object {$_.Directory.Name -like '*_*'} |
Move-Item -Destination {
$suffix = ($_.Directory.Name -split '_')[-1]
Join-Path -Path $destinationFolder -ChildPath ('{0}_{1}{2}' -f $_.BaseName, $suffix, $_.Extension)
} -Force
Here, the $_ Automatic variable is used instead of a variable you define in a foreach loop.
P.S. If you only need files from subfolders with a name ending in _ followed by numbers only as opposed to names like sub_folder, change the Where-Object {...} clause in the code to
Where-Object {$_.Directory.Name -match '_\d+$'}

How to search for specific files recursively, create folder and move file to it?

How can I search for a specific file extension recursively through out the entire directory structure, for each file/extension found create a folder at the file location using each file's name, and move the file/s to its own folder (that matches the files name)?
Thank you #Alex_P: The following code creates only one folder, and moves ALL the files found into this folder. Is there a way to make it create a folder for each item and then move each item to its corresponding folder. Appreciate your help.
$_ = (Get-ChildItem -Path "C:\3\ML\300000-310000S\302355\OLn2" -Recurse -File | Where-Object { $_.Extension -eq '.MCX-5' })
ForEach-Object {
New-Item -Path $_[0].PSParentPath -Name $_[0].BaseName -ItemType Directory
$newpath = Join-Path -Path $_[0].PSParentPath -ChildPath $_[0].BaseName
Move-Item -Path $_.FullName -Destination $newpath -Force
}
Get-ChildItem returns System.IO.FileInfo objects. You can use their property 'Extension' to filter for file extensions.
This example will give you all PDF files:
$files = Get-ChildItem -Path .\Documents\ -Recurse -File | Where-Object { $_.Extension -eq '.pdf' }
In order to move the files you can use some other, useful properties of the object. .PSParentPath gives you the path up to the directory of your object. .BaseName gives you the file name, excluding the extension.
New-Item -Path $files[0].PSParentPath -Name $files[0].BaseName -ItemType Directory
Now, in order to move your item, you need to concatenate your path with your new directory and then you can move the item to your new directory. .Fullname gives you the full path of the object.
$newpath = Join-Path -Path $files[0].PSParentPath -ChildPath $files[0].BaseName
Move-Item -Path $files[0].FullName -Destination $newpath
In my case, I only moved one item but you need to add these to your foreach loop.