Rename and copy select files in nested directory Powershell - powershell

I cannot seem to rename let alone copy any text files using this code, I am trying to go through a nested directory which should be taken care of with Get-ChildItem -Recurse.
It seems like I am only going through the selected source folder's files instead of fully recursing through all of the subfolders.
A sample text file in the directory would be 02-01-2016 Test.txt
$InputDate = Read-Host -Param 'Please select a starting date (In the following format: mmddyyyy)'
$Date = [datetime]::ParseExact($InputDate, "MMddyyyy", [Globalization.CultureInfo]::CreateSpecificCulture('en-US'), $null)
$Dst = Select-FolderDialog #This function is working for me, assume you can select a folder
$Src = 'C:\Users\Bart Zhang\Downloads\Test Folder (1)\Test Folder' # #source
$FileType = '*.txt'
Get-ChildItem -Path $Src -Recurse -Force | Where-Object {$_.Name -notcontains "Archive"} | ForEach-Object {
$DateStr = $_.BaseName.Substring(0, 2) + $_.BaseName.Substring(3, 2) + $_.BaseName.Substring(6, 4)
$FileDate = [datetime]::ParseExact($DateStr, "MMddyyyy", [Globalization.CultureInfo]::CreateSpecificCulture('en-US'), $null)
If ( $FileDate -ge $Date ) {
Rename-Item -NewName { $_.Directory.Name + ' ' + $_.Name} -Filter $FileType -Recurse -Force
Copy-Item -Path (Join-Path -Path $Src -ChildPath '\*' ) -Destination $Dst -Filter $FileType -Recurse -Force
}
}

I started with a sample folder with files with this naming standard, matching what you described.
Then I ran through your date conversion logic and found that it didn't seem to work as described (lots of errors trying to conver '04082011' to date, for instance) , so I made a change on line 10, changing the line to this:
$DateStr = $_.BaseName.Substring(0,2)+'/'+$_.BaseName.Substring(3,2)+'/'+$_.BaseName.Substring(6,4)
I simply added slashes to the date, so we would end up with '04/08/2011' which seemed to be all I needed for $DateStr to populate, which then allowed the line of file date comparison to work. I also changed the conversion on line 11 to this
$FileDate = get-date $DateStr
Adding some Write-Host lines for visibility and I get this.
03/02/2017 03-02-2017 Test has date of 03/02/2017 00:00:00
03-02-2017 Test has a file date of 03/02/2017 00:00:00 which is newer than 02/04/2014 10:13:14, time to move it
03/22/2010 03-22-2010 Test has date of 03/22/2010 00:00:00
03-22-2010 Test has a file date of 03/22/2010 00:00:00 which is older than 02/04/2014 10:13:14, ignoring...
04/08/2011 04-08-2011 Test has date of 04/08/2011 00:00:00
04-08-2011 Test has a file date of 04/08/2011 00:00:00 which is older than 02/04/2014 10:13:14, ignoring...
05/08/2016 05-08-2016 Test has date of 05/08/2016 00:00:00
05-08-2016 Test has a file date of 05/08/2016 00:00:00 which is newer than 02/04/2014 10:13:14, time to move it
I haven't checked the rest of your code, but this should get you back on track.
Conclusion
Good work for parsing out the file date from a file name like that, which is tricky. However the Conversion technique you were trying was making things harder than it needed to be, so by changing the way we parse the filename (adding slashes so that PowerShell would recognize the string with the much easier Get-Date cmdlet), we could use a different technique which is easier to understand.

Related

How to Parse through hundreds of files and move them to their respected file via powershell

