is file a child of given folder in PS? [duplicate] - powershell

Trying to get my copy-item to copy everything in directory except a subfolder. I was able to exclude in the folder and files, but not subfolders.
I tried using get-children and the -exclude in the copy-item but didn't exclude them as I hope
$exclude = "folder\common"
Get-ChildItem "c:\test" -Directory |
Where-Object{$_.Name -notin $exclude} |
Copy-Item -Destination 'C:\backup' -Recurse -Force
Hoping that the common folder will exist but nothing in it would be copy.
Thanks for the help

I think this should do what you need:
$sourceFolder = 'C:\test'
$destination = 'C:\backup'
$exclude = #("folder\common") # add more folders to exclude if you like
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($exclude | ForEach-Object { [Regex]::Escape($_) }) -join '|'
Get-ChildItem -Path $sourceFolder -Recurse -File |
Where-Object{ $_.DirectoryName -notmatch $notThese } |
ForEach-Object {
$target = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($sourceFolder.Length)
if (!(Test-Path -Path $target -PathType Container)) {
New-Item -Path $target -ItemType Directory | Out-Null
}
$_ | Copy-Item -Destination $target -Force
}
Hope that helps

I think using the -exclude parameter on Get-ChildItem would work:
$exclude = 'Exclude this folder','Exclude this folder 2','Folder3'
Get-ChildItem -Path "Get these folders" -Exclude $exclude | Copy-Item -Destination "Send folders here"

Here is an example:
$exclude= 'subfolderA'
$path = 'c:\test'
$fileslist = gci $path -Recurse
foreach ($i in 0..$fileslist){ if( -not ($i.Fullname -like "*$($exlusion)*")){ copy-item -path $i.fullname -Destination 'C:\backup' -Force } }

Related

Powershell copy only selected files with folder structure

I have a folder hierarchy with a lot of files.
I need to copy all folders and only selected files. For this purposes I write script:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" }
$Destination = "D:\test\"
Copy-Item $files -Destination $Destination -recurse
When I execute variable $files, it returns correct path:
But when I execute Copy-Item it returns not full path:
Perhaps my approach is wrong. If so, how to copy entire folder structure, and only selected files (in this case system.serviceModel.client.config file)?
UPD1 Ok, I've found, how to copy only folders:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181\"
$Destination = "D:\test\"
Copy-Item $path $Destination -Filter {PSIsContainer} -Recurse -Force
But how to copy only selected files, preserving their location? What needs to be in $Destination variable?
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" } | % { Copy-Item -Path $_.FullName -Destination $Destination }
This code would keep the directory structure the same too
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181\"
$Destination = "D:\test\"
$fileName = "system.serviceModel.client.config"
Get-ChildItem -Path $path -Recurse | ForEach-Object {
if($_.Name -like $fileName) {
$dest = "$Destination$(($_.FullName).Replace($path,''))"
$null = New-Item $dest -Force
Copy-Item -Path $_.FullName -Destination $dest -Force
}
}
To copy the whole folder structure AND files with a certain name, below code should do what you want:
$Source = 'D:\Drop\SOA-ConfigurationManagement - Test\181'
$Destination = 'D:\test'
$FileToCopy = 'system.serviceModel.client.config'
# loop through the source folder recursively and return both files and folders
Get-ChildItem -Path $Source -Recurse | ForEach-Object {
if ($_.PSIsContainer) {
# if it's a folder, create the new path from the FullName property
$targetFolder = Join-Path -Path $Destination -ChildPath $_.FullName.Substring($Source.Length)
$copyFile = $false
}
else {
# if it's a file, create the new path from the DirectoryName property
$targetFolder = Join-Path -Path $Destination -ChildPath $_.DirectoryName.Substring($Source.Length)
# should we copy this file? ($true or $false)
$copyFile = ($_.Name -like "*$FileToCopy*")
}
# create the target folder if this does not exist
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
if ($copyFile) {
$_ | Copy-Item -Destination $targetFolder -Force
}
}
try this
$path = 'D:\Drop\SOA-ConfigurationManagement - Test\181\'
$Destination = 'D:\test\'
$files = Get-ChildItem -Path $path -Recurse -File | where Name -like "*system.serviceModel.client.config*" | %{
$Dir=$_.DirectoryName.Replace($path, $Destination)
$NewPAthFile=$_.FullName.Replace($path, $Destination)
#create dir if not exists
New-Item -Path $Dir -ItemType Directory -Force -ErrorAction SilentlyContinue
#copy file in new dir
Copy-Item $_.FullName $NewPAthFile
}
With minimal changes I'd suggest the following:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" }
$Destination = "D:\test\"
$files | % { $_ | Copy-Item -Destination $Destination -recurse }
You can even put the whole copy on one line:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$Destination = "D:\test\"
Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" } | % { $_ | Copy-Item -Destination $Destination -recurse }
Copy-Item can find the path from the stream of input objects but it doesn't seem to be able to take a collection of System.IO.FileInfo objects as an argument to Path.

