I have
\\192.168.1.2\Video\PodCasts\MyPodcast S01E01.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S01E02.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S01E02.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S02E01.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S02E02.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S02E03.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S03E01.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S03E02.mp4
\\192.168.1.2\Video\PodCasts\MyPodcast S03E03.mp4
I want to create
\\192.168.1.2\Video\PodCasts\Podcasts S01
\\192.168.1.2\Video\PodCasts\Podcasts S02
\\192.168.1.2\Video\PodCasts\Podcasts S03
And I have a PS Script to create the folders and move the files within it..
I have so far
$Show = Read-Host "Show"
cd "\\192.168.1.90\video\$Show"
Get-ChildItem -Filter "$Show S*.*" -File | ForEach-Object {
$series = $_.Name -replace '.*(S\d{2}).*', '$1'
# create the target path inside the same directory and create if needed
$destination = Join-Path -Path $_.DirectoryName -ChildPath $series
if (!(Test-Path -Path $destination -PathType Container)) {
$null = New-Item -Path $destination -ItemType Directory
}
# move the file to the new path
$_ | Move-Item -Destination $destination -Force
}
This works
\192.168.1.2\Video\PodCasts\S01\MyPodcast S01E01.mp4
I would like to adjust to do
\192.168.1.2\Video\PodCasts\MyPodcast S01\MyPodcast S01E01.mp4
I dont see where in $destination to adjust it
Your code can be simplyfied by getting the list of files in the shared directory \\192.168.1.2\PodCasts and looping through them in a ForEach-Object loop.
Then, get the series number S01, S02 etc. from the file's name, create a folder in the shared directory \\192.168.1.2\PodCasts with that series name and move the file there:
Get-ChildItem -Path '\\192.168.1.2\PodCasts' -Filter 'MyPodcast S*.mp4' -File | ForEach-Object {
$series = $_.Name -replace '.*(S\d{2}).*', '$1'
# or do something like this: $series = ($_.BaseName -split ' ',2)[1].Substring(0,3)
# create the target path inside the same PodCasts directory and create if needed
$destination = Join-Path -Path $_.DirectoryName -ChildPath $series
if (!(Test-Path -Path $destination -PathType Container)) {
$null = New-Item -Path $destination -ItemType Directory
}
# move the file to the new path
$_ | Move-Item -Destination $destination -Force
}
Before:
\\192.168.1.2\PODCASTS
MyPodcast S01E01.mp4
MyPodcast S01E02.mp4
MyPodcast S02E01.mp4
MyPodcast S02E02.mp4
MyPodcast S02E03.mp4
MyPodcast S03E01.mp4
MyPodcast S03E02.mp4
MyPodcast S03E03.mp4
After:
\\192.168.1.2\PODCASTS
+---S01
| MyPodcast S01E01.mp4
| MyPodcast S01E02.mp4
|
+---S02
| MyPodcast S02E01.mp4
| MyPodcast S02E02.mp4
| MyPodcast S02E03.mp4
|
\---S03
MyPodcast S03E01.mp4
MyPodcast S03E02.mp4
MyPodcast S03E03.mp4
P.S. In your example filelist, file 'MyPodcast S01E02.mp4' is doubled
Firstly, never run destructive (New, create, rename, move, delete, update, clear...) code without a validation step.
Is this what you are after?
Clear-Host
#(
'D:\PodCasts\MyPodcast S01E01.mp4',
'D:\PodCasts\MyPodcast S01E02.mp4',
'D:\PodCasts\MyPodcast S01E02.mp4',
'D:\PodCasts\MyPodcast S02E01.mp4',
'D:\PodCasts\MyPodcast S02E02.mp4',
'D:\PodCasts\MyPodcast S02E03.mp4',
'D:\PodCasts\MyPodcast S03E01.mp4',
'D:\PodCasts\MyPodcast S03E02.mp4',
'D:\PodCasts\MyPodcast S03E03.mp4'
) |
ForEach {
$SourceFolder = [regex]::matches($PSItem, '.*\\PodCasts').Value
$DestinationFolder = [regex]::matches($PSItem, 'S0\d').Value
If (Test-Path -Path "$SourceFolder\$DestinationFolder")
{
Write-Verbose -Message "Processing $SourceFolder\$DestinationFolder" -verbose
Move-Item -Path $PSItem -Destination $destinationFolder -WhatIf
}
Else
{
Write-Warning -Message "
Attempt to move a file to nonexistent folder, failed.
Creating the resource: $SourceFolder\$DestinationFolder
"
New-Item $DestinationFolder -ItemType Directory -WhatIf
Move-Item -Path $PSItem -Destination $destinationFolder -WhatIf
}
}
# Results
<#
WARNING:
Attempt to move a file to nonexistent folder, failed.
Creating the resource: D:\PodCasts\S01
What if: Performing the operation "Create Directory" on target "Destination: D:\Scripts\S01".
What if: Performing the operation "Move File" on target "Item: D:\PodCasts\MyPodcast S01E01.mp4 Destination: D:\Scripts\S01".
...
#>
If the folder already exists
# Results
<#
VERBOSE: Processing D:\PodCasts\S01
What if: Performing the operation "Move File" on target "Item: D:\PodCasts\MyPodcast S01E01.mp4 Destination: D:\Scripts\S01".
VERBOSE: Processing D:\PodCasts\S01
What if: Performing the operation "Move File" on target "Item: D:\PodCasts\MyPodcast S01E02.mp4 Destination: D:\Scripts\S01".
...
WARNING:
Attempt to move a file to nonexistent folder, failed.
Creating the resource: D:\PodCasts\S02
What if: Performing the operation "Create Directory" on target "Destination: D:\Scripts\S02".
What if: Performing the operation "Move File" on target "Item: D:\PodCasts\MyPodcast S02E01.mp4 Destination: D:\Scripts\S02".
#>
Related
This is my first post to Stack Overflow, and I avoided asking for help and tried to figure this out as much as I could on my own. I have very little scripting experience, but I'm looking to learn. I chose this project as a place to start, and felt like my goals for this script got out of hand rather quickly.
What I have is a functional, probably very bloated, script, that only does a fraction of what I wanted it to do for me.
Here is the task I have, that before we were doing 100% by hand - manually file by file:
I have MP3 files of high importance that need to get copied off of an SD card and eventually moved to a shared drive that is backed up regularly.
These files are in the file name format of MMDDYYYYHHMMSS_RC-700R.mp3
We store these files on our data share in its own directory, organized further by the month, leading me try to add that in as part of my script, but it is a less important feature.
My goal was to safely move these files off of the SD card, rename them - removing the TIME of the file, but if there were 2 (or more) files made on the same date to append an alphabetical iterative count up. I tried to comment out every step, not only for others to read, but to keep myself apprised of what I was trying to accomplish in each section of the code.
#Start by Clearing Host and Saving Transcript
Clear-Host
$date = Get-Date -Format 'dddd MM-dd-yyyy'
Start-Transcript -Path "F:\Script$date.txt" -NoClobber -Append
#Set locations - SD Card:Import
$Import = "C:\Users\Death\Desktop\Minutes"
$Source = "F:\Minutes\"
$Destination = "F:\Final\"
#Test if $Source Exists, if not Create directory for Files to be transferred to
if(!(Test-Path -Path $Source)) {
New-Item -ItemType directory -Path $Source
Write-Host "Folder path has been created successfully at: " $Source
}
else {
Write-Host "The given folder path $Source already exists";
}
#Test if $Destination exists and create if false
if(!(Test-Path -Path $Destination)) {
New-Item -ItemType directory -Path $Destination
Write-Host "Folder path has been created successfully at: $Destination "}
else {
Write-Host "The given folder path $Destination already exists";
}
#Copy Items from $Import location
Get-ChildItem -Path $Import -Filter *.mp3 | Copy-Item -Destination $Source
#Rename Files adding Dashes between MM DD YYYY and HHMMSS
Get-ChildItem -Path $Source -Filter *.mp3 | Rename-Item -NewName {$_.Name -Replace ('^\n*(\d{2})(\d{2})(\d{4})(\d{6}).(?:...)(\d{3})\w','TC $1-$2-$3-$4')}
#Move files into $Destination\Year\Month created - Need to add
#Move files into $NewPath\Year\Month created
#Running in to problems with moving the files after they have been renamed - Likely due to
Get-ChildItem -File -Path $Source -Filter '*.mp3' |
ForEach-Object {
$Year = $_.LastWriteTime.Year
$Month = $_.LastWriteTime.Month
$Monthname = (Get-Culture).DateTimeFormat.GetMonthName($Month)
$ArchDir = "$Destination\$Year\$Monthname\"
if (-not (Test-Path -Path $ArchDir)) { New-Item -ItemType "directory" -Path $ArchDir | Out-Null }
Move-Item -Path $Source\*.mp3 -Destination $ArchDir -Verbose
}
#Would like to add a list of files renamed and where they moved to instead of just Enter to exit
Read-Host -Prompt "Press Enter to exit"
I have had little parts of my goals working in other versions of this code, but this is my most functional one.
Problems that currently exist:
I haven't figured out how to safely iterate files created on the same day when renaming files and leaving off the TIME - So as it is currently functioning I have it leaving the TIME on the file and I am manually removing it and adding any letters when needed
It is throwing all of the files in to $Destination in the Month of the first file, and putting all the files in there (not a huge issue as this was extra)
I would like it to list every move operation as well as any errors. It is doing this now with the $Source & $Destination folders & the -Verbose on the final GCI - Move operation.
Until I demonstrate that the script is 100% functional I have all locations in the script on my local machine to keep my boss happy.
I am sorry for the wall of text & Thanks in advance for any assistance.
This looks way over-complicated.
For the file parts, it could be as simple as this...
As per your stated use case:
My goal was to safely move these files off of the SD card,
rename them - removing the TIME of the file,
Clear-Host
$SourcePath = 'C:\Temp'
$TargetPath = 'C:\Temp\TempChild'
Get-ChildItem -Path $SourcePath -Filter '*.mp3' |
ForEach {
$FileName = $PSItem
Try
{
If ((Get-Item -Path "$TargetPath\$($FileName.Name)" -ErrorAction Stop))
{
Rename-Item -Path "$TargetPath\$($PSItem.Name)" -NewName "$($FileName.Name -replace '\d+_')" -WhatIf
Move-Item -Path $FileName.FullName -Destination $TargetPath -WhatIf
}
}
Catch {Move-Item -Path $FileName.FullName -Destination $TargetPath -WhatIf}
}
# Results
<#
# When the file does not exists
What if: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3".
# When the file exists
What if: Performing the operation "Rename File" on target "Item: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\RC-M1234R.mp3".
What if: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3".
#>
You can create new paths, without using New-Item. Just use the -Force switch/parameter on the copy/move action.
Test-Path -Path "$TargetPath\test1"
# Results
<#
False
#>
Get-ChildItem -Path $SourcePath -Filter '*.mp3' |
Copy-Item -Destination "$TargetPath\test1" -Force -WhatIf
# Results
<#
What if: Performing the operation "Copy File" on target "Item: C:\Temp\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\test1".
#>
Get-ChildItem -Path $SourcePath -Filter '*.mp3' |
Copy-Item -Destination "$TargetPath\test1" -Force
Test-Path -Path "$TargetPath\test1"
Get-ChildItem -Path $TargetPath -Filter '*.mp3'
# Results
<#
True
Directory: C:\Temp\TempChild
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/8/2021 6:04 PM 39 04122021143000_RC-M12345R.mp3
-a---- 4/8/2021 6:04 PM 39 04122021143000_RC-M1234R.mp3
#>
As for
but if there were 2 (or more) files made on the same date to append an alphabetical iterative count up.
I am not sure why you use alpha vs numeric. Since alpha would limit you to 26 letters before you'd end up having to double that string. Numeric of course, you can just look at the number and increment by 1.
Here's what I mean, just using your file name vs file properties. Yet, you can do the same approach, by looking at the file properties in the mix.
Clear-Host
$SourcePath = 'C:\Temp'
$TargetPath = 'C:\Temp\TempChild'
Get-ChildItem -Path $SourcePath -Filter '*.mp3' |
ForEach {
$FileName = $PSItem
Try
{
If (
-Not ((Get-ChildItem -Path $TargetPath -Filter $FileName.Name) -match "(?<=RC-M\d+R\d)") -and
($FileName.Name -replace '_\.*') -match
((Get-ChildItem -Path $TargetPath -Filter $FileName.Name) -replace '_\.*')
)
{
Rename-Item -Path "$TargetPath\$($FileName.Name)" -NewName "$(
$FileName.Name -replace 'R\.', 'R1.'
)" -ErrorAction Stop -WhatIf
Move-Item -Path $FileName.FullName -Destination $TargetPath -Verbose -WhatIf
}
}
Catch
{
$FileToIncrement = (
Get-ChildItem -Path $TargetPath |
Where-Object -Property Name -Match ($FileName.BaseName -replace 'R\d+')
).FullName
if($FileToIncrement -match "(?<=RC-M\d+R)(?<bv>\d+)")
{
Rename-Item -Path $FileToIncrement -NewName (
$FileToIncrement -replace "(?<=RC-M\d+R)(\d+)",
("{0:0000}" -f (([int]::Parse($matches.bv)+1)))
) -Verbose -WhatIf
Move-Item -Path $FileName.FullName -Destination $TargetPath -Verbose -WhatIf
}
}
}
# Results - when incrementer does not exist for the matched time string
<#
VERBOSE: Performing the operation "Rename File" on target "Item: C:\Temp\TempChild\04122021143000_RC-M12345R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M12345R1.mp3".
VERBOSE: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M12345R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M12345R.mp3".
VERBOSE: Performing the operation "Rename File" on target "Item: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R1.mp3".
VERBOSE: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3".
#>
# Results - when incrementer exists for the matched time string
<#
What if: Performing the operation "Rename File" on target "Item: C:\Temp\TempChild\04122021143000_RC-M12345R1.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M12345R0002.mp3".
What if: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M12345R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M12345R.mp3".
What if: Performing the operation "Rename File" on target "Item: C:\Temp\TempChild\04122021143000_RC-M1234R1.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R0002.mp3".
What if: Performing the operation "Move File" on target "Item: C:\Temp\04122021143000_RC-M1234R.mp3 Destination: C:\Temp\TempChild\04122021143000_RC-M1234R.mp3".
#>
I'm currently reading a CSV file and creating a folder structure dependent on column values and copying files into these sub-directories. I'm currently struggling to adjust this, so that the file name is amended upon the copy to DotDate_CurrentName (DotDate is a column in the csv).
##Pull the CSV & Create Directories
Echo "Getting root directory for CSV File" #via root variable
#import the csv file and loop through the results
Echo "Importing CSV file"
Import-Csv -Path "$($FilePath)\$($DateStr)_$($TimeStr)_Export.csv" | ForEach-Object {
Echo "Building subpath and fullpath strings"
$subPath = [System.IO.Path]::Combine($_.'ID' + '_' + $_.'First Name' + '_' + $_.'Surname', $_.Area, $_.SubArea, $_.'DotDate')
$fullPath = Join-Path -Path $rootPath -ChildPath $subPath
"Test fullpath and build path from strings"
if (!(Test-Path -Path $fullPath -PathType Container)) {
New-Item -Path $fullPath -ItemType Directory | Out-Null
}
Copy-Item -Path $_.'Document File Path' -Destination $fullPath
}
You do not need to copy then rename; you can do both in the same action. To prepend the DotDate, you can do something like this:
#requires -Version 4
#(Import-Csv -Path "$FilePath${DateStr}_${TimeStr}_Export.csv").ForEach{
$path = [IO.Path]::Combine(
$rootPath,
('{0}_{1}_{2}' -f $_.ID, $_.'First Name', $_.Surname),
$_.Area,
$_.SubArea,
$_.DotDate
)
if (-not (Test-Path -Path $path -PathType Container)) {
New-Item -Path $path -ItemType Directory >$null
}
$copy = [IO.FileInfo]$_.'Document File Path'
$copy | Copy-Item -Destination "$path\$($_.DotDate)_$($copy.Name)"
}
I've put together a script that recursively copies from one directory to another, skipping files with a certain pattern in the filename:
function Copy-RevitFiles ([string]$source, [string]$destination, [boolean]$recurse) {
$pattern = '\.\d\d\d\d\.[RVT]'
if ($recurse) {$files = Get-ChildItem $source -Recurse}
else {$files = Get-ChildItem $source}
$files | ForEach-Object {
if ((Select-String -InputObject $_.Name -pattern $pattern -AllMatches -quiet) -eq $null) {
#Write-Host $_.Name
#Write-Host $_.Fullname
#Write-Host "$($destination)\$($_.FullName.TrimStart($source))"
Copy-Item $_.FullName -Destination "$($destination)\$($_.FullName.TrimStart($source))" #add on full name of item, less $source start end of file path
#Write-Host "----------"
}
}
}
It works well, for the most part. The problem I have though is that it creates an additional subfolder inside each folder with files in it. For example:
If input the source as a directory with this structure:
Source
-file1.rvt
-file1.0225.rvt (will not copy as it matches the pattern)
-file1.0226.rvt (will not copy as it matches the pattern)
-folder1
|-file2.rvt
|-file2.0121.rvt (will not copy as it matches the pattern)
|-file2.0122.rvt (will not copy as it matches the pattern)
-folder2
I am expecting the following structure to be created in the destination folder:
Destination
-file1.rvt
-folder1
|-file2.rvt
-folder2
But instead, I am getting:
Destination
-file1.rvt
-folder1
|-file2.rvt
|-folder1 (extra folder not in source)
-folder2
Any idea where I am going wrong?
It's the way you construct the destination and also how you handle the returned value for the Select-STring cmdlet with option -Quiet.
Using the Quiet switch will have the cmdlet return a Boolean value ($true or $false), but you are testing for equality to $null.
If I use the Join-Path cmdlet (along with some other adjustments to your function) like this:
function Copy-RevitFiles {
[CmdletBinding()]
Param(
[string]$source,
[string]$destination,
[string]$pattern,
[switch]$recurse
)
# test if the destination folder exists
if (!(Test-Path -Path $destination -PathType Container)) {
New-Item -ItemType Directory -Path $destination -Force | Out-Null
}
$files = Get-ChildItem $source -Recurse:$recurse
$files | ForEach-Object {
if (!(Select-String -InputObject $_.Name -Pattern $pattern -AllMatches -Quiet)) {
#Write-Host $_.Name
#Write-Host $_.Fullname
$target = Join-Path -Path $destination -ChildPath $_.Fullname.TrimStart($source)
#Write-Host "Copying '$_.Fullname' to '$target'"
$_ | Copy-Item -Destination $target
#Write-Host "----------"
}
}
}
and use it according to your Source example:
Copy-RevitFiles -source "D:\Source" -destination "D:\Destination" -pattern '\.\d\d\d\d\.[RVT]' -recurse
It will result in:
Destination
| file1.rvt
|
+---folder1
| file2.rvt
|
\---folder2
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;
Below power shell script will copy and replace all the contents from source to destination.
Copy-Item -Path $sourcePath -Destination $installationPath -Recurse -Force
This looks simple. But in my case, I need to implement a custom file copy logic.
Logging everything about files being copied.
Skipping certain set of folders.
Sample script:
[Array]$files=Get-ChildItem ($sourceDirectoryPath) -Recurse | Format-Table Name, Directory, FullName
for($i=0;$i -le $files.Length-1;$i++)
{
. . . . . .
# Build destination path based on the source path.
# Check and create folders if it doesn't exists
# Add if cases to skip certain parts.
Copy-Item -Force $sourcePath -Destination $destinationPath
}
Any ideas on how to achieve this? Any other ideas also will help.
Thanks.
Something like this:
$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$sourceDir = "c:\temp\source"
$targetDir = "c:\temp\target"
$skipFiles = #(
"skip.me",
"and.me"
)
Get-ChildItem -Path $sourceDir -Recurse | ForEach-Object {
# ignore folders
if ($_.PSIsContainer)
{
return
}
# skip this file?
if ($skipFiles -contains $_.Name)
{
Write-Verbose "Skipping '$_.FullName'"
return
}
# create target folder when needed
$path = $_.DirectoryName -replace "^$([RegEx]::Escape($sourceDir))",$targetDir
if (!(Test-Path $path))
{
Write-Verbose "Creating target path '$path'..."
New-Item -Path $path -ItemType Directory
}
# copy the file
Write-Verbose "Copying '$_.FullName' to '$path'..."
Copy-Item $_.FullName $path | Out-Null
}