Copy file with relative path - powershell

I would like to copy all files of a certain type from a certain sub-directory with their relative path from that sub-directory to another directory with the relative path intact. e.g.:
Source sub-dir:
c:\temp\sourcedirectory
Source files:
c:\temp\sourcedirectory\tonymontana\fileOne.txt
c:\temp\sourcedirectory\poker\fileTwo.txt
Target dir:
c:\temp\targetdirectory
Desired result:
c:\temp\targetdirectory\tonymontana\fileOne.txt
c:\temp\targetdirectory\poker\fileTwo.txt
So far I've come up with:
Set-Location $srcRoot
Get-ChildItem -Path $srcRoot -Filter $filePattern -Recurse |
Resolve-Path -Relative |
Copy-Item -Destination {Join-Path $buildroot $_.FullName}
However, this "everything is an object" à la PowerShell is beating me down (at least that's what I suspect). I.e. the files gets copied, but without their relative path.
Anyone who could enlighten me a bit?

Don't bother with PowerShell cmdlets for this, simply use robocopy:
robocopy C:\temp\sourcedirectory C:\temp\targetdirectory *.txt /s

You can try this:
$srcroot = "c:\temp\sourcedirectory"
$builroot= "c:\temp\targetdirectory"
gci -path $srcroot -filter $filepattern -recurse |
% { Copy-Item $_.FullName -destination ($_.FullName -replace [regex]::escape($srcroot),$builroot) }

Try this:
Copy-item $srcRoot -destination $destination -recurse

To prevent copying the folder itself i.e. creating
c:\temp\targetdirectory\sourcedirectory
Change into the source folder, then use a wildcard instead of the folder as the source:
cd C:\temp\sourcedirectory\
Copy-item * -destination c:\temp\targetdirectory -recurse`

Related

Powershell copy file/folder based on keyword

I want to copy folder which match with the keyword. however i want powershell read the keyword from starting point. i added my script below
if any folder name contain test at the start, script will copy the folder. but it's coping all folder even if "Test" keyword is available in the middle name. like if there is two folder
"This.is.a.Test.Folder"
"Test.this.is.a.Folder"
I want powershell copy only "Test.this.is.a.Folder"
any help please
$dest = "D:\2";
$include= #("*Test*")
Get-ChildItem $source -recurse -Force -Verbose -include $include | copy-Item -Destination {Join-Path $dest $_.FullName.Substring($source.length)}```
Your wildcard is meant to capture anything that contains the word Test in this case.
If you want to specifically start with the word Test followed by anything: Test*
Contrary, anything that ends with the word Test would be: *Test
$include = #( "Test*" )
Get-ChildItem $source -Include $include -Recurse -Force -Verbose |
Copy-Item -Destination {
Join-Path $dest -ChildPath $_.FullName.Substring($source.length)
}
Note, that you can use -File to filter only files and -Directory to filter only folders.

Powershell script to copy folder structure and specific file types

I have the following script to copy the folder structure (including empty folders) and specific file types into another directory. However, the issue is that the script copies all files instead of just the .dat and .py files even though I'm using the -Include switch. How to fix this so that it only copies the desired file types
$sourceDir = "C:\User\001"
$targetDir = "C:\User\002"
Get-ChildItem -Path $sourceDir | Copy-Item -Destination $targetDir -Recurse -Include '*.dat', '*.py' -Container
As #Lee_Dailey pointed out, it's probably best to use robocopy for this:
robocopy $sourceDir $targetDir *.dat *.py /e
Yes, this is tricky. You should look up the documentation for the -Include parameter
The Include parameter is effective only when the command includes the contents of an item, such as C:\Windows*, where the wildcard character specifies the contents of the C:\Windows directory.
You could make it work like this:
Copy-Item $sourceDir\* -Destination $targetDir -Recurse -Include '*.dat', '*.py'
-Container is true by default, so you can safely omit it.
Note that you can always use the -WhatIf switch to check if you command will actually do what you want.
You could make it work like this:
i use -Filter
Specifies a filter to qualify the Path parameter. The FileSystem
provider is the only installed PowerShell provider that supports the
use of filters. You can find the syntax for the FileSystem filter
language in about_Wildcards. Filters are more efficient than other
parameters, because the provider applies them when the cmdlet gets the
objects rather than having PowerShell filter the objects after they're
retrieved.
#('*.dat', '*.py') | %{Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter $_ -Force}
or
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter '*.dat' -Force
Copy-Item -Path $sourceDir -Destination $targetDir -Recurse -Filter '*.py' -Force
it should work but
The Include parameter is effective only when the command includes the
contents of an item, such as C:\Windows*, where the wildcard character
specifies the contents of the C:\Windows directory.
Copy-Item -Destination $targetDir -Recurse -Include '*.dat', '*.py'
may find it easier to include files that can be excluded
Copy-Item -Destination $targetDir -Recurse -Exclude'*.da1', '*.xxx

Powershell script to copy files based on filename

I have a folder that contains several thousand files. I would like to write a Powershell script that loops through the files and copies each file whose filename contains a specific keyword. In pseudocode:
For each file in C:\[Directory]
If filename contains "Presentation" Then
copy file in C:\[Directory 2]
Simply like this ?
copy-item "C:\SourceDir\*Presentation*" "C:\DestinationDir"
or like this :
copy-item "C:\SourceDir\*" "C:\DestinationDir" -Filter "*rrrr*"
But a risk exist if you have a directory with "presentation" in his name into the source directory. Then take all method proposed here and add -file in get-childitem command.
Like in this short version of Robdy code :
gci "C:\SourceDir" -file | ? Name -like "*Presentation*" | cpi -d "C:\DestinationDir"
That code should do the trick:
$files = Get-ChildItem -Path "C:\path\to\source\folder"
$files | Where-Object Name -Like "*Presentation*" | Copy-Item -Destination "C:\path\to\destination\folder"
Of course can be written in one line but I put in two for visibility.
Edit: as Esperento57 pointed out, you might want to add -ItemType File to Get-ChildItem cmdlet to not include folders with 'Presentation' in their name. Also, depending on your needs you might also want to use -Recurse param to include files in subfolders.
If you have files in subfolders and you want to keep the path in destination folder you'll have to change the script a bit to something like:
Copy-Item -Destination $_.FullName.Replace('C:\path\to\source\folder','C:\path\to\destination\folder')
And for the above you'll have to make sure that folders are actually created (e.g. by using -Force for Copy-Item.
This seems to work:
$src = "Dir1"
$dst = "Dir2"
Get-ChildItem $src -Filter "*Presentation*" -Recurse | % {
New-Item -Path $_.FullName.Replace($src,$dst) -ItemType File -Force
Copy-Item -Path $_.FullName -Destination $_.FullName.Replace($src,$dst) -Force
}
Try something like this:
Get-ChildItem "C:\Your\Directory" -File -Filter *YourKeyWordToIsolate* |
Foreach-Object { Copy-Item $_.FullName -Destination "C:\Your\New\Directory" }
... but, of course, you'll need to fill in some of the blanks left open by your pseudocode example.
Also, that's a one-liner, but I inserted a return carriage for easier readability.

Using Remove-Item cmdlet but excluding sub-directory

I want to remove the following files from the source, however in the source there is a sub-directory that contains files with similar names. When I run the following command it is deleting files in the sub-directory with similar file name. Is there a way to just delete the files from the source and not the sub-directory?
Example: test_1_file, test_2_file, test_3_file exists in each directory, TestFolder and TestFolder/sub
$source = testfolder
remove-item -Path $source -filter test_*_file -recurse -force
It's usually easiest to pipe the output of Get-ChildItem cmdlet into Remove-Item. You then can use the better filtering of Get-ChildItem as I think -Recurse in Remove-Item has some issues. You can even use Where-Object to further filter before passing to Remove-Item
$source = testfolder
Get-ChildItem -Path $source -Filter test_*_file -Recurse |
Where-Object {$_.Fullname -notlike "$source\sub\*"} |
Remove-Item -Force
If the files to delete:
are all located directly in $source
and no other files / directories must be deleted:
Remove-Item -Path $source/test_*_file -Force
No need for -Recurse (as #Bill_Stewart notes).
Note: For conceptual clarity I've appended the wildcard pattern (test_*_file) directly to the $source path.
Using a wildcard expression separately with -Filter is generally faster (probably won't matter here), but it has its quirks and pitfalls.

Get-ChildItem to Move-Item - path not found

I try to move my old logfiles to a yyyy\MM\dd folder structure by
Get-ChildItem . -Recurse -Include *.log |
Move-Item -Dest {"D:\Archive\{0:yyyy\\MM\\dd}\{1}" -f $_.LastWriteTime, $_.Name} -Force
but i get a path-not-found error.
update
The source path does not seem to be the problem. It looks like using -Force on Move-Item does not create missing destination directories.
sub question: Could the same be done without Get-ChildItem?
As far as I found the proposed way of moving logs practically interesting, I decided to complete the task:
Get-ChildItem . -Recurse -Include *.log |
Move-Item -Force -Destination {
$dir = "C:\Temp\{0:yyyy\\MM\\dd}" -f $_.LastWriteTime
$null = mkdir $dir -Force
"$dir\$($_.Name)"
}
I guess that for a source file “some.log” the destination is supposed to be something like “D:\Archive\2010\04\23\some.log” and the directory “D:\Archive\2010\04\23” actually does not exist. In this case Move-Item fails. Is this the case?