Copy folders paths and folders as different inputs powershell - windows

I am trying a script which should copy the folders where the source and destination are in one input file and the folder names in another input file.
The below script is working which does the job for one source, one destination and multiple folders at a time.
$folders = Get-Content -Path D:\input.txt
$Source = Read-host "Enter the Source Path"
$Destination = Read-host "Enter the Destination Path"
foreach ($folder in $folders)
{
Copy-item -Path $Source\$folder -Destination $destination\$folder -Recurse -Verbose
}
Likewise, I need to copy the folders by inputting multiple source and destination and also multiple folders.
csv sample:
Text sample:
Below is the script which I tried but it didnt worked
$folders = Get-Content -Path D:\input.txt
$fileName = 'D:\input.csv'
Import-Csv -Path $fileName -UseCulture -PipelineVariable row |
ForEach-Object -Process {
$source = $row.source
$destination = $row.destination
$path1 = Join-path $source $folders
$path2 = Join-Path $destination $folders
copy-item -Path $path1 -Destination $path2 -Recurse -Verbose
}
Any help?

Related

how to copy files based on filename lenght using powershell

I need to batch copy a sort of file extensions from subfolders to specific folders for each location.
All folders have a 6 digit number
let's say folder Rood folder: BATCH
Subfolder 1: 000000
Subfolder 2: 111111
despite their extensions, most files have the name as the subfolder but some of them may have extra alphanumeric characters, therefore the script should grab only the ones that are not larger than 6 digits.
Example Subfolder1: 000000.pdf 000000.eps the script would need to grab all pdf within subfolders and export them to a PDF exclusive new folder, and the same would apply for eps files.
I know nothing about powershell but I know that something like this would work for an specific subfolder but I'm still missing the parts where it distributes them to a new PDFONLY and EPSONLY folders and the fact the I want to apply this to all the folders whiting the root folder.
Get-ChildItem -Path "C:\BATCH\*" -Include *.pdf,*.eps -Recurse | Copy-Item -Destination D:\
You can use Group-Object to group all the files by their extension and then loop over each group of objects, create a new folder with the desired name and lastly copy all objects of each group to their folders.
$target = 'D:\' # Set destination here
Get-ChildItem -Path C:\BATCH\* -Include *.py, *.ps1 -Recurse |
Group-Object Extension | ForEach-Object {
# Example of `$folderName` would be `PDF ONLY`
$folderName = '{0} ONLY' -f $_.Name.TrimStart('.').ToUpper()
$destination = Join-Path $target -ChildPath $folderName
# If the `$destination` folder doesn't exist
if(-not (Test-Path $destination)) {
# Create it
$null = New-Item $destination -ItemType Directory
}
Copy-Item -LiteralPath $_.Group.FullName -Destination $destination
}
Similar to Santiago's answer but with an extra filter and without grouping you can do this:
$destination = 'X:\somewhere'
Get-ChildItem -Path "C:\BATCH" -Include '*.pdf','*.eps' -File -Recurse |
Where-Object {$_.BaseName -match '^\d{6}$' } | # filter files with a BaseName of just 6 digits
ForEach-Object {
$targetPath = Join-Path -Path $destination -ChildPath ('{0}ONLY' -f $_.Extension.TrimStart(".").ToUpper())
# make sure the target path exists
# for directories, using the -Force switch either creates a new folder
# or returns the DirectoryInfo object of an existing folder.
$null = New-Item -Path $targetPath -ItemType Directory -Force
$_ | Copy-Item -Destination $targetPath
}

Powershell: Copy files from multiple folders to one folder appending files name as source server name

I currently have multiple servers on the farm and want to copy the files of the same extension from these servers to one folder. Each server has the same folder name. The goal is to copy all files from these servers(same path) to another remote folder by appending the files name as the source server. The powershell script I wrote works but was wondering if there was a more elegant way by excluding the second foreach loop in the script (using a foreach-object after the GCI command doesn't work)
Clear-Variable source
Clear-Variable destination
Clear-Variable files
Clear-Variable file
Clear-Variable newPath
Clear-Variable server
$machines = Get-Content "C:\Users\localadmin\Desktop\servers.txt"
$destination = '\\nprodserver1\C$\Users\localadmin\Documents'
foreach($server in $machines){
$source = "\\$server\L$\Logs\W3SVC21"
#$files = Get-ChildItem -File "\\$server\L$\Logs\W3SVC21" -Filter *.log -Recurse -Force | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-1)}
$files = Get-ChildItem -Path $source -Filter *.log -Recurse -Force | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-1)}
foreach ($file in $files) {
$newPath = Join-Path -Path "$destination" -ChildPath "$($file.BaseName)-$("$server")-$(Split-Path -Path $source -Leaf).log" #change file output format here (e.g..txt)
Copy-Item -Path $($file.FullName) -Destination $newPath
}
}

