I built a script that copies files from the local C drive to a Network Drive.
I have a folder in C:\www\root called "images" or "C:\www\root\images"
The script creates a folder called "images" in the "F:\powershell_wwwroot\root_" + $TimeStamp" however the "images" directory is empty in the destination folder. The script copies everything from the C:\www\root\images\ folder to base destination folder "F:\powershell_wwwroot\root_" + $TimeStamp".
So I see everything from C:\www\root\images\ in F:\powershell_wwwroot\root_02_12_2021
however the F:\powershell_wwwroot\root_02_12_2021\images is empty. I would like to see everytying from "C:\www\root\images" in "F:\powershell_wwwroot \root_02_12_2021\images"
$TimeStamp = get-date -f dd_MM_yyyy
$Destination = "F:\powershell_wwwroot\root_" + $TimeStamp
New-Item -ItemType directory -Path $Destination -Force
gci "C:\www\root\" -recurse | %{
$file = $_.Fullname
Write-Host $file
Copy-Item -Path $file -Destination $Destination -Force
}
A ForEach-Loop for this shouldn't be needed, let Copy-Item handle it. The following should leave the Folder / File hierarchy intact.
$TimeStamp = Get-Date -Format dd_MM_yyyy
$Destination = "F:\powershell_wwwroot\root_" + $TimeStamp
New-Item -ItemType directory -Path $Destination -Force
$Source = "C:\www\root\"
Copy-Item -LiteralPath $source -Destination $destination -Recurse -Force
you can use either copy-item or bit-transfer. I wrote a script that uses the bits transfer cmdlet. If you update my script, to create the destination folder your home dry. If you have any issues regarding the script holler at me :o)
https://superuser.com/questions/1689980/start-bitstransfer-failing-to-send-files-to-remote-destination/1690801#1690801
Import-Module BitsTransfer
#Get Script Location Path
$ScriptPath = Get-Location
$ScriptPath = $ScriptPath.ToString()
$dirName=[System.IO.Path]::GetDirectoryName($ScriptPath)
#Build Source Server Location Path
#Source Server
$Sourceserver = $env:COMPUTERNAME
#Source Server Folder Path
$Sourcefolderpath = "C:\Temp"
#Switch Colon for Dollar Sign
$Sourcepath = $Sourcefolderpath.Replace(':','$')
#Build Target Folder Path
$ServerSourceFolderpathTest = "\\" + $SourceServer + "\" + $Sourcepath
#Print to screen to view path
#Write-Host $ServerSourceFolderpathTest
#Test Path
$testsourcefolderpath = Test-Path -LiteralPath $ServerSourceFolderpathTest
IF ($testsourcefolderpath -eq $False) {
Write-Host -Fore Red "Source Folder Path Cannot Be Established.
Path is - $testsourcefolderpath"
Write-Host "Script Will Exit"
Exit
} ELSE {
Write-Host -Fore Green "Source Folder Path Established.
Path Is - $testsourcefolderpath"
}
#Build Target Server Location Path
#Target Server
$Targetserver = $env:COMPUTERNAME
#Target Server Folder Path
$Targetfolderpath = "C:\Test"
#Switch Colon for Dollar Sign
$Targetpath = $Targetfolderpath.Replace(':','$')
#Build Target Folder Path
$ServerTargetFolderpathTest = "\\" + $TargetServer + "\" + $Targetpath
#Print to screen to view path
#Write-Host $ServerTargetFolderpathTest
#Test Path
$testTargetfolderpath = Test-Path -LiteralPath $ServerTargetFolderpathTest
IF ($testTargetfolderpath -eq $False) {
Write-Host -Fore Red "Target Folder Path Cannot Be Established.
Path is - $testTargetfolderpath"
Write-Host "Script Will Exit"
Exit
} ELSE {
Write-Host -Fore Green "Target Folder Path Established.
Path Is - $testTargetfolderpath"
}
#Build Source Target Paths for Bit Transfer
$SourceFolder = $ServerSourceFolderpathTest
$PreTargetFolder = $ServerTargetFolderpathTest
$Slash = "\"
$TargetFolder = $PreTargetFolder + $Slash
#Test Target Folder Path
#$TargetFolder
#Get All Text Files From Source Folder
$GetFiles = (gci $SourceFolder -Filter *.txt)
$GetFilesFileFullName = $GetFiles.FullName
#Test View All Full File Names
#$GetFilesFileFullName
ForEach($File in $GetFilesFileFullName) {
$Discript = "Backing Up $File from $Sourceserver to $Targetserver -- " + (Get-Date)
$Discript
Start-BitsTransfer -Source $File -Destination $TargetFolder -Display $Discript -Priority 'Low' -Asynchronous -WhatIf
}
Related
I'm relatively new to PowerShell and have only been doing "light" scripting to automate a few tasks at work.
Most of the time, I can Google and get the answer(s) I need, with maybe some minor tweaking/experimenting.
But I need some help with this one as I can't find the answer I'm looking so hoping someone here might be able to help me.
DETAILS:
I am provided a directory link on the network drive to either sub-folders containing ".zips" or a folder with ".zips" only.
The latter case works for my current script (will be provided further down) to do it's job but the former is where I'm struggling.
TL;DR - I need the script to go into each folder, extract each ".zip" into a "Temp" folder and then look for a "backup" image file (file type may vary) and then copy it out to the sub-folder and rename to the same as the ".zip" it was extracted from.
Again, my script works if I'm physically in the folder with the ".zip" files but not if the ".zip" files are in sub-folders as I can't get it recursively go into each folder and run the script.
EXAMPLE SETUP:
FolderA\FolderB\1.zip
FolderA\FolderB\2.zip
FolderA\FolderB\3.zip
FolderA\FolderC\1.zip
FolderA\FolderC\1.zip
FolderA\FolderC\1.zip
Script below:
#Current Directory of ".zip" files
$fileLocation = read-host "Type/Paste location of creatives"
#replace server path with drive letter
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
#change directory to the one provided
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory\*.zip"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $UnzipPath/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
I'm open to any suggestions provided or areas of improvement. If I need to completely change the code, I don't mind. Long as it works for both scenarios.
Thanks.
UPDATE
Modified script as per HAL9256's instruction:
#Current Directory of creatives
$fileLocation = read-host "Type/Paste location of creatives"
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $upzipPath/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
That did what I need to do. But how can I modify my script so it stores the backups in their respective folder? So the backups extracted from "FolderB" stay in "FolderB", etc? Is there something I can do?
UPDATE 2
Final code - Thanks to help from HAL9256:
#Current Directory of creatives
$fileLocation = read-host "Type/Paste location of creatives"
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
$DestinationDir = $ZipFile.DirectoryName.Replace($ZipFilesPath,$unzipPath)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $DestinationDir/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
When you specify the path:
#Files Location
$ZipFilesPath = "$currentDirectory\*.zip"
Then trying to get the files:
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
What you essentially are saying is Get-Childitem and get only *.zip files. Because the path parameter has the wildcard filter, it will only get all the *.zip files in that directory and will not get any folders. Since you have no folders matching the *.zip wildcard, Get-Childitem won't have any folders to continue to recurse through.
The solution is to only give a base folder to the path parameter for the Get-Childitem to recurse through, and, correctly, use the -Include to apply the filter for the type. e.g.:
#Files Location
$ZipFilesPath = "$currentDirectory"
...
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
EDIT:
To move the file to the same folder structure, when inside the loop, you simply use the replace function to replace the source Directory path (the first part of the Directory Name) with your destination base path. Then the sub folders will remain the same. e.g.
...
$DestinationDir = $ZipFile.DirectoryName.Replace($ZipFilesPath,$upzipPath)
...
$BackupFiles |% {Move-Item $_.Fullname $DestinationDir/$ZipFileActualName'_backup'.$typefilter}
I'm struggling to understand how PowerShell handles recursion and Copy-Item command.
$date=Get-Date -Format yyyyMMdd
$oldfolder="c:\certs\old\$date"
New-PSDrive -Name "B" -PSProvider FileSystem -Root "\\(server)\adconfig"
$lastwrite = (get-item b:\lcerts\domain\wc\cert.pfx).LastWriteTime
$timespan = new-timespan -days 1 -hours 1
Write-Host "testing variables..."
Write-Host " date = $date" `n "folder path to create = $oldfolder" `n
"timespan = $timespan"
if (((get-date) - $lastwrite) -gt $timespan) {
#older
Write-Host "nothing to update."
}
else {
#newer
Write-Host "newer certs available, moving certs to $oldfolder"
copy-item -path "c:\certs\wc" -recurse -destination $oldfolder
copy-item b:\lcerts\domain\wc\ c:\certs\ -recurse -force
}
Existing files exist at c:\certs\wc\cert.pfx
I have the "test" comparing the time between the cert.pfx in the b:\lcerts\domain\wc\ folder and the current time . If the cert has been modified in the past 1 day and 1 hour, then the script should continue:
Copy cert.pfx from c:\certs\wc\ to c:\certs\old\$date\cert.pfx
Copy cert.pfx from b:\lcerts\domain\wc to c:\certs\wc\cert.pfx
I obviously don't understand PowerShell nomenclature for this because the first time I run this script, it works fine. The second time it creates another folder inside c:\certs\wc\$date\wc\cert.pfx.
How do I get it to fail with "c:\certs\wc\$date\cert.pfx already exists?"
I don't want to restrict this to just the cert.pfx file by specifying the actual file name, I want all files in the folder as eventually there will be more than one file.
The behavior of Copy-Item when a directory is specified in the -Path parameter depends on whether the directory specified in the -Destination parameter exists.
Copy-Item -Path "c:\certs\wc" -Recurse -Destination "c:\certs\old\$date"
If the c:\certs\old\$date directory does not exist, then the wc directory is copied and named c:\certs\old\$date.
If the c:\certs\old\$date directory exists, the wc directory is copied under the c:\certs\old\$date directory. Therefore, it becomes c:\certs\old\$date\wc.
So you are sure to check in advance if the directory exists.
if(Test-Path $oldfolder) { throw "'$oldfolder' is already exists." }
Copy-Item -Path "c:\certs\wc" -Destination $oldfolder -Recurse
You are not testing if the destination folder exists. Seeing you are creating its name using a current date, it is more than likely this folder does not yet exist, so you need to create it first.
Also, There should be no need to use the New-PSDrive cmdlet, because Copy-Item is perfectly able to use UNC paths.
Something like this perhaps:
$server = '<NAME OF THE SERVER>'
$serverPath = "\\$server\adconfig\lcerts\domain\wc"
$testFile = Join-Path -Path $serverPath -ChildPath 'cert.pfx'
$localPath = 'c:\certs\wc'
$date = Get-Date -Format yyyyMMdd
$timespan = New-TimeSpan -Hours 1 -Minutes 1
$oldfolder = "c:\certs\old\$date"
# check if this output path exists. If not, create it
if (!(Test-Path -Path $oldfolder -PathType Container)) {
Write-Host "Creating folder '$oldfolder'"
New-Item -ItemType Directory -Path $oldfolder | Out-Null
}
Write-Host "testing variables..."
Write-Host "date = $date`r`nfolder path to create = $oldfolder`r`ntimespan = $timespan"
# test the LastWriteTime property from the cert.pfx file on the server
$lastwrite = (Get-Item $testFile).LastWriteTime
if (((Get-Date) - $lastwrite) -gt $timespan) {
#older
Write-Host "Nothing to update."
}
else {
#newer
Write-Host "Newer cert(s) available; copying all from '$localPath' to '$oldfolder'"
Copy-Item -Path $localPath -Filter '*.pfx' -Destination $oldfolder
Copy-Item -Path $serverPath -Filter '*.pfx' -Destination $localPath -Force
}
I have created a script to copy the folder/sub folders/files from a specific location to a list of servers that I specified on a notepad.
It checks that if the folder has not been created, it will create it and copy over the files, but if the folder has already been created - then it stops.
However, I would like to still copy over newer files even if that folder has already been created, albeit with no subfolders or files in there.
My current code
[String] $KfxComputers = "C:\temp\Kofax Apps\servers.txt"
# This file contains the list of servers you want to copy files/folders to
$computers = get-content -Path $KfxComputers
# the folder you want to copy to the servers in the $computer variable
$sourceRoot = #("\\wdevkofx110\Kofax Software\Oracle Clients",
"\\wdevkofx110\Kofax Software\Kofax Capture 11")
# the destination location you want the file/folder(s) to be copied to
$destinationRoot = "C$\temp"
foreach ($computer in $computers) {
$testpath = Test-Path -Path \\$computer\$destinationRoot
if (!$testpath)
{
Write-Host "creating folder and copying files..." -ForegroundColor green
New-Item -ItemType Directory -Force -Path "\\$computer\$destinationRoot"
copy-item -Path $sourceRoot -Recurse -Destination
"\\$computer\$destinationRoot" -Container
} else {
Write-Host "$computer\$destinationRoot folder already exists"
}
}`
You can use Else IF
[String] $KfxComputers = "C:\temp\Kofax Apps\servers.txt"
# This file contains the list of servers you want to copy files/folders to
$computers = get-content -Path $KfxComputers
# the folder you want to copy to the servers in the $computer variable
$sourceRoot = #("\\wdevkofx110\Kofax Software\Oracle Clients",
"\\wdevkofx110\Kofax Software\Kofax Capture 11")
# the destination location you want the file/folder(s) to be copied to
$destinationRoot = "C$\temp"
foreach ($computer in $computers) {
$testpath = Test-Path -Path \\$computer\$destinationRoot
if (!$testpath)
{
Write-Host "creating folder and copying files..." -ForegroundColor green
New-Item -ItemType Directory -Force -Path "\\$computer\$destinationRoot"
copy-item -Path $sourceRoot -Destination
"\\$computer\$destinationRoot" -Container -Recurse -force
}
ElseIF ($testpath) {
Write-Host "folder already exists, copying files..." -ForegroundColor green
copy-item -Path $sourceRoot -Destination
"\\$computer\$destinationRoot" -Container -Recurse -force
}
else {
Write-Host "$computer\$destinationRoot folder already exists"
}
}`
I'm trying to copy files to a specific folder based on a file name.
For example:
Current Folder - C:\Stuff\Old Files\
The File- 206.Little Rock.map.pdf
Destination Folder - D:\Cleanup\206\Repository
So basically the leading number on the file (206) is part of the subfolder. The "\Repository" would stay constant. Only the leading number would change.
If the file was 207.Little Rock.map.pdf then the destination folder would be
D:\Cleanup\207\Repository
I started with a code I got from here but I'm not sure how to account for the change in number and how to make it create a folder if the folder doesn't exist. So 206\Repository would probably already exist, but I would need the script to create the folder if it doesn't.
$SourceFolder = "C:\Stuff\Old Files\"
$targetFolder = "D:\Cleanup\"
$numFiles = (Get-ChildItem -Path $SourceFolder -Filter *.pdf).Count
$i=0
clear-host;
Write-Host 'This script will copy ' $numFiles ' files from ' $SourceFolder ' to ' $targetFolder
Read-host -prompt 'Press enter to start copying the files'
Get-ChildItem -Path $SourceFolder -Filter *.PDF | %{
[System.IO.FileInfo]$destination = (Join-Path -Path $targetFolder -ChildPath $Name.Repository(".*","\"))
if(!(Test-Path -Path $destination.Directory )){
New-item -Path $destination.Directory.FullName -ItemType Directory
}
[int]$percent = $i / $numFiles * 100
copy-item -Path $_.FullName -Destination $Destination.FullName
Write-Progress -Activity "Copying ... ($percent %)" -status $_ -PercentComplete $percent -verbose
$i++
}
Write-Host 'Total number of files read from directory '$SourceFolder ' is ' $numFiles
Write-Host 'Total number of files that was copied to '$targetFolder ' is ' $i
Read-host -prompt "Press enter to complete..."
clear-host;
This should do mostly what you need. You might have to tweak the destination path a bit, but that should be fairly straight forward to figure out. I Highly recommend that use a '-' as the delimiter for your file prefix as opposed to a '.' as this will prevent accidentally moving EVERY FILE in a directory if you happen to execute it in the wrong place.
Also, when you write a script, do create functions to do individual units of work, and then call those functions at the end. It's much easier to modify, and debug that way.
<#
.SYNOPSIS
Moves files from source to destination based on FileName
Creates destination folder if it does not exist.
.DESCIPTION
The script expects files with a prefix defined by a hyphen '-' i.e. 200-<filename>.<ext>.
There is no filename validation in this script; it will *probably* skip files without a prefix.
A folder based on the prefix will be created in the destination.
If your file is name string-cheese.txt then it will be moved to $DestinationIn\string\string-cheese.txt
.PARAMETER SourceIn
Source Path (folder) where your files exist.
.PARAMETER DestinationIn
Target Path (folder) where you want your files to go.
.EXAMPLE
& .\CleanUp-Files.ps1 -SourceIn "C:\Users\User\Documents\Files\" -DestinationIn "C:\Users\User\Documents\Backup\" -Verbose
.NOTES
Author: RepeatDaily
Email: RepeatedDaily#gmail.com
This script is provided as is, and will probably work as intended. Good Luck!
https://stackoverflow.com/questions/50662140/copy-file-based-a-specified-folder-based-on-file-name-create-folder-if-it-doesn
#>
[CmdletBinding()]
param (
[string]$SourceIn,
[string]$DestinationIn
)
function Set-DestinationPath {
param (
[string]$FileName,
[string]$Target
)
[string]$NewParentFolderName = $FileName.SubString(0,$FileName.IndexOf('-'))
[string]$DestinationPath = Join-Path -Path $Target -ChildPath $NewParentFolderName
return $DestinationPath
}
function Create-DestinationPath {
[CmdletBinding()]
param (
[string]$Target
)
if (-not(Test-Path -Path $Target)) {
Try {
New-Item -ItemType Directory -Path $Target | Write-Verbose
}
catch {
Write-Error $Error[0];
}
}
else {
Write-Verbose "$Target exists"
}
}
function Move-MyFiles {
[CmdletBinding()]
param (
[string]$Source,
[string]$Destination
)
[array]$FileList = Get-ChildItem $Source -File | Select-Object -ExpandProperty 'Name'
foreach ($file in $FileList) {
[string]$DestinationPath = Set-DestinationPath -FileName $file -Target $Destination
Create-DestinationPath -Target $DestinationPath
try {
Move-Item -Path (Join-Path -Path $Source -ChildPath $file) -Destination $DestinationPath | Write-Verbose
}
catch {
Write-Warning $Error[0]
}
}
}
Move-MyFiles -Source $SourceIn -Destination $DestinationIn
Here is something you might try. The number for the directory is grabbed from a regex match, "(\d+)\..*.pdf". When you are confident that the correct file copies will be made, remove the -WhatIf from the Copy-Item cmdlet.
I did not try to address the Write-Progress capability. Also, this will only copy .pdf files that begin with digits followed by a FULL STOP (period) character.
I do not fully understand the need for all of the Write-Host and Read-Host usage. It is not very PowerShell. pwshic
$SourceFolder = 'C:/src/t/copymaps'
$targetFolder = 'C:/src/t/copymaps/base'
$i = 0
$numFiles = (
Get-ChildItem -File -Path $SourceFolder -Filter "*.pdf" |
Where-Object -FilterScript { $_.Name -match "(\d+)\..*.pdf" } |
Measure-Object).Count
clear-host;
Write-Host 'This script will copy ' $numFiles ' files from ' $SourceFolder ' to ' $targetFolder
Read-host -prompt 'Press enter to start copying the files'
Get-ChildItem -File -Path $SourceFolder -Filter "*.pdf" |
Where-Object -FilterScript { $_.Name -match "(\d+)\..*.pdf" } |
ForEach-Object {
$NumberDir = Join-Path -Path $targetFolder -ChildPath $Matches[1]
$NumberDir = Join-Path -Path $NumberDir -ChildPath 'Repository'
if (-not (Test-Path $NumberDir)) {
New-Item -ItemType Directory -Path $NumberDir
}
Copy-Item -Path $_.FullName -Destination $NumberDir -Whatif
$i++
}
Write-Host 'Total number of files read from directory '$SourceFolder ' is ' $numFiles
Write-Host 'Total number of files that was copied to '$targetFolder ' is ' $i
Read-host -prompt "Press enter to complete..."
clear-host;
The basic idea:
Mirror the directory structure of the target path
Search the target path for files and folders of a certain age and create a text file with all the paths.
Read the previous text file and copy the contents of the different paths to a new drive location.
Script 1 - Mirror the directory structure of the target path from drive to the next. This I feel like I have working pretty decently.
$target = Read-Host "What is the target path?"
$destination = "Z:\This\Is\The\Destination"
Copy-Item $target -Filter {PSIsContainter} -Recurse -Destination $destination -Force
Script 2 - Is used to look through the $target path and looks for files and folders that are -ge -le -eq a lastwritetime, then outputs the locations in a text file.
$path = read-host "What path would you like to search?"
$daysOLD = read-host "How many days old should the files I'm looking for be?"
$outfile = "C:\locationOFtheTEXTfile\ReadThis.txt"
$today = Get-Date
$targetdate = $today.AddDays(-$daysOLD).ToString('MM-dd-yyyy')
$files = Get-ChildItem $path -Recurse| Where-Object {$_.lastwritetime.ToString('MM-dd-yyyy') -le $targetdate} | ForEach-Object {$_.fullname}| out-file $outfile
Script 3 - Is where I am having an issue. I know that I can use Get-Content and point to the location of the text file. What I have a hard time with is having the script read the file, test the path, and not create duplicates in the $destination.
Since I mirrored the directory structure with the first path, I just need the third script to move files to their appropriate folders on the new drive.
$dest = "Z:\This\Is\The\Destination"
$safe = Get-Content "C:\locationOFtheTEXTfile\ReadThis.txt"
$safe | ForEach-Object{
#find drive-delimeter
$first=$_.IndexOf(":\");
if($first -eq 1){
#stripe it
$newdes=Join-Path -Path $dest -ChildPath #($_.Substring(0,1)+$_.Substring(2))[0]
} else {
$newdes=Join-Path -Path $des -ChildPath $_
}
$folder = Split-Path -Path $newdes -Parent
$err=0
#check if folder exists"
$void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue
if($err.Count -ne 0){
#create when it doesn't
$void=New-Item -Path $folder -ItemType Directory -Force -Verbose
}
$void=Copy-Item -Path $_ -destination $newdes -Recurse -Container -Force -Verbose
}
write-host "Doomsday =("
This script was taken from the web and I haven't had a chance to figure it's parts and pieces for myself. I know that sound pathetic but I don't feel like trying to reinvent the wheel is necessary.