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.
Related
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")
How to compare the current month with file modified in current month using power shell script. My code is working file but it is reading all the csv file in the given directory. I just wanted to read current month file i.e. modified in October 2018.
Please help me out , I have total 6 files in my directory. 3 files having date modified in October 2018 and remaining 3 files are modified in September 2018.
I want my script to check the current month then read all csv of current month i.e. October 2018
Code:
$files = Get-ChildItem 'C:\Users\212515181\Desktop\Logsheet\*.csv'
$targetPath = 'C:\Users\212515181\Desktop\Logsheet'
$result = "$targetPath\Final.csv"
$curr_month = (Get-Date).Month
$curr_year = (Get-Date).Year
# Adding header to output file
[System.IO.File]::WriteAllLines($result,[System.IO.File]::ReadAllLines($files[1])[1])
foreach ($file in $files)
{
$month = $file.LastWriteTime.ToString()
$curr_month=(Get-Date).Month
if ($month= $curr_month)
{
$firstLine = [System.IO.File]::ReadAllLines($file) | Select-Object -first 1
[System.IO.File]::AppendAllText($result, ($firstLine | Out-String))
$lines = [System.IO.File]::ReadAllLines($file)
[System.IO.File]::AppendAllText($result, ($lines[2..$lines.Length] | Out-String))
}
}
# Change output file name to reflect month and year in MMYYYY format
Rename-Item $result "Final_$curr_month$curr_year.csv"
Your comparison is wrong. And will return $true causing all files to be read
It should be
if ($month -eq $curr_month)
Also I would remove the second
$curr_month = (get-date).month
it's adding overhead to your script as you set it before the loop
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.
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.
I have a folder X:/EmpInfo that contains many different folders. Each of these folders contains about 5-10 files.
I need to backup folders that have a modified date newer than 7 days ago. That is, modified would mean new files were added to the folder or an existing file was modified.
Example: If I run it today (11/08), it'll backup all folders in X:/EmpInfo with a modification date of 11/01 to current time today (when the script is run). It should move the entire folder, not just the modified files. Overwrite any existing folders.
It might not be "something for real like Perl" but PowerShell can handle that pretty easily. This should get you started:
$newFolders = dir X:\EmpInfo | ? {$_.PSIsContainer} | ? {$_.LastWriteTime -gt (Get-Date).AddDays(-7)}
$newFolders | % { copy $_.FullName c:\temp\archive -Recurse -Force}
Have fun with the pipeline!
My answer is a combination of the answers of MrKWatkins and Eric Nicholson. In your question you clarify that what you actually want is to copy directories where new files were added or existing files were copied. The behaviour of the last modification date for the containing directory will be different on different filesystems:
NTFS: On an NTFS file system, the modified date of a folder DOES change if the contents of the folder change.
FAT: On a FAT file system, the modified date of a folder does not change if the contents of the folder change.
Description of NTFS date and time stamps for files and folders
Therefore ideally we should first test the filesystem type of the source directory before deciding on how to determine what directories to copy:
function Copy-ModifiedSubdirectory {
param ($sourcefolder, $destinationfolder, [DateTime] $modifieddate)
# Escaping source folder for use in wmi query
$escapedsourcefolder = $sourcefolder -replace "\\","\\"
# Determine what filesystem our folder is on
$FSName = (get-wmiobject -query "select FSName from CIM_Directory where name = '$escapedsourcefolder'").FSName
if ($FSName -eq "NTFS") # The Eric Nicholson way
{
$FoldersToCopy = get-childitem $sourcefolder | where {$_.PSIsContainer} | where {$_.LastWriteTime -ge $modifieddate}
}
elseif ($FSName -eq "FAT32") # The MrKWatkins way
{
$FoldersToCopy = get-childitem $sourcefolder | where {$_.PSIsContainer} | ? { Get-ChildItem $($_.fullname) -Recurse | ? { $_.LastWriteTime -ge $modifieddate } }
}
else
{
Write-Error "Unable to Copy: File System of $sourcefolder is unknown"
}
# Actual copy
$FoldersToCopy | % { copy $_.FullName $destinationfolder -Recurse -Force}
}
To use the function:
$sevendaysago = ((get-date).adddays(-7))
copy-modifiedsubdirectory X:\EmpInfo Y:\Archive $sevendaysago
Here is a rough and ready script to get you started. I'm sure there are better ways to a lot of this...
$sevenDaysAgo = (Get-Date).AddDays(-7);
# Get the directories in X:\EmpInfo.
$directories = Get-ChildItem . | Where-Object { $_.PSIsContainer };
# Loop through the directories.
foreach($directory in $directories)
{
# Check in the directory for a file within the last seven days.
if (Get-ChildItem .\UnitTests -Recurse | Where-Object { $_.LastWriteTime -ge $sevenDaysAgo })
{
$directory
}
}