Create a folder from a file name which has 2 underscores, then place that file in the folder

I try to create a folder using PowerShell for the following files
4_2017-07-16_01-22-52.mp4
4_2017-07-16_01-23-50.mp4
4_2017-07-16_01-24-54.mp4
4_2017-07-16_01-26-21.mp4
I use this method
https://stackoverflow.com/a/41468253/13002495
the problem that it will create a directory 4 then move the files to it what I need to have a directory like the following
4_2017-07-16 or a directory like 4_2017_07_16
this is the first method.
the second method if you can help to have a script to create the following directories
2017 directory then a subdirectory 02 then subdirectory 16 then a subdirectory 4 then move the files to subdirectory 4
so it will be as following
2017
--------07
------------16
---------------------04 ----> files will be here
can you help with these 2 methods?
You could try something like this:
$folder = 'FILES_FOLDER'
Get-ChildItem -Path $folder | ForEach-Object {
$subFolders = $_.Name.Split("-_")
$path = Get-Location
$order = 1, 2, 3, 0
$order | ForEach-Object {
$path = Join-Path -Path $path -ChildPath $subFolders[$_]
if (-not (Test-Path -Path $path -PathType Container)){
New-Item -Path $path -ItemType Directory
}
}
Move-Item -Path $_.FullName -Destination $path
}
Which will move all files to:
2017/07/16/4/4_2017-07-16_01-22-52.mp4
2017/07/16/4/4_2017-07-16_01-23-50.mp4
2017/07/16/4/4_2017-07-16_01-24-54.mp4
2017/07/16/4/4_2017-07-16_01-26-21.mp4
Explanation:
Split the files on "-" and "_" with Split. Can look at about_split for more information.
Get the current folder path with Get-Location, which is used to append to the current path for making sub directories.
Create an $order array to create the correct sub folder order as shown in the question.
Iterate through this $order array and create new directories if they dont exist. Can use Test-Path to check if the sub folders exist, and New-Item to create a new directory.
Move files to final sub directory with Move-Item. These sub directories will be in your current working directory. You could obviously change this to another directory location as well.
For your first method (one destination folder with name like 4_2017_07_16), you can do:
$source = 'D:\Mp4Files' # rootfolder where the files are
$destination = 'D:\Test' # rootfolder where the files need to go
Get-ChildItem -Path $source -File -Filter '*.mp4' |
Group-Object { ($_.BaseName -replace'(\d+_[^_]+).*', '$1') } |
ForEach-Object {
$targetFolder = Join-Path -Path $destination -ChildPath $_.Name
# create this folder if it does not already exist
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
$_.Group | Move-Item -Destination $targetFolder
}
Result:
D:\TEST\4_2017-07-16
4_2017-07-16_01-22-52.mp4
4_2017-07-16_01-23-50.mp4
4_2017-07-16_01-24-54.mp4
4_2017-07-16_01-26-21.mp4
The second method creates more subfolders, based on the first part of the filenames:
$source = 'D:\Mp4Files'
$destination = 'D:\Test'
Get-ChildItem -Path $source -File -Filter '*.mp4' |
Group-Object { ($_.BaseName -replace'(\d+_[^_]+).*', '$1') } |
ForEach-Object {
$index, $year, $month, $day = $_.Name -split '[-_]'
$targetFolder = Join-Path -Path $destination -ChildPath ('{0}\{1:00}\{2:00}\{3:00}' -f $year, [int]$month, [int]$day, [int]$index)
# create this folder if it does not already exist
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
$_.Group | Move-Item -Destination $targetFolder
}
Result:
D:\TEST\2017
\---07
\---16
\---04
4_2017-07-16_01-22-52.mp4
4_2017-07-16_01-23-50.mp4
4_2017-07-16_01-24-54.mp4
4_2017-07-16_01-26-21.mp4

Folder deleting after script ends

