Copy-Item and rename to a specific parent directory in Powershell - database

I've got a script that will copy a list of directories that I've filtered and copied into a new directory with the name plus the LastWriteTime
$srcdir = "Z:\Production500\000600"
$destdir = "X:\Standards\Water Resources\GIS\_Water Resources GIS Database\_Unprocessed_Raw_data"
$folders = Get-ChildItem -Recurse "Z:\Production500\000600" -Filter "Water Resources","GIS" -Recurse
$i=1
$folders | % ($_) {cp $_.FullName -Destination "$destdir\$($_.Name + $_.LastWriteTime.toString("_yyyy_MM_dd_") + $i)" -recurse; $i++}
The script works great copying the exact folders and files I need into the following format:
.\GIS_2017_07_09_1
.\GIS_2017_07_10_2
.\GIS_2017_07_10_3
Instead of the counter, I'd prefer to have a name on the end from one of the parent directories. For Example if $folders is this list:
Directory: Z:\Production500\000600\B000676\Design\004\Chisholm Park\Water Resources
Directory: Z:\Production500\000600\B000667\Design\001\Water Resources
Directory: Z:\Production500\000600\B000663\Design\001\Water Resources
I'd like the copied items renamed to this:
.\GIS_2017_07_09_B000676
.\GIS_2017_07_10_B000667
.\GIS_2017_07_10_B000663
thus eliminating the need for the counter and also making the destination more organized. Notably, the B000### is always the 3rd folder deep.

