I am writing a scheduled script that will move images (jpg's) from one location to another.
The problem is that a parent directory is variable in name while the end directory is fixed.
If robocopy would do this I would be happy: robocopy C:\temp\pcbmodel**\defect c:\test**\defect*. But it doesn't
For example this will almost work:
foreach ($i in Get-ChildItem C:\temp\pcbmodel\*\*\defect -recurse)
{
if ($i.CreationTime -lt ($(Get-Date).AddMonths(0)))
{
write $i.FullName
Copy-Item $i.FullName C:\Test
}
}
The problem is that the files are copied in c:\test but the ** path isn't. And the * path I need as it will change for each customer.
Some suggestions would be nice,
Bert
This should put you on the right path to getting a working solution. The important part is the Resolve-Path cmdlet which takes a -Relative parameter: http://technet.microsoft.com/en-us/library/hh849858.aspx. new-Item -Force merely tell it to create a folder structure if required.
# $OldRoot = 'Top-level of old files'
# $DestRoot = 'Top-level of destination'
# Go to old root so relative paths are correct
Set-Location $OldRoot
# Get all the images, then for each one...
Get-ChildItem -Recurse -Include "*.jpeg", "*.jpg" |
ForEach-Object {
# Save full name to avoid issues later
$Source = $_.FullName
# Construct destination filename using relative path and destination root
$Destination = '{0}\{1}' -f $DestRoot, (Resolve-Path -Relative -Path:$Source).TrimStart('.\')
# If new destination doesn't exist, create it
If(-Not (Test-Path ($DestDir = Split-Path -Parent -Path:$Destination))) {
New-Item -Type:Directory -Path:$DestDir -Force -Verbose
}
# Copy old item to new destination
Copy-Item -Path:$Source -Destination:$Destination -Verbose
}
How about something like that:
$step1 = get-childitem C:\temp\pcbmodel\
$Else = #FILETYPE YOU DO NOT WANT
$step1 | foreach {get-childitem -recurse -exclude "Directories", $ELSE | where {$_.Creationtime -lt ($(get-date).Addmonths(0))}
}
Hope I got it right and this helps :)
EDIT: Work with -Exclude and -Include parameters they help a lot :)
EDIT2: Ofc, I overread something, sorry for the many edits - you are just looking for jpg files.
$step1 | foreach {get-childitem -recurse -include *.jpg, *.jpeg | where {$_.Creationtime -lt ($(get-date).Addmonths(0))}
Another idea:
Don't try it on your C: disk. It will need forever. But if u have permissions for every directory and subdirectory in a certain path and the subdirectory amount is not enormous it should work.
I created a directory "New Directory" on C: and another "New Directory" in this directory. And ofc, another "New Directory" in the directory. and lastly I created a file with the name "superduper.txt" --> C:\New Directory\New Directory\New Directory\superduper.txt
(get-childitem C:\).FullName | where {(Get-ChildItem $_).FullName | where {(get-childitem $_ -Recurse).FullName -match "superduper"}}
Result:
C:\New Directory
I think it won't be fast and you would need 2 of these to achieve your goal, I guess it should work.
I'm trying to copy all subfolders and their files from one folder into another, without copying their parent folder as well.
For example, in C:\test with some subfolders containing files, copy to D:\test without it being D:\test\test\subfolders.
Related
Hi all reaching out because I've reached the limits of my powershell knowledge.
I have a directory that has over 200,000 files, I need to copy all files that have a partial match to the filename into folders that I have already created using this script
Set-Location "C:\Users\joshh\Documents\Testing Environment"
$Folders = Import-Csv "C:\Users\joshh\Documents\Weichert.csv"
ForEach ($Folder in $Folders) {
New-Item "myfilepathhere\$($Folder.folderName)" -type directory
}
UPDATED:
Here is a sample of the filenames:
TH-246-02050-LOL-SQ-ALT2.png
TH-246-02050-WHT-H.png
TH-247-02050-EMB-LOD.png
TH-246-02050-LOL-H-ALT2.png
TH-246-02050-LOL-SQ.png
TH-246-02050-LOL-SQ-ALT.png
TH-247-02050-EMB-LOD-ALT.png
TH-247-02050-EMB-LOL.png
TH-247-02050-EMB-LOL-ALT.png
TH-247-02050-LOD-H.png
Above is an example of what the filenames look like, I need to copy all files containing -EMB- and move them into folders in another directory that match the first 12 characters of that filename (ex. TH-247-02050)
UPDATED:
And if a folder doesn't exist create a folder with the first 12 characters of the filename.
Mind you the first 12 characters have many variants some start with RM, KW, etc.
This is what I have so far and what I know but I know the Move-Item portion isn't exactly what I want it to do
$source = "targetPath"
$destination = "targetPath2"
$embFiles = #(Get-ChildItem ${source}/*EMB* -File | Select-Object -ExpandProperty FullName)
foreach($file in $embFiles) {
if($file | Where-Object { $_ -clike "*EMB*" }){
Move-Item -Path $source -Destination $destination
}
}
Any and all help would be GREATLY appreciated!
Here is one way you could do it:
Get all files that contain -EMB- in their names: -Filter *-EMB-* -File.
Group all this files by everything before -EMB-, here we can use Group-Object -AsHashTable and a calculated expression using Regex.Match. See https://regex101.com/r/iOoBJS/1 for details.
Loop through the Keys of the hash table, each Key will be the Name Destination folder of the group of files (i.e.: TH-247-02050).
Join the destination path ($destinationPath2) with the name of the destination folder ($folder), here we can use Join-Path and check if this joined path exists, if it doesn't, create a new folder with New-Item.
Lastly, we can move all the files (the Values of each Key from the hash table) to their corresponding destination.
$source = "targetPath"
$destination = "targetPath2"
$map = Get-ChildItem $source -Filter *-EMB-* -File | Group-Object -AsHashTable -AsString {
[regex]::Match($_.BaseName, '(?i).+(?=-EMB-)').Value
}
foreach($folder in $map.Keys) {
$d = Join-Path $destination -ChildPath $folder
$d = New-Item $d -ItemType Directory -Force
# -WhatIf can be removed once you have checked the script is doing what you want
$map[$folder] | Move-Item -Destination $d -WhatIf -Verbose
}
-AsString is needed in Windows PowerShell due to a bug.
I have a script that looks at the source folder and then the destination folder and decides if the sub-folders are present. If not, it creates the corresponding folder. Once that is done, it moves all of the files in the sub folders to the destination. Problem - There are duplicate files that need can't be overwritten. I need a way to check for duplicates and if found, increment the source file name by -1. There may be incremented files already.
My current script works flawlessly to create needed sub-folders and move files but I loose any previous files.
$SFolder = "C:\Temp\Test\Source\"
$DFolder = "C:\Temp\Test\Destination\"
$folders = Get-ChildItem -Path $SFolder -Directory
foreach ($folder in $folders) {
Get-ChildItem -File "$sfolder\$folder" |
Where-Object -FilterScript {$_.LastWriteTime -lt [datetime]::Now.AddMinutes(-5)} |
Sort-Object -Property LastWriteTime |
Group-Object -Property {$_.LastWriteTime.ToString("yyyy")} |
ForEach-Object {
if (!(Test-Path -Path "$dfolder\$folder" -PathType Container -ErrorAction SilentlyContinue)) {
New-Item -ItemType Directory -Force -Path "$dfolder\$folder"
}
$_.group|move-item -Destination "$dfolder\$folder" -PassThru
}
}
The script as written works great. Here is what I need. I start with the following:
Source test1\05013018-22503-652469-1 (no file extension)
test1\05013018-22503-652469-2
Destination test2\05013018-22503-652469-1
test2\05013018-22503-652469-1-1
test2\05013018-22503-652469-1-2
I want the following result after running the script:
Source test1\
Destination test2\05013018-22503-652469-1
test2\05013018-22503-652469-1-1
test2\05013018-22503-652469-1-2
test2\05013018-22503-652469-1-3
test1\05013018-22503-652469-2
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!
To give some context, I have two root folders, one source and one destination. I am trying to write a PowerShell script that goes through a specific file in each folder and if that file meets the criteria, the entire folder of that file gets copied over.
Currently, I am only able to copy the contents of the folder and not the entire folder itself.
I found that using (Get-Item $files).Directory gets me the path of the file it's checking. However, when I use Get-Item -Path $fileRoot -Recurse it comes back saying that -Recurse is unknown.
Below is the full script.
$files = Get-ChildItem -Path "C:\testPath\source\*\content*.xml"
$files | ForEach-Object {
$file = [xml](Get-Content $_.FullName);
$nodeXML = $file.SelectNodes("//*[local-name()='testPathq']");
if ($file.ParentNode.InnerXml.Contains('testPathq') -eq $nodeXML) {
$fileRoot = (Get-Item $files).Directory
$destination = 'C:\testPath\destination\'
Get-ChildItem -Path $fileRoot -Recurse |
Copy-Item -Destination $destination -Force
}
}
Problem
I am working on a rollback feature in my application in which I copy the files from a backup/rollback directory to a destination folder. As simple as that sounds, this is where it gets complicated. Due to all the files sharing the same or similar name, I used the parent folder as the anchor to help enforce unique locations.
I want to essentially recursively search a directory and wherever a folder name matches a parent directory of an object, paste a copy of the object into that folder, overwriting whatever file(s) share a name with said object.
A more visible way to represent this would be:
$Path = C:\Temp\MyBackups\Backup_03-14-2017
$destination = C:\SomeDirectory\Subfolder
$backups = GCI -Path "$Path\*.config" -Recursive
foreach ($backup in $backups) {
Copy-Item -Path $backup -Destination $destination | Where-Object {
((Get-Item $backup).Directory.Name) -match "$destination\*"
}
}
However, the above doesn't work and none of my research is finding anything remotely similar to what I'm trying to do.
Question
Does anyone know how to Copy an Item from one location to another in which the parent folder of the copied item matches a folder in the destination using PowerShell?
Enumerate the backed-up files, replace the source base path with the destination base path, then move the files. If you only want to replace existing files, test if the destination exists:
Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
$dst = $_.FullName.Replace($Path, $destination)
if (Test-Path -LiteralPath $dst) {
Copy-Item -Path $_.FullName -Destination $dst -Force
}
}
If you want to restore files that are missing in the destination make sure to create missing directories first:
Get-ChildItem -Path $Path -Filter '*.config' -Recursive | ForEach-Object {
$dst = $_.FullName.Replace($Path, $destination)
$dir = [IO.Path]::GetDirectoryName($dst)
if (-not (Test-Path -LiteralPath $dir -PathType Container)) {
New-Item -Type Directory -Path $dir | Out-Null
}
Copy-Item -Path $_.FullName -Destination $dst -Force
}
You may be over thinking this. If you are backing up a web.config file from a website, I'd highly advise using the SiteID as the backup folder. Then simply utilize this as the means to find the right folder to copy the web.config file to when you want to rollback.
Ideally when working with any group of items (in this instance websites) try to find a unique identifier for the items. SiteIDs are ideal for this.
$Path = C:\Temp\MyBackups\Backup_03-14-2017 #In this directory store the web.config's in directories that match the SiteID of the site they belong to
#For example, if the site id was 5, then the full backup directory would be: C:\Temp\MyBackups\Backup_03-14-2017\5
$backups = Get-ChildItem -Path $Path -Include *.config -Recurse
foreach ($backup in $backups)
{
$backupId = $backup.Directory.Name
$destination = (Get-Website | where {$_.id -eq $backupId}).physicalPath
Copy-Item -Path $backup -Destination $destination
}