Move-Item moves entire source directory instead of specified files - powershell

In PowerShell, I'm trying to use Move-Item to move all files containing the string "2017", located in $Source, to $MovieDst
The files that I want to move in $Source are individual .mkv files with the string "2017" in the filename, located at the root of $Source - they are not in a directory.
If I hash out Move-Item and un-hash Write-Host $NoDirMovie, it outputs the following:
ExampleFile.2017.mkv
ExampleFile2.2017.mkv
So, it definitely knows which are the correct files to be referencing. But as soon as I use Move-Item, it moves the entire $source directory into $MovieDst. I can't use -Exclude *COMPLETED_DOWNLOADS* as it includes the very files that I want to move.
So, I'm a bit stuck - It can't move my files, because it FIRST wants to move the entire directory containing them. Is there a way to stop it from moving the entire $Source directory, and JUST move only the contents of $Source that contain the string "2017" ?
$Source = "C:\TV Shows 7\COMPLETED_DOWNLOADS"
$MovieDst = "C:\TV Shows 7\COMPLETED DOWNLOADS_Sorted\MOVIES"
$NoDirMovies = dir $Source *2017*
foreach($NoDirMovie in $NoDirMovies | where {$_ -ne $Source})
{
Move-Item -Path $Source -Destination $MovieDst
#Write-Host $NoDirMovie
}

Why are you storing the files you want in $NoDirMovie, then passing $Source to Move-item?
Surely you want:
foreach($NoDirMovie in $NoDirMovies | where {$_ -ne $Source})
{
Move-Item -Path $NoDirMovie -Destination $MovieDst
#Write-Host $NoDirMovie
}
Edit
That's a simple fix, which I haven't tried. A few things:
dir is an alias for the built-in PowerShell Cmdlet Get-ChildItem
Your loop Where is illogical. $NoDirMovies are files in directory $Source, so they will never equal $Source (assume this was an attempt to not copy directory?)
Worth checking if the directory you are trying to copy to exists.
V2 (I tried this one)
$Source = "C:\TV Shows 7\COMPLETED_DOWNLOADS"
$MovieDst = "C:\TV Shows 7\COMPLETED DOWNLOADS_Sorted\MOVIES"
$filter = "2017"
If(!(Test-Path $MovieDst)){
New-Item -ItemType Directory -Path $MovieDst
}
foreach($file in (Get-ChildItem $Source | Where-object {$_.Name -match $filter})){
Move-Item -Path $file.FullName -Destination $MovieDst
}

IMHO your approach is overcomplicated. Move-Item accepts piped input, so
$Source = "C:\TV Shows 7\COMPLETED_DOWNLOADS"
$MovieDst = "C:\TV Shows 7\COMPLETED DOWNLOADS_Sorted\MOVIES\"
Get-ChildItem -Path $Source -Filter "*2017*.mkv" |Where {!($_.PSIsContainer)}
Move-Item -Destination $MovieDst -WhatIf
If the outpout looks OK, remove the -WhatIf

Related

How to move items excluding certain folder using PowerShell?