I am currently writing a script that takes a folder of files, moves the first file to a folder with a specific name, then move the rest to another folder with a number for a name.
My script works however it also moves the folder and renames it too. Which section of the code is causing this?
$path = "C:\Users\User1\Desktop\MergeTest\_First\"
$FileCount = Get-ChildItem -Path $path -File | Measure-Object | %{$_.Count}
$FirstFile = Get-ChildItem -Path $path -Force -File | Select-Object -First 1
$FinalReport = "C:\Users\User1\Desktop\MergeTest\___Final\TestOutput.xlsx"
Move-Item "C:\Users\User1\Desktop\MergeTest\_First\$FirstFile" $FinalReport
$Counter = 0;
Write-host $FileCount
for($Counter = 0; $Counter -lt $FileCount; $Counter++)
{
$FileInWork = Get-ChildItem -Path $path -Force -File | Select-Object -First 1
move-item "C:\Users\User1\Desktop\MergeTest\_First\$FileInWork" "C:\Users\User1\Desktop\MergeTest\__Second\$Counter.xlsx"
Write-host "File Moved"
}
What you could do is specify the -Include *.txt condition to your move-item commands so it is only to move just .txt, .log, or whatever file type you're moving and leave the folder how it is.
I believe your code could do with some cleaning up. Now you are executing Get-ChildItem 3 times, where using it once is enough.
Also, you should try and use the Join-Path rather than constructing the path and filenames yourself.
Especially where you do "C:\Users\User1\Desktop\MergeTest\_First\$FileInWork", you should realize that Get-ChildItem returns FileInfo and/or DirectoryInfo objects; not strings.
Anyway, the below code should do what you want:
# define the path where all other paths are in
$rootPath = "C:\Users\User1\Desktop\MergeTest"
# create the working paths using the common root folder path
$filesPath = Join-Path -Path $rootPath -ChildPath '_First'
$firstDestination = Join-Path -Path $rootPath -ChildPath '___Final'
$secondDestination = Join-Path -Path $rootPath -ChildPath '__Second'
# test if the destination folders exist and if not create them
if (!(Test-Path -Path $firstDestination -PathType Container)) {
Write-Host "Creating folder '$firstDestination'"
$null = New-Item -Path $firstDestination -ItemType Directory
}
if (!(Test-Path -Path $secondDestination -PathType Container)) {
Write-Host "Creating folder '$secondDestination'"
$null = New-Item -Path $secondDestination -ItemType Directory
}
# get an array of all FileInfo objects in $filesPath
# you could consider adding -Filter '*.xlsx' here..
$allFiles = Get-ChildItem -Path $filesPath -Force -File
Write-Host 'Total number of files found: {0}' -f $allFiles.Count
# move the files
for ($i = 0; $i -lt $allFiles.Count; $i++) {
if ($i -eq 0) {
# the first file should go in the $firstDestination folder with specified name
$target = Join-Path -Path $firstDestination -ChildPath 'TestOutput.xlsx'
}
else {
# all other files go to the $secondDestination folder
# each file should have the index number as name
$target = Join-Path -Path $secondDestination -ChildPath ('{0}.xlsx' -f ($i + 1))
}
$allFiles[$i] | Move-Item -Destination $target -Force -WhatIf
}
Hope that helps
Remove the -WhatIf if you are satisfied with whatever the output on console shows.
P.S. I really think you should edit your question and change its title, because nothing in the question has to do with Folder deleting after script ends..

How can I move items without hardcoded variables

I want to move items with the .txt extension but not like this, hard-coded. I want to select from a folder all files with some extension and move them into a folder with the same name as extension. And I want to do that for all the extensions in the directory.
Any ideas?
Thank you!
Take a look at my code but I did it with hardcoded variables
$variable=Get-ChildItem -Path "C:\somePath"
foreach ($variables in $variable)
{
if($extension=($variables | Where {$_.extension -like ".txt"}))
{
New-Item -ItemType Directory -Path "C:\somePath\text"
$extension | Move-Item -Destination "C:\somePath\text"
}
}
Although this solution is not as clean-looking as the other solution, it does handle the case where the destination folders don't already exist. It also moves files that may contain special characters like []. It also explicitly ignores files with no extension since no requirement was given for those. The amount of looping is minimized through the use of Group-Object.
$Path = "C:\Somepath"
$files = Get-ChildItem -Path $Path -File |
Group-Object -Property {($_.extension |
Select-String -Pattern "[^. ]+").matches.value
}
Foreach ($ExtGroup in $files) {
$Destination = "$Path\$($ExtGroup.Name)"
if (!(Test-Path -Path $Destination -PathType Container)) {
$null = New-Item -Path $Destination -Type Directory
}
Move-Item -LiteralPath $ExtGroup.Group -Destination $Destination -Force
}
I believe this will do:
$variable = Get-ChildItem -Path "C:\somePath"
foreach ($v in $variable){
$dest = '{0}\{1}' -f $v.DirectoryName, ($v.Extension -replace '^\.')
$v | Move-Item -Destination $dest -Force
}

Resources