Copying folder contents preserving the folder structure using powershell script - windows

I have the source folder structure as shown below
c:\TestResults
|-- Log
| |-- xyz.pdf
| `-- Reports
| `-- rp.pdf
|-- Keywords
| |-- key.txt
| | `-- pb.ea
| `-- reports
|-- Test
| |-- 11.pdf
| |-- 12
| `-- Log
| |-- h1.pdf
| `-- Reports
| `-- h2.pdf
`-- Dev
|-- st
|-- ea
`-- Log
`-- Reports
`-- h4.pdf
I need to copy all the "Log" folders while maintaining the folder structure. The destination path is "c:\Work\Logs\TestResults". The resultant structure should be as shown below.
c:\Work\Logs\TestResults
|-- Log
| |-- xyz.pdf
| `-- Reports
| `-- rp.pdf
|-- Test
| `-- Log
| |-- h1.pdf
| `-- Reports
| `-- h2.pdf
`-- Dev
`-- Log
`-- Reports
`-- h4.pdf
Is there an easy way of achieving this using a powershell script? Thanks!
Edit: Here's the code that I have written so far. It flattens the folder structure but doesn't maintain the hierarchy. I am new to powershell scripting. Please help.
$baseDir = "c:\TestResults"
$outputDir = "c:\Work\Logs"
$outputLogsDir = $outputDir + "\TestResults"
$nameToFind = "Log"
$paths = Get-ChildItem $baseDir -Recurse | Where-Object { $_.PSIsContainer -and $_.Name.EndsWith($nameToFind)}
if(!(test-path $outputLogsDir))
{
New-Item -ItemType Directory -Force -Path $outputLogsDir
}
foreach($path in $paths)
{
$sourcePath = $path.FullName + "\*"
Get-ChildItem -Path $sourcePath | Copy-Item -Destination $outputLogsDir -Recurse -Container
}

What you are after is as below. it will copy the item and dir if any part of it has "\log" in it.
$gci = Get-ChildItem -Path "C:\TestResults" -Recurse
Foreach($item in $gci){
If($item.FullName -like "*\log*"){
Copy-Item -Path $item.FullName -Destination $($item.FullName.Replace("C:\TestResults","C:\Work\Logs\TestResults")) -Force
}
}

Related

Output multiple .csv files appending the .csv file name as the source folder name with powershell