Copy-item exclude Sub-folders

Trying to get my copy-item to copy everything in directory except a subfolder. I was able to exclude in the folder and files, but not subfolders.
I tried using get-children and the -exclude in the copy-item but didn't exclude them as I hope
$exclude = "folder\common"
Get-ChildItem "c:\test" -Directory |
Where-Object{$_.Name -notin $exclude} |
Copy-Item -Destination 'C:\backup' -Recurse -Force
Hoping that the common folder will exist but nothing in it would be copy.
Thanks for the help
I think this should do what you need:
$sourceFolder = 'C:\test'
$destination = 'C:\backup'
$exclude = #("folder\common") # add more folders to exclude if you like
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($exclude | ForEach-Object { [Regex]::Escape($_) }) -join '|'
Get-ChildItem -Path $sourceFolder -Recurse -File |
Where-Object{ $_.DirectoryName -notmatch $notThese } |
ForEach-Object {
$target = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($sourceFolder.Length)
if (!(Test-Path -Path $target -PathType Container)) {
New-Item -Path $target -ItemType Directory | Out-Null
}
$_ | Copy-Item -Destination $target -Force
}
Hope that helps
I think using the -exclude parameter on Get-ChildItem would work:
$exclude = 'Exclude this folder','Exclude this folder 2','Folder3'
Get-ChildItem -Path "Get these folders" -Exclude $exclude | Copy-Item -Destination "Send folders here"
Here is an example:
$exclude= 'subfolderA'
$path = 'c:\test'
$fileslist = gci $path -Recurse
foreach ($i in 0..$fileslist){ if( -not ($i.Fullname -like "*$($exlusion)*")){ copy-item -path $i.fullname -Destination 'C:\backup' -Force } }

Powershell: Loop through sub-directories and move files