I am trying to write a script that will move hundreds of account PDFs into their respective folders. I am very new to powershell and my basic script for now I was able to move one file to the other folder and match its name and date format of 052020 using this script:
cd \\Sageshare\share
copy-item -path "\\Sageshare\share\Reconciliation\PDF Recon Center\DEA RECON 05292020.pdf" -destination "\\Sageshare\share\Reconciliation\Account Rec. Sheets\Separate Accounts\DEA" | Where-Object {$_.Name -like '*DEA RECON 052020*'}
Since that is only one file going into its named folder in another directory, how would I do this with 400 files going each into a respective folder? If I can get this then I am going to run into the issue to where the 05 date is going to need to change to 06 and so on until the end of the year where it will also have to change the month and year. But I would really like to just figure out the first part for now.
I have make you an code example which shows you how to work in Powershell. You cant break anything when you run my code until you uncomment the two lines at the end
$sourceFolder = '\\Sageshare\share\Reconciliation\PDF Recon Center'
$targetFolder = '\\Sageshare\share\Reconciliation\Account Rec. Sheets\Separate Accounts\DEA'
$files = Get-ChildItem $sourcefolder -Filter *.pdf
$files | ForEach-Object {
echo ('Processing file ' + $_.Name)
$regex = [regex]::Match($_.Name, '\s([0-9]{2})([0-9]{2})([0-9]{4})[.]pdf')
echo ('Month ' + $regex.Groups[1].Value)
echo ('Date ' + $regex.Groups[2].Value)
echo ('Year ' + $regex.Groups[3].Value)
$targetFolderTmp = (Join-Path $targetFolder -childpath ($regex.Groups[3].Value + '\' + $regex.Groups[1].Value + '\' + $regex.Groups[2].Value))
Write-Host ('Copy to: ' + $targetFolderTmp)
#if(-not $targetFolderTmp) {mkdir $targetFolderTmp} uncomment if code is good
#copy-item -path $_.FullName -destination targetFolderTmp uncomment if code is good
}

Need to change lastwritetime in renaming file

I would like to ask help for the lastwritetime need to change if its multiple files having the same time stamp.
I am using below query to fetch and rename the file name with my predefined $prefix+$lastwritetime, suppose if multiple files having same timestamp means I am unable to rename the files, hence the first file is rename with Lastwritetime in that situation I need to change my Lastwritetimes seconds so that files will be created.
Thanks for your kind help.
$FilePath = $ToPath+"\"+$ToFile
Get-ChildItem -Path $FilePath | Foreach { Rename-Item $_ -NewName ($Prefix+$_.LastWriteTime.ToString("yyMMddhhmm")) }
suppose Lastwritetime is 20190619082733 for two files i need it as 20190619082734 + or - is fine. I have tried with AddMinutes(-"2") but something i am missing kindly advise.
Try addminutes(-2). It takes an int and not a string. Something like:
Get-ChildItem -Path $FilePath | Foreach-Object {
$DateString = $_.LastWriteTime.AddMinutes(-2).ToString("yyMMddhhmm")
Rename-Item $_.FullName -NewName ($Prefix + $DateString + $_.Extension)
}
If you want your string to include seconds, you should format it like this:
$DateString = $_.LastWriteTime.AddMinutes(-2).ToString("yyMMddhhmmss")

Copy files to backup location and rename using Lastwritetime

I'm attempting to write a script that copies files from their original location to a backup location. Upon copying to the backup location I'd like the files to be renamed to include the lastwritetime in the name.
ex: \\server1\C$\Logs\Logfile-1.txt (last written to Wednesday, December 20, 2017 5:00:27 AM) copied to \\backupserver\c$\LogBackups\Server1Logfile20171220050027.txt
The program generating the logfiles iterates them with a -1, -2, -3, etc as they reach a certain size.
I have a csv which contains the following information
OldFilePath,NewFilePath,NewFileName
\\server1\c$\Log\LogFile-*.txt,\\backupserver\c$\LogBackups\,Server1LogFile
\\server2\c$\Log\LogFile-*.txt,\\backupserver\c$\LogBackups\,Server2LogFile
\\server3\c$\Log\LogFile-*.txt,\\backupserver\c$\LogBackups\,Server3LogFile
Here is the script that I've got so far.
import-csv \\backupserver\c$\scripts\test.csv | foreach-object {
$FilePath = $_.OldFilePath
$NewFilePath = $_.NewFilePath
$NewFileName = $_.NewFileName
copy-item -path $_.OldFilePath -Destination "$NewFilePath$NewFileName$LastWriteTime.txt"
}
I've tried the following commands to set the $LastWriteTime variable and, so far, haven't been able to correctly format the outputs.
$LastWriteTime = Get-ItemPropertyValue -path \\server1\C$\Logfile-1.txt -name LastWriteTime |
Format-list Year,Month,Day,Hour,Minute,Second
&
$LastWriteTime = Get-ChildItem $OldFilePath | select LastWriteTime
Any help pointing me in the right direction would be appreciated!
Assume you have a DateTime $dt, you can format it like so:
$dt = [DateTime]::Parse((get-item D:\temp\grinder.jpg).LastWriteTime)
$fmt = "{0:N4}{0:N2}{0:N2}{0:N2}{0:N2}{0:N2}" -f $dt.Year, $dt.Month, $dt.Day, $dt.Hour, $dt.Minute, $dt.Second
Which gives:
20171220110535
for
Wednesday, December 20, 2017 11:05:35 AM
From this, you should be able to make progress on rest of your code.

Extract date from a path in powershell

I have a folder called files which has a path like : C:\users\xxxx\desktop\files
Inside this folder are different folders: 2015-12-02, 2015-12-01, 2015-11-30, etc
Inside each folder there are multiple files. I was looking to append the folder date at the end of each file inside the folder. I have written the below script for that:
function checkfile($file) {
$filenm = $file.FullName
return($filenm.Contains('.txt'))
}
function renamefile($file) {
$filenm = $file.Name
$ip = $file.FullName.Substring(34)
$ip1 = $ip.Substring(1,4) + $ip.Substring(6,2) + $ip.Substring(9,2)
$txt = $filenm.Split(".")[1] + "_" + $file.name.Split(".")[3] + "_" + $file.name.Split(".")[4] + "." + $file.name.Split(".")[2] + "." + $ip1
Rename-Item $file.FullName -NewName $txt
}
$sourcepath = "C:\users\xxxx\desktop\files"
$inputfiles = (Get-ChildItem -Path $sourcepath -Recurse) | Where-Object { checkfile $_ }
foreach ($inputfile in $inputfiles) {
renamefile $inputfiles
}
The problem I'm facing is in the above script I have used substring(34) to extract the date from the file path. If for some reason the source path changes (to say : H:\powershell\scripts\files) then 34 will not work.
How can I extract the correct date from the file path irrespective of the full file path?
Why not:
$sourcepath = "C:\users\xxxx\desktop\files"
Get-ChildItem -Path $sourcepath -Include "*.txt" -Recurse | % {
Rename-Item $_ "$($_.BaseName)_$($_.Directory)$($_.Extension)"
}
BaseName is the file name without the extension
Directory is the directory name (your date)
Extension is the file extension (i.e. .txt)
$(...) is used to make sure ... is evaluated properly
% is an alias for ForEach-Object and will iterate over the objects coming from the pipeline.
$_ will hold the current object in the ForEach loop
Here, your checkfile function is replaced by -Include "*.txt".
Example :
C:\users\xxxx\desktop\files\2015-12-02\sample.txt
becomes
C:\users\xxxx\desktop\files\2015-12-02\sample_2015-12-02.txt
Not sure if you need it, but if you want to remove the dashes from the date, you could use:
Rename-Item $_ "$($_.BaseName)_$($_.Directory -replace '-','')$($_.Extension)"
EDIT : OP wished to remove the dashes but append the date after the file extension, so:
$sourcepath = "C:\users\xxxx\desktop\files"
Get-ChildItem -Path $sourcepath -Include "*.txt" -Recurse | % {
Rename-Item $_ "$($_.Name).$($_.Directory.Name -replace '-', '')"
}
The particulars of the problem aren't entirely clear. I gather that the date your are interested in is in the fullpath. You want to extract the date from the path and rename the file, such that the new filename includes that date at the end.
However your script implies that there are at least five periods in the path. But I don't see that mentioned in the OP anywhere.
So there are a few problems and open items I see:
1. What is the syntax of a full path? That includes the five or more periods
2. Will the date always be at the same directory depth? I'm guessing xxxx represents the date. If so the date is the second subdirectory. Will the date always be in the second subdirectory?
3. Related to #2, will there ever be paths that include two or more dates?
Assuming my guesses are correct AND that the date will always be the second subdirectory, then extracting the date would be:
`$dateString = $file.fullpath.split('\')[3]
If some of my guesses are incorrect then please add details to the OP. If #3 is true then you'll need to also explain how to know which date is the correct date to use.
An option that you could do is just cd to each path. Then use Get-ChildItem in each dir, without using -Recurse.
In rename $ip would just be $file, no need for FullName.
For example, define your functions and then:
$sourcefile = 'Whateversourcediris'
cd $sourcefile
$directories = (Get-ChildItem)
foreach ($direct in $directories) {
cd $direct
$inputfiles = (Get-ChildItem)|where-object{checkfile $_}
foreach ($inputfile in $inputfiles) {
renamefile $inputfile
}
cd..
}
Hope this helps.

Folder Structure Name Match Powershell

I have a folder structure in a directory called FTP.
\\FTP\December 15
\\FTP\January 15
\\FTP\February 15
\\FTP\March 15
etc...
I will be moving files to this folder using a powershell script: multiple files. potentially multiple folders.
I want to extract the month
$month = get-date -format m
This will return December
Now how do I write the GCI statement to match the folder to the month
For example: Something like this?
gci '\\FTP\' -recurse WHERE $_.Fullname -like $a.substring(0,9)
Please help
Here is a function to get the month specific folder then you can do whatever you need by replacing the "Do Work To Said Folder" Comment with whatever you want to do to the folder.(Copy To, Get-ChildItems, etc.)
function Get-MonthlyFolder
{
$month = get-date -format m;
#Bellow Line Gets The Full Path To Current Monthly Folder Stored In $folderInst variable:
$folderInst = gci "\\FTP" | Where {$.Name -like "$month*"} | Select FullName;
#Do Work To Said Folder
}
Get-MonthlyFolder;
$month = get-date -format m returns December 15 I assume that's correct.
Then your code will look like this:
Get-ChildItem \\FTP\ -recurse | where { $_.Fullname -like "*$month*"}
we use Where-Object which will return each item matching the expression.