I have 30 folders. Each folder contains 22 .text files. I am trying to get the filenames and row count of each .text files and output it in a .csv file, appending the name of the .csv file with the name of each subfolder.
The script I made works but it will pull all the .text files from all subfolders and output it in a single .csv file.
Any idea how I can create one .csv file per subfolder ?
$results = Get-ChildItem "C:\Users\testserver\Documents\logfiles\*.txt" -Recurse | % { $_ | select name, #{n="lines";e={get-content $_ | measure-object -line | select -expa lines } } } | Select-Object name, lines
$results | Export-Csv "C:\Users\testserver\Documents\results.csv" -notype
Use the Group-Object cmdlet to process the files grouped by the directory they reside in:
$inDir = 'C:\Users\testserver\Documents\logfiles'
$outDir = 'C:\Users\testserver\Documents'
Get-ChildItem -File -Recurse -Filter *.txt $inDir |
Group-Object DirectoryName |
ForEach-Object {
$outFile = Join-Path $outDir "results-$(Split-Path -Leaf $_.Name).csv"
$_.Group |
Select-Object Name, #{ n="Lines"; e={ (Get-Content $_.FullName | Measure-Object -Line).lines } } |
Export-Csv -NoTypeInformation $outFile
}
The above creates output files such as results-foo.csv in $outDir, where foo is the name of a subdirectory containing *.txt files.
Note that the assumption is that no two subdirectories in the target $inDir directory tree have the same name; more work is needed if you need to handle such collisions, such as reflecting the relative paths in the file name, with \ replaced with a substitute char.

Powershell | Find similar files by name(Name.txt/Name (01).txt/ Name (02).txt) in a directory and delete all except last modified

I have a folder in which i download working files, usually all versions of the files have the same name, so windows mark tham as "name (01).ext", "name (02).ext" and so on. I need to write a script that deletes every copy EXCEPT last modified. For now my script working perfectly if folder contains only one pack of similar files, but if there are a lot of them, that it deletes everything except only one last modified.
Get-ChildItem -Path D:\Re\* -Include *.txt, *.rtf |
Group-Object { $_.BaseName.Split('\ \(\d\)', 2)[0] } |
Where-Object { $_.Count -gt 1 } |
ForEach-Object { $_.Group | Sort LastWriteTime | Select -SkipLast 1 } |
Remove-Item -Force
I think that the problem is in
Group-Object { $_.BaseName.Split('\ \(\d\)', 2)[0] } |
as its puts every single found file in one single group.
The .split() method does not use regex, the -split operator does. I believe it would work fine if you changed it to
Get-ChildItem -Path D:\Re\* -Include *.txt, *.rtf |
Group-Object { ($_.BaseName -Split '\ \(\d\)')[0] } |
Where-Object Count -gt 1 |
ForEach-Object { $_.Group | Sort LastWriteTime | Select -SkipLast 1 } |
Remove-Item -Force
Also note with any single property operation in the *-Object cmdlets you can omit the braces { } and automatic variable $_.

Prefix every file in subdirectories with the folder name

Preferably using bash or PowerShell, I would like to prefix every file in subdirectories of a directory with their respective folder name.
Each folder has a series of PDF forms with generic names. The folders possess the names of the individuals who are to sign the forms, so are to be renamed accordingly.
This PowerShell snippet seems similar to what I'll need,
dir | Rename-Item -NewName {$_.Directory.Name + "_" + $_.Name}
--but I couldn't figure out how to make it apply to all subdirectories.
Thank you deeply in advance for any assistance!
$ tree
.
└── foo
├── bar
│   ├── baz
│   │   └── file
│   └── file
└── file
3 directories, 3 files
$ find . -type f -exec sh -c 'f=${1//\//_}; mv $1 ${1%/*}/${f:2}' _ {} \;
$ tree
.
└── foo
├── bar
│   ├── baz
│   │   └── foo_bar_baz_file
│   └── foo_bar_file
└── foo_file
3 directories, 3 files
You need to use Get-ChildItem (alias dir) and specify parameters Recurse and File at least, so your code will traverse subdirectories and rename files only (not also folder objects)
$rootFolder = 'D:\Test' # the folder where the subfolders storing the PDF files are
(Get-ChildItem -Path $rootFolder -Filter '*.pdf' -File -Recurse) | Rename-Item -NewName {
'{0}_{1}' -f $_.Directory.Name, $_.Name
}
If you run the above several times, then each time the pdf files get their name prefixed with the directory name, so you'll end up with files like foo_foo_foo_file1.pdf.
To prevent that from happening, you can add a Where-Object clause like:
$rootFolder = 'D:\Test'
(Get-ChildItem -Path $rootFolder -Filter '*.pdf' -File -Recurse) |
Where-Object { $_.Name -notmatch "^$($_.Directory.Name)_" } |
Rename-Item -NewName { '{0}_{1}' -f $_.Directory.Name, $_.Name }
Note that the brackets around the Get-ChildItem cmdlet are needed to make sure it does not 'pick up' any file you have renamed earlier in the pipe
Try this:
Get-ChildItem -Recurse | Foreach {
$Parent = Split-Path "$_.Fullname" -Parent
$Name = "$($Parent)" + "_" + "$_.Name"
Renmae-Item -Path "$_.Fullname" -Newname "$Name"
}

Gather similar files into separate folders based on keywords in the filenames of multi-part archives

I have a folder that contains many rar or zip files. I want put similar files (based on part word in filename if exist) to own folder.by default in parent folder there isn't any folder.maybe in future another part of file added to parent directory so this time it should move file to his own folder instead of create new folder.
For example assume the files are:
Visual_Studio_2015.part1.rar
Visual_Studio_2015.part2.rar
Visual_Studio_2015.part3.rar
SQL-Server-Enterprise-2016-SP1.part1.rar
SQL-Server-Enterprise-2016-SP1.part2.rar
VSCodeSetup x64 1.29.1.rar
Microsoft.Visual.Studio.Ultimate.2012.update.3.part1.rar
Microsoft.Visual.Studio.Ultimate.2012.update.3.part12.rar
after moving,become looks like this:
Parent Directory
├───Visual_Studio_2015
│ ├───Visual_Studio_2015.part1.rar
│ ├───Visual_Studio_2015.part2.rar
│ ├───Visual_Studio_2015.part3.rar
├───VSCodeSetup x64 1.29.1
│ ├───VSCodeSetup x64 1.29.1.rar
├───SQL-Server-Enterprise-2016-SP1
│ ├───SQL-Server-Enterprise-2016-SP1.part1.rar
│ ├───SQL-Server-Enterprise-2016-SP1.part2.rar
├───Microsoft.Visual.Studio.Ultimate.2012.update.3
│ ├───Microsoft.Visual.Studio.Ultimate.2012.update.3.part1.rar
│ ├───Microsoft.Visual.Studio.Ultimate.2012.update.3.part2.rar
i can't use any software or compiled programming language for this problem. sorry for weak English
update:
in powershell somthing like this:
Get-ChildItem -File |
Group-Object { $_.Name -replace '.part.*' } |
ForEach-Object {
$dir = New-Item -Type Directory -Name $_.Name
$_.Group | Move-Item -Destination $dir
}
can separating files that have part in filename but not work for without it, also i must mention that all filename end with .partX (X is a digit) if it is multi parted archives.
If all the files are in one root folder and have the naming convention you specify, then here is one way to move them into appropriate subfolders:
Get-Childitem -path "C:\Test" -File |
ForEach-Object {
if($_.Name -match "^(?<folder>.*)\.part\d+|(?<folder>.*)\.rar$") {
New-Item -Path "$($_.Directory)\$($matches.Folder)" -ItemType Directory -Force | Out-Null
Move-Item -Path $_.FullName -Destination "$($_.Directory)\$($matches.Folder)\$($_.Name)" -Force
}
}
Change the path in Get-Childitem as appropriate. Also, you can modify the paths for New-Item and Move-Item if you want them to be located somewhere else instead of as subfolders of the root directory.
Another way to do it would be this:
$parentFolder = '<THE PARENTFOLDER THAT HOLDS ALL .RAR AND .ZIP FILES>'
# Get all files inside the parent folder with extension '.rar' or '.zip'
# Because '-Filter' only accepts a single string, we need to use a 'Where-Object' clause.
# Another way would be to use the '-Include' parameter on Get-Childitem, but for that to work
# you must either also use '-Recurse' or append '\*' to the $parentfolder like this:
# Get-ChildItem -Path "$parentFolder\*" -File -Include *.rar, *.zip
Get-ChildItem -Path $parentFolder -File | Where-Object { $_.Extension -match '\.(rar|zip)$' } | ForEach-Object {
# create the name of the subfolder by removing the '.partX' from the basename if that exists
$subFolder = Join-Path -Path $parentFolder -ChildPath ($_.BaseName -replace '\.part\d+', '')
# create this subfolder if it does not already exist
if (!(Test-Path -Path $subFolder -PathType Container)) {
New-Item -Path $subFolder -ItemType Directory -Force | Out-Null
}
# move the file to the subfolder
$_ | Move-Item -Destination $subFolder
}

recursively check all folders and export the list of folders that has no created backup file in it during last 24 hour

There is a folder containing database backup files. I need to recursively check all folders and export the list of last backup files in each folder.
I have a code here that contains my idea. just I have to add this part:
-check for each selected file(selected file is the last created backup file) if the file creation time is older than 24 hours, export in csv file.
Thanks in advance
[Cmdletbinding()]
param(
[Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true)]$path=
"\F:\backups",
[Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)]
$OutPutFilepath=
"f:\backup-daily.csv"
)
function Get-LastestWroteFile{
[Cmdletbinding()]
param(
[Parameter(Position=0,Mandatory=$true)]$Folder
)
begin{
$Latest = Get-ChildItem $Folder.FullName -File | select FullName,
CreationTime, LastAccessTime, LastWriteTime, Attributes, #{N='SizeInMb';E=
{$_.Length/1mb}},Name | Sort-Object CreationTime | select -Last 1
}
process{
}
end{
#new custom object with 3 props.
if($Latest){
return New-Object PSobject -Property #{"FullName"=$latest.Name;
LastWriteTime =
$latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =
[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
}
}
}
$OutPut=#()
Get-ChildItem -Directory -Path $path -Recurse | foreach{
$OutPut+= Get-LastestWroteFile $_
}
$OutPut | ConvertTo-Csv -NoTypeInformation -delimiter '|' | Out-File -
FilePath $OutPutFilepath
an advanced function would not be required, try below
Get-ChildItem -Path $Path -Recurse -File | Where-Object -FilterScript {
([Datetime]::Now - $_.CreationTime ).Hours -gt 24
} | Select-Object -Property Name,LastWriteTime,FullName,#{N='SizeInMb';E=
{$_.Length/1mb}},

Resources