I'm targeting simple task.
I would like to create folder of constant name "jpg" in all subfolders of supplied root folder "D:Temp\IMG" and move all files in every subfolder with extension ".jpg" to that newly created "jpg" folder.
I thought I'll be able to solve this by myself without deep knowledge of powershell, but it seems I have to ask.
So far, I created this code
$Directory = dir D:\Temp\IMG\ | ?{$_.PSISContainer};
foreach ($d in $Directory) {
Write-Host "Working on directory $($d.FullName)..."
Get-ChildItem -Path "$($d.FullName)" -File -Recurse -Filter '*.jpg' |
ForEach-Object {
$Dest = "$($d.DirectoryName)\jpg"
If (!(Test-Path -LiteralPath $Dest))
{New-Item -Path $Dest -ItemType 'Directory' -Force}
Move-Item -Path $_.FullName -Destination $Dest
}
}
What I'm getting out of this is infinite loop of folder "jpg" creation in every subfolder.
Where is my code and logic failing here, please?
The following script would do the job.
$RootFolder = "F:\RootFolder"
$SubFolders = Get-ChildItem -Path $RootFolder -Directory
Foreach($SubFolder in $SubFolders)
{
$jpgPath = "$($SubFolder.FullName)\jpg"
New-Item -Path $jpgPath -ItemType Directory -Force
$jpgFiles = Get-ChildItem -Path $SubFolder.FullName -Filter "*.jpg"
Foreach($jpgFile in $jpgFiles)
{
Move-Item -Path $jpgFile.FullName -Destination "$jpgPath\"
}
}
This will accomplish what you are attempting, I'm pretty sure. Your original script doesn't actually recurse, despite specifying that you want it to (Get-ChildItem has some finicky syntax around that), so I fixed that. Also fixed my suggestion (I forgot that the Extension property includes the preceding dot, so 'FileName.jpg' has '.jpg' as the extension). I added in some checking, and have it throw warnings if the file already exists at the destination.
$Directory = dir D:\Temp\IMG\ -Directory
foreach ($d in $Directory) {
Write-Host "Working on directory $($d.FullName)..."
Get-ChildItem -Path "$($d.fullname)\*" -File -Recurse -filter '*.jpg' |
Where{$_.Directory.Name -ne $_.Extension.TrimStart('.')}|
ForEach-Object {
$Dest = join-path $d.FullName $_.Extension.TrimStart('.')
If (!(Test-Path -LiteralPath $Dest))
{New-Item -Path $Dest -ItemType 'Directory' -Force|Out-Null}
If(Test-Path ($FullDest = Join-Path $Dest $_.Name)){
Write-Warning "Filename conflict moving:`n $($_.FullName)`nTo:`n $FullDest"
}Else{
Move-Item -Path $_.FullName -Destination $Dest -Verbose
}
}
}

Copy-Item and exclude folders

