Powershell - Move files 1 folder deeper - powershell

I'm looking to move a large set of pdf files one folder deeper.
The current file structure is:
[Reference Code]\[file].pdf
and i'm looking to move the files to:
[Reference Code]\April 18\[file].pdf
if i recall correctly this could be done in linux with mv */*.pdf */April 18/*.pdf but a solution for windows seems to be a bit more complicated

$rootPath = "C:\"
$moveTo = "C:\April 18"
foreach ($pdfFile in (Get-ChildItem $rootPath | Where-Object {$_.Extension -eq ".pdf"}))
{
Move-Item -Path $pdfFile.FullName -Destination "$moveTo\$($pdfFile.Name)"
}
Like this?

One possibility:
$rootDir = "Reference Code"
Get-ChildItem -Path "$rootDir\*.pdf" -File |
ForEach-Object {
Move-Item $_.FullName -Destination "$rootDir\April 18\$($_.Name)"
}
Note that this will fail if folder April 18 doesn't exist.

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
}

Exclude multiple folders from get-childitem

I have this script that compares 2 directories with each other if it matches it copies it to the other directory. But i need 2 folders to be excluded on the source folder because there are old files there. I excluded one folder but i can't add an second one. Can someone help me out? (I'm a beginner in Powershell) I know the foreach loop is empty, this is for testing purposes.
$aDir = "C:\Replace TEST SCRIPT\A"
$bDir = "C:\Replace TEST SCRIPT\Y"
$aFiles = Get-ChildItem -Path "$bDir\" -Exclude "Folder1","Folder2" | Get-ChildItem -Path "$bDir\*.pdf" -Recurse -File | select -exp FullName
ForEach ($file in $aFiles) {
$laatste = (Get-Item $file).LastWriteTime
$filenaam = Split-Path -Path "$file" -Leaf
if(Test-Path -Path "C:\Replace TEST SCRIPT\A\$filenaam") {
Write-Output "$filenaam exists in $aDir. Copying."
Copy-Item -Path "$file" -Recurse -Destination "$aDir"
} else {
}
}
You can do it the following way:
$aFiles = Get-ChildItem -Path "$bDir\" -Exclude "PDF","folder2" | Get-ChildItem -filter "*.pdf" -Recurse -File | select -exp FullName
Btw.
There is already a post to your certain question:
How can I exclude multiple folders using Get-ChildItem -exclude?
Please take a look at it and let us know.

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
}
}

Move-Item moves entire source directory instead of specified files

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

Avoid recursively fetching specific folders in PowerShell

I have a Visual Studio solution with several projects. I clean up the bin and obj folders as part of clean up using the following script.
Get-ChildItem -path source -filter obj -recurse | Remove-Item -recurse
Get-ChildItem -path source -filter bin -recurse | Remove-Item -recurse
This works perfectly. However, I have a file-based data folder that has about 600,000 sub folders in it and is located in a folder called FILE_DATA.
The above script takes ages because it goes through all these 600,000 folders.
I need to avoid FILE_DATA folder when I recursively traverse and remove bin and obj folders.
Here is a more efficient approach that does what you need--skip subtrees that you want to exclude:
function GetFiles($path = $pwd, [string[]]$exclude)
{
foreach ($item in Get-ChildItem $path)
{
if ($exclude | Where {$item -like $_}) { continue }
$item
if (Test-Path $item.FullName -PathType Container)
{
GetFiles $item.FullName $exclude
}
}
}
This code is adapted from Keith Hill's answer to this post; my contribution is one bug fix and minor refactoring; you will find a complete explanation in my answer to that same SO question.
This invocation should do what you need:
GetFiles -path source -exclude FILE_DATA
For even more leisurely reading, check out my article on Simple-Talk.com that discusses this and more: Practical PowerShell: Pruning File Trees and Extending Cmdlets.
If the FILE_DATA folder is a subfolder of $source (not deeper), try:
$source = "C:\Users\Frode\Desktop\test"
Get-Item -Path $source\* -Exclude "FILE_DATA" | ? {$_.PSIsContainer} | % {
Get-ChildItem -Path $_.FullName -Filter "obj" -Recurse | Remove-Item -Recurse
Get-ChildItem -Path $_.FullName -Filter "bin" -Recurse | Remove-Item -Recurse
}