powershell Copying files into new directories - best way - powershell

I'm using this answer to try to copy files to a new location using a .csv list where OldName is the current file name and NewName is the new name including filepath.
What is the best way to force the script to generate a new folder according to the new path?
For example:
OldName NewName
A.pdf C:\NewFolder\Anew.pdf
This is my script
$Copies = Import-Csv '.\copies.csv' -Header "OldName","NewName"
foreach($File in $Copies) {
New-Item -Force $File.NewName -Type File
Copy-Item $File.OldName $File.NewName
}
But this overwrites any files that stay in the same folder before they get copied.

Replace the line where you create the directory:
New-Item -Force $File.NewName -Type File
With this:
$NewDir = ($File.NewName -as [System.IO.FileInfo]).DirectoryName
If (-not (Test-Path -Path $NewDir)) {
New-Item -ItemType Directory -Path $NewDir -Force | Out-Null
}

Related

powershell Script for moving specific files from a folder based on a filename.txt

I have a folder that contains 2000+ Jpeg images
I want to copy some images from this folder to another folder based on the filename that I have in sort.txt file.
I have a filename in text format. how this can be done?
Source is E:\SORT\RUSH
Destination is E:\SORT\SORTED
filename list is E:\sort.txt
$file_list = Get-Content E:\sort.txt
foreach ($file in $file_list) {
$subf = $file.Split('-')[0]
$source = "E:\SORT\RUSH"
Copy-Item $source E:\SORT\SORTED -WhatIf
}
Ok, so now we know the input textfile only contains file BaseNames (no extension), you need to check if such a file can be found in the $source directory.
Try
$source = 'E:\SORT\RUSH'
$destination = 'E:\SORT\SORTED'
# first, make sure the destination folder exists
$null = New-Item -Path $destination -ItemType Directory -Force
# make sure no duplicates are in the text file
$file_list = Get-Content -Path 'E:\sort.tx' | Select-Object -Unique
foreach ($file in $file_list) {
# create the full path and filename for the file to copy
$sourceFile = Join-Path -Path $source -ChildPath "$file.jpg"
# if the file can be found, copy it
if (Test-Path -Path $sourceFile -PathType Leaf) {
Copy-Item -Path $sourceFile -Destination $destination
}
else {
Write-Warning "Could not find file '$sourceFile'"
}
}

Create multiple directories in different folders

I want to create one folder for each preselected *.mkv-file in the corresponding subfolder, named after that *.mkv-file, e.g.:
Z:\1\1.mkv; Z:\2\2.mp4; Z:\3\3.mkv --> Z:\1\1 (additional folder);
Z:\1\1.mkv; Z:\2\2.mp4; Z:\3\3 (additional folder); Z:\3\3.mkv
$inputfiles = gci *.mkv -recurse
foreach ($file in $inputfiles)
{
new-item -path Z:\* -name "$($file.BaseName)" -itemtype directory
}
Problem here is, that in each subfolder all of the directories are created, not just the corresponding one.
I also tried -path $inputfiles but got an error message.
Any help is appreciated
The main problem is that you have added \* after the path for the New-Item.
Try:
Get-ChildItem -Filter '*.mkv' -File -Recurse | ForEach-Object {
# construct the path for the (new) subfolder
$targetFolder = Join-Path -Path 'Z:\' -ChildPath $_.BaseName
# create a new directory if not already existed
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# if you want the .mkv file to be moved to that new directory, uncomment the line below
# $_ | Move-Item -Destination $targetFolder
}
The -Force switch on the New-Item line ensures it either creates a new directory or returns the folder object of an existing one without error messages.

A PowerShell script to move files to a folder based on their names?

I have a folder c:\test with files:
Raport-en-us-Country1.xlsx
Raport-en-us-Country2.xlsx
Raport-en-us-Country3.xlsx
etc.
and I want to
create folders based on the last part of the file name
move files to the new folders
if the file already exist the old file should be overwritten
Example: c:\test\Raport-en-us-Country1.xlsx should go to c:\test\Country1\Raport-en-us-Country1.xlsx.
Can anyone help me to create a PowerShell script for this, please?
I have this code, it creates the folder/s but it doesn't move the files:
# 1. Get a list of files in the c:\test folder
$FileList = Get-ChildItem -Path c:\test;
# 2. Parse file names, create folder structure, and move files
foreach ($File in $FileList) {
$File.Name -match '(?<folder>.*?)(?:-)(?<subfolder>\w{2})(?:-)(?<filename>.*)';
if ($matches) {
$Destination = 'c:\test\{0}\{1}\{2}' -f $matches.folder, $matches.subfolder, $matches.filename;
mkdir -Path (Split-Path -Path $Destination -Parent) -ErrorAction SilentlyContinue;
Move-Item -Path $File.FullName -Destination $Destination -WhatIf;
}
$matches = $null
}

copying files from recycle bin