I need to copy all of my c:\inetpub directory to a new location but exclude the following folders and their subfolders:
c:\inetpub\custerr
c:\inetpub\history
c:\inetpub\logs
c:\inetpub\temp
c:\inetpub\wwwroot
So far I am doing this:
# Directory name is created with a format string
$dirName = "\\servername\folder1 _ {0}\inetpub" -f (get-date).ToString("yyyy-MM-dd-hh-mm-ss")
$dirName # Check the output
# Create dir if needed
if(-not (test-path $dirName)) {
md $dirName | out-null
} else {
write-host "$dirName already exists!"
}
#Copy Backup File to Dir
Copy-Item "\\servername\c$\inetpub\*" $dirName -recurse
This is a simple example of something you could do. Build an array of the parent folders that you want to exclude. Since you are accessing them via UNC paths we cannot really use the c:\ path (We can get around this but what I am about to show should be good enough.).
Then use Get-ChildItem to get all the folders in the inetpub directory. Filter out the exclusions using -notin and pass the rest to Copy-Item
$excludes = "custerr","history","logs","temp","wwwroot"
Get-ChildItem "c:\temp\test" -Directory |
Where-Object{$_.Name -notin $excludes} |
Copy-Item -Destination $dirName -Recurse -Force
You need at least PowerShell 3.0 for this to work.
Copy-Item -Path (Get-Item -Path "$path\*" -Exclude ('Folder1', 'File.cmd', 'File.exe', 'Folder2')).FullName -Destination $destination -Recurse -Force
Replace:
$path by your source folder
('Folder1', 'File.cmd', 'File.exe', 'Folder2') by your specific files/folder to exclude
$destination by your destination folder
Oh, the answer was SO simple, but it seems we are all PowerShell noobs.
New-Item -ItemType Directory -Force -Path $outDir # directory must exist
Copy-Item $inDir\* $outDir -Exclude #("node_modules",".yarn") -Recurse
It's the \* that makes it work.
PowerShell is awesome, but...
I wrote this for daily use and packaged it in the script module, it maintains all the directory structure and supports wildcards:
function Copy-Folder {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[String]$FromPath,
[Parameter(Mandatory)]
[String]$ToPath,
[string[]] $Exclude
)
if (Test-Path $FromPath -PathType Container) {
New-Item $ToPath -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
Get-ChildItem $FromPath -Force | ForEach-Object {
# avoid the nested pipeline variable
$item = $_
$target_path = Join-Path $ToPath $item.Name
if (($Exclude | ForEach-Object { $item.Name -like $_ }) -notcontains $true) {
if (Test-Path $target_path) { Remove-Item $target_path -Recurse -Force }
Copy-Item $item.FullName $target_path
Copy-Folder -FromPath $item.FullName $target_path $Exclude
}
}
}
}
Just call the Copy-Folder -FromPath inetpub -ToPath new-inetpub -Exclude custerr,history,logs,temp,wwwroot
The -FromPath and -ToPath can be omitted,
Copy-Folder inetpub new-inetpub -Exclude custerr,history,logs,temp,wwwroot
You can do something along the lines of:
?{$_.fullname -notmatch '\\old\\'}
after you get a hold of all your folders to filter them down.
This example would exclude anything containing "old" in the name. You can do this for directory you wish to exclude.
A full example:
C:\Example*" -include "*.txt -Recurse |
?{$_.fullname -notmatch '\\old\\'}|
% {Copy-Item $_.fullname "C:\Destination\"}
For multiple excludes you can use -And :
C:\Example*" -include "*.txt -Recurse |
?{$_.fullname -notmatch '\\old\\' -And $_.fullname -notmatch '\\old2\\'}|
% {Copy-Item $_.fullname "C:\Destination\"}

PowerShell - Copy specific files from specific folders

So, the folder structure looks like this:
SourceFolder
file1.txt
file1.doc
Subfolder1
file2.txt
file2.doc
SubSubFolder
file3.txt
doc3.txt
What I want to do is copy all .txt files from folders, whose (folder) names contains the eng, to a destination folder. Just all the files inside the folder - not the file structure.
What I used is this:
$dest = "C:\Users\username\Desktop\Final"
$source = "C:\Users\username\Desktop\Test1"
Copy-Item $source\eng*\*.txt $dest -Recurse
The problem is that it copies the .txt files only from each parent folder but not the sub-folders.
How can I include all the sub-folders in this script and keep the eng name check as well? Can you please help me?
I am talking about PowerShell commands. Should I use robocopy instead?
Yet another PowerShell solution :)
# Setup variables
$Dst = 'C:\Users\username\Desktop\Final'
$Src = 'C:\Users\username\Desktop\Test1'
$FolderName = 'eng*'
$FileType = '*.txt'
# Get list of 'eng*' file objects
Get-ChildItem -Path $Src -Filter $FolderName -Recurse -Force |
# Those 'eng*' file objects should be folders
Where-Object {$_.PSIsContainer} |
# For each 'eng*' folder
ForEach-Object {
# Copy all '*.txt' files in it to the destination folder
Copy-Item -Path (Join-Path -Path $_.FullName -ChildPath '\*') -Filter $FileType -Destination $Dst -Force
}
You can do this :
$dest = "C:\NewFolder"
$source = "C:\TestFolder"
$files = Get-ChildItem $source -File -include "*.txt" -Recurse | Where-Object { $_.DirectoryName -like "*eng*" }
Copy-Item -Path $files -Destination $dest
Another take:
$SourceRoot = <Source folder path>
$TargetFolder = <Target folder path>
#(Get-ChildItem $SourceRoot -Recurse -File -Filter *.txt| Select -ExpandProperty Fullname) -like '*\eng*\*' |
foreach {Copy-Item $_ -Destination $TargetFolder}
It may be easier to first get a list of all the folders that contain eng in the name.
$dest = "C:\Users\username\Desktop\Final"
$source = "C:\Users\username\Desktop\Test1"
$engFolders = Get-ChildItem $source -Directory -Recurse | Where { $_.BaseName -match "^eng" }
Foreach ($folder In $engFolders) {
Copy-Item ($folder.FullName + "\*.txt") $dest
}
Fine to do that with powershell. Try:
$dest = "C:\Users\username\Desktop\Final"
$source = "C:\Users\username\Desktop\Test1"
Get-ChildItem $source -filter "*.txt" -Recurse | Where-Object { $_.DirectoryName -match "eng"} | ForEach-Object { Copy-Item $_.fullname $dest }