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.
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")
I am writing a script to go through the contents of a folder, check to see if each subdir is dated before last Saturday, and then remove the folders that are older than last Saturday, but for some reason the powershell debugger is missing my breakpoints within the Get-ChildItem curly brackets. There isn't an error message, but I need to add something within the if statement to remove the folder. The debugger jumps to the end of the function from open curly bracket of Get-ChildItem{}{
This is my code:
#do weekly cleanup of DisasterBackup folder
function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
#find out filename with Saturday date before current date
(Get-ChildItem -Path $folderWeeklyCleanupDatedSubdirs -Filter -Directory).Fullname | ForEach {$_}
{ #####debugger jumps from here to end bracket of WeeklyCleanup function when I step over
write-output $_
#check to see if item is before day we want to remove
$lastSaturday = GetLastSaturdayDate
if($_.LastWriteTime -le $lastSaturday)
{
#will remove dir once I've checked it's giving me the right ones
Write-Output $_
Write-Output " 1 "
}
}
} ############debugger skips to here
function GetLastSaturdayDate()
{
$date = "$((Get-Date).ToString('yyyy-MM-dd'))"
for($i=1; $i -le 7; $i++){
if($date.AddDays(-$i).DayOfWeek -eq 'Saturday')
{
$date.AddDays(-$i)
break
}
}
return $date
}
The directory I'm giving to the function looks like this:
E:\Bak_TestDatedFolderCleanup
I store it as a string and give it to the function like this:
$folderToCleanupDatedSubdirs = "E:\Bak_TestDatedFolderCleanup"
WeeklyCleanup $folderToCleanupDatedSubdirs
and it has a long list of maybe 10-20 folders in it, some of which have a date, in the name, like this:
toLocRobo_2019-01-07
Once my script is done, it will have removed all subdirs that are dated prior to last Saturday's date, but only for the current month. I want this do work no matter what day I run the script.
I've been getting my ideas from this link and other ones:
AddDays
escape missing
It's probably a format issue within Get-ChildItem but I don't see it. I only care about the subdirs within the folder passed to the WeeklyCleanup function. There are folders within those subdirs, but I don't want them looked at. I've used this format before for my dir parameter so I don't think it's escaping anything it shouldn't.
Your ForEach is a ForEach-Object it has two scriptblocks, the first is implicitly of -Begin type.
Also by enclosing in parentheses and appending the .FullName
(Get-ChildItem -Path $folderWeeklyCleanupDatedSubdirs -Filter -Directory).Fullname
you expand the property to a string - It's no more an object and has lost the .LastWriteTime property.
Why do format the date ToString? It's a string then, no more a date.
Here a more simple variant:
function GetLastSaturdayDate(){
$Date = Get-Date
$Date.AddDays(-($Date.DayOfWeek+1)%7)} # on a saturday returns same date
#$Date.AddDays(-($Date.DayOfWeek+1))} # on a saturday returns previous sat.
}
function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
Get-ChildItem -Path $folderWeeklyCleanupDatedSubdirs -Directory | ForEach {
"Processing {0}" -f $_.FullName
if($_.LastWriteTime -le (GetLastSaturdayDate)){
"LastWriteTime {0:D}" -f $_.LastWriteTime
# $_ | Remove-Item -Force -Recurse # delete
}
}
}
$folderToCleanupDatedSubdirs = "E:\Bak_TestDatedFolderCleanup"
WeeklyCleanup $folderToCleanupDatedSubdirs
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 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.
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
}
}