Reputation: 11
I have a folder containing video files. I need to create a folder for each file, where the folder name is the same as the file (minus file extension) and move that specific file into it's associated folder.
The end result should eliminate all files in the root, and each folder should contain a single file.
Example folder should start out looking like this:
c:\videos\video1.avi
c:\videos\video2.mov
c:\videos\video3.mkv
And then look like this:
c:\videos\video1\video1.avi
c:\videos\video2\video2.mov
c:\videos\video3\video3.mkv
Everything works except the last step of moving the files into their associated folders.
In this 2nd ForEach
I try to specify the destination path using the $basename
variable used in the first loop. This doesn't work as it results in moving all the files into a single folder, which is the last object passed to the $basename
variable from the 1st Foreach loop.
foreach ($filename in $VideoFiles) {
Move-Item -Path \\server1\Video\Staging\$filename -Destination \\server1\Video\Staging\$basename -verbose
}
This kind of makes sense but with my limited knowledge and experience I can't figure out another way to accomplish my goal. I started to look into nesting ForEach loops but I am guessing there is an easier way to accomplish this.
I tried the following command in the 2nd loop
Move-Item -Path \\server1\Video\Staging\$filename -Destination \\server1\Video\Staging\$filename -verbose
But of course, that variable is storing the file name (including extension) and did not move any files.
Any help will be greatly appreciated..!
Get-ChildItem -Path \\server1\video\staging | ForEach-Object {$_.basename} | Out-File \\server1\video\videonames.txt
$VideoNames = Get-Content \\server1\video\videonames.txt
Get-ChildItem -Path \\server1\video\staging | ForEach-Object {$_.name} | Out-File \\server1\video\videosfiles.txt
$VideoFiles = Get-Content \\server1\video\videosfiles.txt
foreach ($BaseName in $VideoNames) {
New-Item -ItemType Directory -Path \\server1\Video\Staging\$BaseName
}
foreach ($filename in $VideoFiles) {
Move-Item -Path \\server1\Video\Staging\$filename -Destination \\server1\Video\Staging\$basename -verbose
}
Upvotes: 1
Views: 1328
Reputation: 61028
I would simplify this a bit further and in the process eliminate the risk of creating wrong path names by using the Join-Path
cmdlet like this:
$Source = '\\server1\Video\Staging'
(Get-ChildItem -Path $Source -File) | ForEach-Object {
$destination = Join-Path -Path $Source -ChildPath $_.BaseName
if(!(Test-Path $destination)){
New-Item -ItemType Directory -Path $destination | Out-Null
}
$_ | Move-Item -Destination $destination
}
Upvotes: 1
Reputation: 13217
Your answer is good, but there's no need to create a file with property names in.
You can just select the BaseName
property inside the loop, meaning you only need a single foreach
:
$Source = '\\server1\Video\Staging'
foreach ($File in Get-ChildItem -Path $Source) {
$FileBaseName = $File.BaseName
if(!(Test-Path $Source\$FileBaseName)){
New-Item -ItemType Directory -Path $Source\$FileBaseName -WhatIf
}
Move-Item -Path $Source\$FileBaseName.* -Destination $Source\$FileBaseName -WhatIf
}
Note: Remove -WhatIf
when you want the code to perform the actions
Upvotes: 1
Reputation: 11
This is probably not the best way to do this but it works exactly how I need it to. I was too focused on using the exact file name, including .ext when file name and wildcard met the requirements.
#Creates a text file list of the file names and defines a variable for it.
Get-ChildItem -Path \\server1\video\staging | ForEach-Object {$_.basename} | Out-File \\server1\video\videonames.txt
$VideoNames = Get-Content \\server1\video\videonames.txt
#Creates the folder structure based on file names
$Folder = foreach ($BaseName in $VideoNames){
New-Item -ItemType Directory -Path \\server1\Video\Staging\$BaseName
}
#Moves each file in the folder with the same name.
foreach ($File in $VideoNames){
Move-Item -Path \\server1\Video\Staging\$file.* -Destination \\server1\Video\Staging\$file -verbose
}
Upvotes: 0