Lets assume your path is mentioned in a variable and you can proceed with this since you have already mentioned that it will always be the 3rd level folder:
You can use the spilt to get the folder name and can put it inside the foreach
$path="Z:\Production500\000600\B000676\Design\004\Chisholm Park\Water Resources"
$srcdir = "Z:\Production500\000600"
$destdir = "X:\Standards\Water Resources\GIS\_Water Resources GIS Database\_Unprocessed_Raw_data"
$folders = Get-ChildItem "Z:\Production500\000600" -Filter "Water Resources","GIS" -Recurse
$folders | % ($_) {cp $_.FullName -Destination "$destdir\$($_.Name + $_.LastWriteTime.toString("_yyyy_MM_dd_") + "$($path.split('\')[3])")" -recurse}
You do not need the $i variable and do not need to do the incremental operation.
Make sure you are giving the path properly so that it can split on each path. This is just a sample hardcoding the path since you have not specified whether it will be in the destination path or the source path.
Hope it helps.

Related

Using RegEx to match characters between two symbols and copy it to a location

I have directory of files and my goal is matching a 5 digit zip code and copying it to another set of specific folders.
I know there are a number of ways to do this but sometimes the zip code shows up twice in the file name so I have to match the zip code in between ^ and % such that the entire filename is like: mjn22182aguygbc^12350%abc.pdf.
Another assumption is the destination location has preset folders named the zip code such as: d:\queries\12350.
My goal is to move mjn22182aguygbc^12350%abc.pdd to d:\queries\12350 if the zip code exists in some list i can read in and if it is not part of the zip codes, the file stays in the source folder.
So far I have the following but the all files are being copied into my root destination folder and not the folders that I've created eg 12350 and I'm having trouble :
$dstpath = "D:\queries"
$filterlist = #("12350","90182")
$fileList = Get-ChildItem -Path $srcpath -Force -Recurse
foreach ($currentfile in $fileList)
{
foreach($zip in $filterLists)
{
$currentzip = $currentfile.Name -match '(?<=\^)[0-9]+(?=%)';
if($currentzip -in $filterlist)
{
Move-Item -Path $($file.FullName) -Destination $dstpath
}
}
}
The regex is right, but all -match does is return true.
'mjn22182aguygbc^12350%abc.pdd' -match '(?<=\^)[0-9]+(?=%)'
True
The match would be contained in $matches.0 afterwards.
$matches.0
12350
You're moving to $dstpath. There's no reason it would go anywhere else.

Powershell ISE - How do I copy many files and rename them at the same time?

I'm trying to use Powershell ISE to help me do the following:
Perform a search for many files (with an extension of *props.tmpl) under a certain folder and to include all sub-directories.
When found, I want to copy that file to its current location, but with an extension of *.tmpl2 (what I really want is to skip this step and copy *props.tmpl to a file called *props)
Then rename all *.tmpl2 files and remove the tmpl2 entirely, leaving just the *.props extension.
Ideally, what I want is to copy existing files to the same directory with a new name. It seems like all of the searches I've ran on Powershell ISE are not coming up with the right info I need (or I'm not searching for the right way to do it - trying 'powershell ise copy many files with new names' didn't help.
I had the replacement piece down and working, but I no longer want to eliminate the original tmpl files (they are templates so I may want to review them later for their original content).
What I was doing to replace them was this:
Get-ChildItem -Filter "*props.tmpl" -Recurse |
Rename-Item -NewName { $_.name -replace '.tmpl',''}
Which works great other than completely removing the original file.
I started trying to piece something together, but I'm not understanding how to properly name the copy and stopped at this point with just an error (this was an attempt to skip the extra copy and just simply rename the copy instead of adding the extra step of '*.tmpl2'):
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file
ForEach-Object {
Copy-Item $_.name |
Rename-Item -NewName { $_.name -replace '.props.tmpl','.props' }
}
Any help would be really appreciated (not much of a Powershell guy, but I'm trying to learn since powershell tends to be a little more dynamic then oldschool batch scripts).
Thanks in advance
Final version of this script per help from #ssennett
Here's my final version:
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file and copy it to non-template form in same location
ForEach-Object {
Copy-Item $_.FullName ($_.Name -replace '.tmpl','')
}
You're not too far from the answer! It's just how Copy-Item is being handled.
Without a Destination being specified, the Copy-Item will effectively try and copy the file onto itself. Instead of piping it to Rename-Item, you can handle the renaming with the -Destination parameter, as below.
$files = Get-ChildItem -Filter "*props.tmpl" -Recurse
$files | % { Copy-Item -Path $_.FullName -Destination ($_.Name -replace 'props.tmpl','.props') }
This would copy a file called RandomFileprops.tmpl into another file RandomFile.props. If you want to remove the original, you can use the Move-Item cmdlet with the same parameters, which effectively renames the original file.

Move files from an array of subfolders to a new directory with same array names

Using powershell I would like to search through an array of sub-folders in multiple directories containing 1 folder called incoming and move the files from incoming to a staging area using the same folder name as its source.
IE: Files arrive in folders like this:
z:\folder1\incoming\file.*, z:\folder2\incoming\file.*, z:\folder3\sub1\incoming\file.*, z:\folder3\sub2\incoming\file.* etc.
Then would need to be moved to a staging area using the same folder structure:
\nas\staging\folder1\incoming\file.*, \nas\staging\folder2\incoming\file.*, \nas\staging\folder3\sub1\incoming\file.*, \nas\staging\folder3\sub2\incoming\file.* etc.
Basically the only sub-folders i want to extract from are the ones containing the "Incoming" folder with files. Since there is no predefined folder names other than the sub-folder "Incoming" i would need to loop through every folder within Z:.
Any help or advice would be greatly appreciated.
I was able to come up with this which affectively moves the folder structure excluding "outgoing" to the staging directory which is great but in my environment there would be to many exclusions to check for this way. Also is there a chance i can move the files to specific folders from maybe a list if needed?
$from = 'C:\ftp'
$to = 'C:\staging'
$excludeMatch = #("Outgoing")
Get-ChildItem -Path $from -Recurse -Exclude $exclude |
where { $excludeMatch -eq $null -or $_.FullName.Replace($from, "") -notmatch $excludeMatch } |
Copy-Item -Destination {
if ($_.PSIsContainer) {
Join-Path $to $_.Parent.FullName.Substring($from.length)
} else {
Join-Path $to $_.FullName.Substring($from.length)
}
} -Force -Exclude $exclude
Sooooo, what we need is, to identify any file whos parent directory is called 'incoming'? There are at least two ways of solving this I can think of, but there may be a neater, more idiomatic solution that eludes me.
Method 1 - Identify 'incoming' folders then copy contents
get-childitem -Path $from -recurse -Filter "incoming" |
where-object { $_.PSIsContainer }
If you are using PowerShell 3, I believe (read 'untested') this could be shortened to
get-childitem -Path $from -recurse -Filter "incoming" -Directory
Either of the above should result in a stream of 'directory' objects, all of which are 'incoming' folders. For each one, copy the files to appropriate destination.
Method 2 - Identify all files then process those whos folder is 'incoming'
get-childitem -path $from -recurse |
where-object { -not $_.PSIsContainer } |
where-object { (Split-Path $_.Directory -Leaf) -eq "incoming" }
This results in a stream of 'file' objects, all of which are in a folder called 'incoming'. For each one, copy to appropriate destination.

Copy files from source directory to target directory and exclude specific file types from specified directories

I have created a simple Powershell script to copy files during a deployment from a target directory to a source directory and I would like to exclude a list of files. The caveat however is that I would like the ability to exclude files only from a sub directory if specified. This is the snippet I'm using to perform the copy and exclude a list of files:
$SourceDirectory = "C:\Source"
$DestinationDirectory = "C:\Destination"
$Exclude = #("*.txt*", "*.xml*")
Get-ChildItem $SourceDirectory -Recurse -Exclude $Exclude | Copy-Item -Destination {Join-Path $DestinationDirectory $_.FullName.Substring($SourceDirectory.length)}
This will exclude the specified files wherever they appear in the directory tree. Where I would like to get to with the Exclude list is something like this:
$Exclude = #("*Sub1\.txt*", "*.xml*").
This would exclude .txt files only under the Sub1 folder while .xml files would be excluded throughout. I know this doesn't work, but I hope that it helps to better demonstrate the problem I'm trying to solve.
I have considered using a multidimensional array, but I'm not sure if that might be overkill. Any help would be appreciated.
This is one way to do it
$SourceDirectory = 'C:\Source'
$DestinationDirectory = 'C:\Destination'
$ExcludeExtentions = '*.txt*', '*.xml*'
$ExcludeSubDirectory = 'C:\Source\bad_directory1', 'C:\Source\bad_directory2'
Get-ChildItem $SourceDirectory -Recurse -Exclude $ExcludeExtentions |
Where-Object { $ExcludeSubDirectory -notcontains $_.DirectoryName } |
Copy-Item -Destination $DestinationDirectory
Your best friend here is Where-Object, or where. It takes a scriptblock as parameter and uses that scriptblock to validate each object that goes through pipeline. Only objects that make script return $true are passed through Where-Object.
Also, take a look at the object that represents a file you get from Get-ChildItem. It has Name, Directory and DirectoryName containing pieces of file's FullName already split respectively. Directory is actually an object that represents parent directory, and DirectoryName is a string. Get-Member commandlet will help you to discover hidden gems like.
$SourceDirectory = 'C:\Source'
$DestinationDirectory = 'C:\Destintation'
$ExcludeExtentions1 = "^(?=.*?(SubDirectory1))(?=.*?(.xml)).*$"
$ExcludeExtentions2 = "^(?=.*?(SubDirectory2))(?=.*?(.config)).*$"
$ExcludeExtentions3 = "^(?=.*?(.ps1))((?!SubDirectory1|SubDirectory2).)*$"
$ExcludeExtentions4 = ".txt|.datasource"
$files = Get-ChildItem $SourceDirectory -Recurse
foreach ($file in $files)
{
if ($file.FullName -notmatch $ExcludeExtentions1 -and $file.FullName -notmatch $ExcludeExtentions2 -and $file.FullName -notmatch $ExcludeExtentions3-and $file.FullName -notmatch $ExcludeExtentions4)
{
$CopyPath = Join-Path $DestinationDirectory $file.FullName.Substring($SourceDirectory.length)
Copy-Item $file.FullName -Destination $CopyPath
}
}
In this solution, using regex and -notmatch I am able to exclude specific file types from specific directories. $ExcludeExtentions1 will exclude xml files only from SubDirectory1, $ExcludeExtentions2 will exclude config files only from SubDirectory2, $ExcludeExtentions3 will exclude ps1 files as long as they are not in either of the two SubDirectories, $ExcludeExtentions4 will exclude txt and datasource files throughout the entire tree.
We are not actually using all of these matches in our solution, but since I was working on this, I thought I would add multiple conditions in case others could benefit from this approach.
Here are a couple of links that also helped:
http://www.tjrobinson.net/?p=109
http://dominounlimited.blogspot.com/2007/09/using-regex-for-matching-multiple-words.html

copy files from one location to another in powershell script, in addition checking for certain values

So I have folder with files in it, in a certain location
C:\Users\ainfowara\Desktop\testfiles
so I want to move those files to this location
C:\Users\ainfowara\Desktop\destinationTestfiles
the "testfiles" have files of this format txt.*.test.* so basically I wanna check before I move the files that they have those two main stuff (txt) and (test) in the third part.
can someone help me, how can perform this in powershell script
I know I can do this, to set the folders paths
path_src= C:\Users\ainfowara\Desktop\testfiles
path_dst= C:\Users\ainfowara\Desktop\destinationTestfiles
thanks in advance for the help
If there are no subfolders in testfiles(at least that you need files from), try this:
$src = "C:\Users\ainfowara\Desktop\testfiles"
$dst = "C:\Users\ainfowara\Desktop\destinationTestfiles"
Get-ChildItem $src -Filter "txt.*.test.*" | Move-Item -Destination $dst -Force
If you have files in subfolders of the source-path, try this:
$src = "C:\Users\ainfowara\Desktop\testfiles"
$dst = "C:\Users\ainfowara\Desktop\destinationTestfiles"
Get-ChildItem $src -Filter "txt.*.test.*" -Recurse | % {
#Creates an empty file at the destination to make sure that subfolders exists
New-Item -Path $_.FullName.Replace($src,$dst) -ItemType File -Force
Move-Item -Path $_.FullName -Destination $_.FullName.Replace($src,$dst) -Force
}
Be aware that if your filename contains square-bracket [ ] you need another script (known PS bug).

Resources