Here (Listing files in recycle bin) I've found a #Smile4ever post saying how to get the original location for the files in recycle bin:
(New-Object -ComObject Shell.Application).NameSpace(0x0a).Items()
|select #{n="OriginalLocation";e={$_.ExtendedProperty("{9B174B33-40FF-11D2-A27E-00C04FC30871} 2")}},Name
| export-csv -delimiter "\" -path C:\Users\UserName\Desktop\recycleBinFiles.txt -NoTypeInformation
(gc C:\Users\UserName\Desktop\recycleBinFiles.txt | select -Skip 1)
| % {$_.Replace('"','')}
| set-content C:\Users\UserName\Desktop\recycleBinFiles.txt
I'd like to copy them somewhere (in case I've been told that some of them were not to be deleted and someone empty recycle bin).
Here (https://superuser.com/questions/715673/batch-script-move-files-from-windows-recycle-bin) I've found a #gm2 post for copying them
$shell = New-Object -ComObject Shell.Application
$recycleBin = $shell.Namespace(0xA) #Recycle Bin
$recycleBin.Items() | %{Copy-Item $_.Path ("C:\Temp\{0}" -f $_.Name)}
And they work fine, but I'd need something more.
I don't know anything about powershell, but what I'd like to do would be:
for each file in Recycle bin to create its original location folder in the backup folder C:\Temp and to copy the file there (so I won't have the problem of more files with the same name).
And then to zip that C:\Temp.
Is there a way foir doing it?
Thanks!
You should be able to do it like this:
# Set a folder path INSIDE the C:\Temp folder to collect the files and folders
$outputPath = 'C:\Temp\RecycleBackup'
# afterwards, a zip file is created in 'C:\Temp' with filename 'RecycleBackup.zip'
$shell = New-Object -ComObject Shell.Application
$recycleBin = $shell.Namespace(0xA)
$recycleBin.Items() | ForEach-Object {
# see https://learn.microsoft.com/en-us/windows/win32/shell/shellfolderitem-extendedproperty
$originalPath = $_.ExtendedProperty("{9B174B33-40FF-11D2-A27E-00C04FC30871} 2")
# get the root disk from that original path
$originalRoot = [System.IO.Path]::GetPathRoot($originalPath)
# remove the root from the OriginalPath
$newPath = $originalPath.Substring($originalRoot.Length)
# change/remove the : and \ characters in the root for output
if ($originalRoot -like '?:\*') {
# a local path. X:\ --> X
$newRoot = $originalRoot.Substring(0,1)
}
else {
# UNC path. \\server\share --> server_share
$newRoot = $originalRoot.Trim("\") -replace '\\', '_'
#"\"# you can remove this dummy comment to restore syntax highlighting in SO
}
$newPath = Join-Path -Path $outputPath -ChildPath "$newRoot\$newPath"
# if this new path does not exist yet, create it
if (!(Test-Path -Path $newPath -PathType Container)) {
New-Item -Path $newPath -ItemType Directory | Out-Null
}
# copy the file or folder with its original name to the new output path
Copy-Item -Path $_.Path -Destination (Join-Path -Path $newPath -ChildPath $_.Name) -Force -Recurse
}
# clean up the Com object when done
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
$shell = $null
The following code needs PowerShell version 5
# finally, create a zip file of this RecycleBackup folder and everything in it.
# append a '\*' to the $outputPath variable to enable recursing the folder
$zipPath = Join-Path -Path $outputPath -ChildPath '*'
$zipFile = '{0}.zip' -f $outputPath.TrimEnd("\")
#"\"# you can remove this dummy comment to restore syntax highlighting in SO
# remove the zip file if it already exists
if(Test-Path $zipFile -PathType Leaf) { Remove-item $zipFile -Force }
Compress-Archive -Path $zipPath -CompressionLevel Optimal -DestinationPath $zipFile -Force
To create a zip file in PowerShell below version 5
If you do not have PowerShell 5 or up, the Compress-Archive is not available.
To create a zip file from the C:\Temp\RecycleBackup you can do this instead:
$zipFile = '{0}.zip' -f $outputPath.TrimEnd("\")
#"\"# you can remove this dummy comment to restore syntax highlighting in SO
# remove the zip file if it already exists
if(Test-Path $zipFile -PathType Leaf) { Remove-item $zipFile -Force }
Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
[System.IO.Compression.ZipFile]::CreateFromDirectory($outputPath, $zipFile)
Of course, you can also use a third party software like 7Zip for this. There are plenty of examples on the net how to use that in Powershell like for instance here
As per your last request to remove the 'RecycleBackup' folder after the zip is created
Remove-Item -Path $outputPath -Recurse -Force
Hope that helps

How to create multiple subfolders?

How do I create a folder structure where I have one root folder, then approximately 9 differently named subfolders; within these subfolders there another set of differently named subfolders. I have already made one .csv file with the script. But I do not feel like writing out 30 lines of the same code to make these subfolders.
Here is what I have so far:
$LogsDir = "D:\Logs"
If (-Not (Test-Path $LogsDir)) {
New-Item -Path $LogsDir -ItemType Directory | Out-Null
} Else {
Write-Host "Directory already exists!"
}
$Subfolders1 = Import-Csv "Subfolders1.csv";
$Subfolders1 | Where-Object {$_.Type -eq 'Subfolder'} |
ForEach-Object {
$Subfolders1 = $_.Name;
New-Item "$LogsDir\$Subfolders1" -ItemType Directory
}
# ******sbf1 = the first set of subfolders******
# ******sf-** = the second set******
New-Item -Path "$LogsDir\sbf1\sf-a1" -ItemType Directory
New-Item -Path "$LogsDir\sbf1\sf-a2" -ItemType Directory
New-Item -Path "$LogsDir\sbf1\sf-a3" -ItemType Directory
New-Item -Path "$LogsDir\sbf2\sf-a1" -ItemType Directory
New-Item -Path "$LogsDir\sbf2\sf-a2" -ItemType Directory
New-Item -Path "$LogsDir\sbf2\sf-b2" -ItemType Directory
I am trying to create a log file folder tree. I think I got some of it down but any help would appreciated.
New-Item will create missing parent folders, so you only need a list of the leaf folders (with full path):
D:\Logs\sbf1\sf-a1
D:\Logs\sbf1\sf-a2
D:\Logs\sbf1\sf-a3
D:\Logs\sbf2\sf-a1
D:\Logs\sbf2\sf-a2
D:\Logs\sbf2\sf-b2
and then create the folders like this:
Get-Content 'C:\path\to\subfolders.txt' | % {
New-Item -Type Directory -Path $_
}