The question is an oversimplification of the real issue.
I have a folder let's call it "ParentFolder". Within this folder are files and subfolders. I want all the files and subfolders moved from the "ParentFolder" except one specific subfolder, let's call it "SpecificChildFolder". For the "SpecificChildFolder" I don't want the folder to be moved but only the files in it.
I can do these two tasks separately. I can either move all the files and folders(including the "SpecificChildFolder) in the "ParentFolder" or I can move files from the "SpecificChildFolder" only (excluding the rest of the files and subfolders in the "ParentFolder").
I want these two tasks to happen simultaneously.
I thought I would accomplish this in two separate functions:
Move everything except "SpecificChildFolder"
Move files from within the "SpecificChildFolder"
The stage# 2 code works. It is Stage# 1 I have issues with.
I have also tried Get-ChildItem $src -ErrorAction SilentlyContinue | Where-Object {$_.Directory.Name -NotLike "*SpecificChildFolder*"} | ForEach-Object{} but this doesn't work either
Secondly, can this is not happen in one line of PowerShell?
I am using PowerShell Core 7.2
Code for Stage 1:
#Sources
$src = "C:\User\Desktop\TEST\ParentFolder\*"
$srcMcaNameChg = "C:\User\Desktop\TEST\ParentFolder"
#Destination
$dest = "C:\Users\harguls\Desktop\TEST\DestinationFolder"
Function MoveFiles{
Param(
[string]$src,
[string]$dest,
[string]$srcNameChange
)
Get-ChildItem $src -Recurse -Exclude 'SpecificChildFolder' -ErrorAction SilentlyContinue | ForEach-Object{
$fileName = $_.Name
# Check for duplicate files
$file = Test-Path -Path $dest\$fileName
Write-Output $file
if($file)
{
"$srcNameChange\$fileName" | Rename-Item -NewName ("Copy_"+$fileName)
}
}
Move-Item -Path $src -Destination $dest -Force
}
MoveFiles -src $src -dest $dest -srcNameChange $srcMcaNameChg
Here is a vague representation of what it seems you're looking to accomplish, hope the inline comments are explanatory.
$source = '\path\to\source\folder'
$destination = '\path\to\destination\folder'
# you can add multiple folders here if you want
$exceptWith = 'foldertoexclude1', 'foldertoexclude2'
# get only the subfolders of `$source` and iterate over them
Get-ChildItem $source -Directory | ForEach-Object {
# if this folder name is in the folders to exclude array
if($_.Name -in $exceptWith) {
# get only the files of this folder and move them to destination
Get-ChildItem $exclude -File | Move-Item -Destination $destination
# if we're here we can proceed with next subfolder
return
}
# if we're here means that the name of the folder was not in `$exceptWith`
# so we move this folder and all it's child folders / files
Move-Item -LiteralPath $_.FullName -Destination $destination -Recurse
}

Moving Files based on filename

Im looking to move files based on the last half of the filename. Files look like this
43145123_Stuff.zip
14353135_Stuff.zip
2t53542y_Stuff.zip
422yg3hh_things.zip
I am only looking to move files that end in Stuff.zip
I have this in PowerShell so far but it only will move files according to the first half of a file name.
#set Source and Destination folder location
$srcpath = "C:\Powershelltest\Source"
$dstpath = "C:\Powershelltest\Destination"
#Set the files name which need to move to destination folder
$filterLists = #("stuff.txt","things")
#Get all the child file list with source folder
$fileList = Get-ChildItem -Path $srcpath -Force -Recurse
#loop the source folder files to find the match
foreach ($file in $fileList)
{
#checking the match with filterlist
foreach($filelist in $filterLists)
{
#$key = $file.BaseName.Substring(0,8)
#Spliting value before "-" for matching with filterlists value
$splitFileName = $file.BaseName.Substring(0, $file.BaseName.IndexOf('-'))
if ($splitFileName -in $filelist)
{
$fileName = $file.Name
Move-Item -Path $($file.FullName) -Destination $dstpath
}
}
}
There seems to be some differences between the state goal and what the code actually does. This will move the files to the destination directory. When you are confident that the files will be moved correctly, remove the -WhatIf from the Move-Item command.
$srcpath = "C:\Powershelltest\Source"
$dstpath = "C:\Powershelltest\Destination"
Get-ChildItem -File -Recurse -Path $srcpath |
ForEach-Object {
if ($_.Name -match '.*Stuff.zip$') {
Move-Item -Path $_.FullName -Destination $dstpath -WhatIf
}
}
Actually this can be written in PowerShell very efficiently (I hope I got the details right, let me know):
Get-ChildItem $srcpath -File -Force -Recurse |
where { ($_.Name -split "_" | select -last 1) -in $filterLists } |
Move-Item $dstpath
Alternatively, if you only want to look for this one particular filter, you can specify that directly, using wildcards:
Get-ChildItem $srcpath -Filter "*_Stuff.zip"

ForEach-Object to look in subfolders

I Have this powershell script “copFiles.ps1” that looks in a txt file "Filestocopy.txt" for a list and copies them to a destination
$source = "C:\Data\Filestocopy.txt"
$destination = "C:\Data\Models"
Get-Content $source | ForEach-Object {copy-item $_ $destination}
It’ll only copy the files if they’re in the same folder as the .ps1 file and it ignores subfolders, how can I get it to look in subfolders of the folder that its in, I gather I need to use the -recurse option but don’t know how to rewrite it so it works.
The .ps1 file is fired by a bat file.
Many thanks
I don't know how fast this will be, but you can give an array as the argument for the -Path parameter of Get-ChildItem add the -Recurse switch to dig out the files in subdirectories and simply pipe them along to Copy-Item. something like:
Get-ChildItem (Get-Content $Source) -Recurse |
Copy-Item -Destination $destination
You may also want to add the -File switch.
Update
Based on your comment I played around with this a a little more:
$source = "C:\Data\Filestocopy.txt"
$Destination = "C:\data\Models"
# Get-ChildItem (Get-Content $Source) -Recurse |
Get-ChildItem (Get-Content $Source) -Recurse -File |
ForEach-Object{
If( $_.Directory.FullName -eq $Destination )
{ # Don't work on files already present in the destination
# when the destination is under the current directory...
Continue
}
$FileNum = $null
$NewName = Join-Path -Path $Destination -ChildPath $_.Name
While( (Test-Path $NewName) )
{
++$FileNum
$NewName = Join-Path -Path $Destination -ChildPath ($_.BaseName + "_" + $FileNum + $_.Extension)
}
Copy-Item $_.FullName -Destination $NewName
}
This will increment the destination file name in cases where a file by that name already exists in the destination. If the destination is under the current directory it will prevent analyzing those files by comparing the path of the file to the destination. Files must have unique names in a given folder so I'm not sure how else it can be handled.

Need to copy single file to all subfolders recursively

Please can someone help me create a powershell or CMD script, as simple as possible (1 line?) that will do the following...
-Take file (c:\test.txt)
-Copy to ALL subfolders within a given folder, including multiple levels deep
eg, c:\test1\1\2\3\ and c:\test2\6\7\8\
-Without overwriting that file if it already exists
-Not changing ANY existing files. Just adding the original txt file if it doesn't exist.
I've tried a bunch of scripts I found online, changing them, but have been unsuccessful. Either it overwrites existing files, or doesn't go multiple levels deep, or skips all the folders between top/bottom levels, or throws errors. I give up.
Thanks
Matt
How about something like this...
$folders = Get-ChildItem -Recurse -Path C:\temp\1 -Directory
$file = "c:\temp\test.txt"
foreach($folder in $folders){
$checkFile = $folder.FullName + "\test.txt"
$testForFile=Test-Path -Path $checkFile
if(!$testForFile){
Copy-Item $file -Destination $folder.FullName
}
}
Not a one-liner, but here you go:
$rootFolder = 'PATH OF FOLDER CONTAINING ALL THE SUBFOLDERS'
$fileToCopy = 'c:\test.txt'
$fileName = [System.IO.Path]::GetFileName($fileToCopy)
Get-ChildItem -Path $rootFolder -Recurse -Directory | ForEach-Object {
if (!(Test-Path -Path (Join-Path -Path $_.FullName -ChildPath $fileName) -PathType Leaf)) {
Copy-Item -Path $fileToCopy -Destination $_.FullName
}
}

Copying Files to Another Folder While Keeping a Single Parent Directory

I'm still new to PowerShell and I'm trying to do something I haven't seen an exact answer for yet. We have one large folder with many subfolders that contain individual audio files (our phone system records and places audio files in folders by date). I want to get certain files from within those folders and move them to a different folder, but I want to create the parent folder that the files came from in the new location. I am not grabbing all files within the folders, only a few. For example:
I want to move a file at C:\CopyFrom\02182019\AudioFile.wav
I have a folder at C:\CopyTo, but I want the destination to be C:\CopyTo\02182019\AudioFile.wav
I want the script to create the folder if it doesn't exist, but copy the files into the folder if it does.
I'm currently using Get-ChildItem -Include to get the files I need and piping it into a foreach loop that I found online. This is as close as I've gotten to what I need, but it copies the ENTIRE folder structure, starting at the root, so my destination ends up being:
C:\CopyTo\CopyFrom\02182019\AudioFile.wav
Here is what I have so far:
Get-ChildItem $SourceFolder -Include $ExtArray -Recurse | forEach {
## Remove the original root folder
$split = $_.Fullname -split '\\'
$DestFile = $split[1..($split.Length - 1)] -join '\'
## Build the new destination file path
$DestFile = "C:\DestinationFolder\$DestFile"
## Copy-Item won't create the folder structure so we have to
## create a blank file and then overwrite it
$null = New-Item -Path $DestFile -Type File -Force
Copy-Item -Path $_.FullName -Destination $DestFile -Force
}
I found the foreach loop in this article. I'm assuming there is more I can add to the $split line that will allow me to shave off the rest of the directory structure, but I'm still pretty new to this and don't understand the syntax well enough.
I know this is kind of convoluted to explain, so please let me know if any clarification is needed.
Try this:
$ExtArray = "keep"
$SourceFolder = "C:\source"
$DestFolder = "C:\dest"
Get-ChildItem $SourceFolder -Recurse -Include "*keep*" | foreach {
$source_dir = $_.DirectoryName
$dest_dir = $_.DirectoryName.replace($SourceFolder, $DestFolder)
if (Test-Path $dest_dir) {
Copy-Item -Path $_ -Destination $dest_dir -Recurse
} else {
New-Item -Path $dest_dir -ItemType "directory" | out-null
Copy-Item -Path $_ -Destination $dest_dir -Recurse
}
}
Here's my attempt at this - I set the top level directory as one variable and the underlying folder structure as another.
$File = "C:\test\IT\testfile.docx"
$Destination = "C:\test2\"
$test2 = "\IT\"
mkdir "$Destination\$test2"
Copy-Item -Path $File -Destination "$Destination\$test2" -recurse
I'm not sure how to implement this into your current code but hopefully it gets the wheels spinning and sends you in the right direction!