I've created a script to find files that are a certain amount of days old. I'm using it to find files that are 30 days old but I'm trying to leave it open should I ever need to plug in a different amount of time.
After you feed this part of the script the information you'd like, it is supposed to create a text file of all the files that meet the criteria. I can find files that are -lt and -gt or -le or -ge but when I attempt to use -eq, I get no results. Any thoughts on what's wrong with the portion of my script listed below?
$Path = Read-Host "What path should I look at?"
$DaysOld = Read-Host "How many days old should the files I'm looking for be?"
$Currentdate = Get-Date
$Targetdate = $Currentdate.AddDays(-$DaysOld).ToString('MM-dd-yyyy')
Write-Host "The target date is $targetdate"
$SourceFolder = $Path
$files = Get-ChildItem $Path -Recurse |
Where-Object { $_.LastWriteTime -eq $Targetdate } |
Where-Object { $_.PSIsContainer -eq $false } |
ForEach-Object { $_.FullName } |
Out-File $outfileCopy
The problem with using -eq is that datetime objects are down to the second, so is 8/22/2017 at 11:59:27 AM -eq to 8/22/2017 at 00:00:00 AM? No, no it isn't. What you could do to defeat that is to use the .ToShortDateString() method which outputs a string such as 8/22/2017.
$Path = Read-Host "What path should I look at?"
$DaysOld = read-host "How many days old should the files I'm looking for be?"
$Currentdate = get-date
$Targetdate = $currentdate.AddDays(-$daysOLD).ToShortDateString()
Write-Host "The target date is $targetdate"
$SourceFolder = $path
$files = Get-ChildItem $path -Recurse| Where-Object {$_.lastwritetime.ToShortDateString() -eq $targetdate}|Where-Object {$_.PSIsContainer -eq $false} | ForEach-Object {$_.fullname}| out-file $outfileCopy
This approach should only be used when trying to match things from the same day, ignoring the time of day, and should not be used when looking for things that are less than, or more than (including -le and -ge) because it uses string evaluation instead of date evaluation.
Edit: I've been doing it wrong for years, and didn't even know. Many thanks to #Matt for pointing out the .date property of a [DateTime] object, which retains the object type, but zeros out the time aspects of it. Better answer: Use the .Date property to compare, and this should work for greater than and less than evaluations as well.
$Path = Read-Host "What path should I look at?"
$DaysOld = read-host "How many days old should the files I'm looking for be?"
$Currentdate = get-date
$Targetdate = $currentdate.AddDays(-$daysOLD).Date
Write-Host "The target date is $targetdate"
$SourceFolder = $path
$files = Get-ChildItem $path -Recurse| Where-Object {$_.lastwritetime.Date -eq $targetdate}|Where-Object {$_.PSIsContainer -eq $false} | ForEach-Object {$_.fullname}| out-file $outfileCopy
Related
I'm writing a script that I can run once every two weeks to clear out folders and files that haven't been accessed in two weeks or longer. I've written most of the script, and it works well until I add the following line of code:
Where-Object { $_.LastAccessTime –lt $RefDate } |
For some reason, this code prevents $condition from having an output [see code below].
I use $condition later in a do-while to recursively delete folders, but it won't loop due to this, or export the data to a CSV folder anymore. [Removing this line lets it work again]
Here's the key sections that the line is used in/relevant to it:
$dPath = "C:\Users\my.name\Desktop\PowTest2\*\"
$RefDate = (Get-Date).AddHours(-1);
$condition = Get-ChildItem $dPath -recurse -force |
Where-Object { $_.LastAccessTime –lt $RefDate } |
Where-Object {$_.PSIsContainer -eq $True} |
Where-Object{$_.GetFileSystemInfos().Count -eq 0} |
select FullName
write-output $RefDate;
write-output $condition
Above, $RefDate outputs as expected, $condition outputs nothing unless I remove the problematic line of code.
Edit:
Hi all,
Olaf made a good point, and asked me to check if the property is tracked for the folder. It appears it isn't, which would explain my issue. I'll update after more research and testing.
Not sure if its been answered, but i was doing some reasearch and found a 7 month old post where it was answered, i changed it around to match what youd like "It deletes all files older than 13 days, so not sure if that works lol". Let me know if this help
OG POST: Powershell delete folder files based on date range criteria
$path = "C:\Users\XXXXXXXX\Desktop\test"
foreach($file in (GEt-childitem -Path $path -Recurse | Where-Object {($_.LastWriteTime
-lt (Get-Date).AddDays(-14))} ))
{
if (($file.lastwritetime.Date.Day -in 1,15,30 ) -or ($file -like '*weekly*'))
{continue}
Remove-Item -Path $file.FullName}
I'm fairly new to Powershell and programming in general. I want to search files using Powershell having multiple conditions. I have managed to write this code
$Drives = Get-PSDrive -PSProvider 'FileSystem'
$Filename= 'Result'
$IncludeExt= '*csv,*docx'
$StartDate= '11/1/20'
$EndDate= '1/26/21'
Get-ChildItem -Path $Drives.Root -Recurse |Where-Object {$IncludeExt -match $_.Extension} | Where-Object { $_.BaseName -match $Filename} | Where-Object {$_.lastwritetime -ge $StartDate -AND $_.lastwritetime -le $EndDate} |
foreach{
$Item = $_.Basename
$Path = $_.FullName
$Type = $_.Extension
$Age = $_.CreationTime
$Path | Select-Object `
#{n="Name";e={$Item}},`
#{n="Created";e={$Age}},`
#{n="filePath";e={$Path}},`
#{n="Folder/File";e={if($Folder){"Folder"}else{$Type}}}`
}| Export-Csv D:\FFNew.csv -NoTypeInformation
This works well when the all variables are mentioned. But how do I get this to work when
Case1: If $Filename is empty then it gives all the files with the mentioned extensions and files modified in Range of dates
Case2: If $IncludeExt is left empty then it gives all files with the $Filename mentioned, currently it gives only the folders and files modified in Range of dates
Case 3: If $Filename and $IncludeExt is left empty it gives all the files modified between the $StartDate and $EndDate
Pranay,
[EDITED]
Ok, here's the revised (exact) script with notes and sample output. Note: you'll have to change the items that are specific to my machine!
$Drives = Get-PSDrive -PSProvider 'FileSystem'
$Filename = "*" #for all or "*partial name*"
$IncludeExt = $Null #for no ext. or "*.csv","*.docx",etc...
$StartDate = '01/1/2020' #to ignore this use 1/1/1920
#For latest date use below otherwise specify date.
$EndDate = (Get-Date).ToShortDateString()
#Note: below uses only 3rd drive in the array remove [2] for all.
$GCIArgs = #{Path = $Drives[2].Root
Recurse = $True
}
If ($Null -ne $IncludeExt) {
$GCIArgs.Add("Include",$IncludeExt)
}
Get-ChildItem #GCIArgs |
Where-Object {($_.BaseName -Like $Filename) -and
($_.lastwritetime -ge $StartDate) -and
($_.lastwritetime -le $EndDate) } |
foreach{
$Item = $_.Basename
$Path = $_.FullName
$Type = $_.Extension
$Type = & {if($_.PSIsContainer){"Folder"}else{$_.Extension}}
$Age = $_.CreationTime
$Path | Select-Object #{n="Name" ;e={$Item}},
#{n="Created" ;e={$Age}} ,
#{n="filePath" ;e={$Path}},
#{n="Folder/File";e={$Type}}
} | Export-Csv -LiteralPath 'G:\BEKDocs\FFNew.csv' -NoTypeInformation
Notes:
$IncludeExt is specified as $Null if it is not used and if used the list is like this ".csv",".docx"
$Filename is specified as "*" for all filenames. Also changed the test from -match to -like so partial filenames should include *, e.g. "partial name".
Notice I changed the location of the check for Extensions to use the -Include parameter of the Get-ChildItem vs checking in the Where-Object.
Changed the piping of data to successive Where-Object clauses and replaced with -and operator, same effect and more efficient.
Changed the test for Directories to use the PSIsContainer property, couldn't see where you were getting the value for $Folder.
Removed the continuation characters from the Select-Object as the comma serves that purpose and is cleaner.
Sample output on Single drive (per code shown above) with some lines hidden for space considerations but notice the last line number.
Sample output on all drives (code edited as per comment in code), again lines hidden for space but showing multiple drives and final line number.
HTH
I am a PowerShell newbie. I have a .csv file of users that I pulled a list of home directories for using the following:
$hdirpath = Get-Content C:\Temp\UserList.csv | ForEach {Get-ADUser $_ -properties HomeDirectory | Select HomeDirectory}
Output example of the above looks something like this:
HomeDirectory
\servername\Users\roc03\username
\servername\Users\nov01\username
\servername\Users\roc05\username
Now I want to check if a folder exists in each users path and if it exists, i want to add today's date to the end of that folder name. I know there's a If-Exist-Then command that I might be able to use but I'm not sure how to use it with the information saved in $hdirpath.
Any help would be greatly appreciated. Thanks in advance.
Newbie myself so please forgive any mistakes.
From the top of my head I've got this in mind:
foreach ($path in $hdirpath) {
$folders = Get-ChildItem $_ -Recurse | Where-Object {$_.PSIsContainer -eq $True} | Select-Object FullName
$folders | if ($_.Name -eq "Folder Name") {Rename-Item "Folder Name" + Get-Date}
}
Someone will probably correct me, but if they don't give it a go and let me know if you have any problems.
Also - just for future reference, make sure you include code you have tried before posting a question.
EDIT
So, I've now got the following:
$hdirpath = Get-Content C:\temp\dir.txt
$fullDate = Get-Date
$date = $($fullDate.ToShortDateString())
$day = $date -replace "/", "."
foreach ($path in $hdirpath) {
Get-ChildItem -Path $_ -Recurse | Where-Object {$_.PSIsContainer -eq $true} |
Rename-Item -NewName {if ($_.Name.StartsWith('target') -and $_.Name.EndsWith('folder')) {$_.Name + " " + $($day)}}
}
This returns multiple errors saying that it Cannot evaluate parameter 'NewName' because its argument input did not produce any output., but it works and appends the folder name with the current date.
Line 3-5 get the date and format it with "." rather than "\". You can format this however works for you obviously.
My test structure was "C:\temp\roc6\username1" - with multiple subfolders and multiple 'usernameX'. My test folder to re-name was called "targetfolder". End result ended with "targetfolder 08.03.2017".
Revision
This would be my final run of the script - with my limited knowledge this is the best I can do.
$ErrorActionPreference = "SilentlyContinue"
$hdirpath = Get-Content C:\temp\dir.txt
$fullDate = Get-Date
$day = $($fullDate.ToShortDateString()) -replace "/", "."
foreach ($path in $hdirpath) {
Get-ChildItem -Path $_ -Recurse | Where-Object {$_.PSIsContainer -eq $true} |
Rename-Item -NewName {if ($_.Name.StartsWith('target') -and $_.Name.EndsWith('folder')) {$_.Name + " " + $($day)}}
}
Need a powershell script that will moved folders and files from a location to another location that are older then x number of days but some folders are exempted.
Also needs to have the ability to email a list of files and folders that it moved.
I can move the files in a folder, I'm not sure how to move the entire folders though.
Here is some code I have put together so far, any suggestions would be great
Set-ExecutionPolicy RemoteSigned
#----- define parameters -----#
#----- get current date ----#
$Now = Get-Date
#----- define amount of days ----#
$Days = "7"
#----- define folder where files are located ----#
$TargetFolder = "C:\test"
$TargetPath = "C:\test5"
#----- define extension ----#
$Extension = "*.*"
#----- define LastWriteTime parameter based on $Days ---#
$LastWrite = $Now.AddDays(-$Days)
#----Exclusion List ----#
$exclude =#('test1', 'test2')
#----- get files based on lastwrite filter and specified folder ---#
$Files = Get-Childitem -path $TargetFolder -Include $Extension -Recurse | Where {$_.LastWriteTime -le "$LastWrite"} -and $_Name -ne $exclude | foreach ($_)} #-
foreach ($File in $Files)
{
if ($File -ne $NULL)
{
write-host "Deleting File $File" -ForegroundColor "DarkRed"
Move-Item $File.FullName $TargetPath -force
}
else
{
Write-Host "No more files to delete!" -foregroundcolor "Green"
}
}
A shorthand version that is supported on PowerShell v3 or higher. This would find all the folder where the LastWriteTime is older that 7 days and move them.
$LastWrite = (Get-Date).AddDays(-7)
gci c:\temp -Directory -Recurse | ?{$_.LastWriteTime -le $LastWrite} | select -expand fullname | %{Move-Item $_ $TargetPath}
There would be no point with file exclusions if you are just looking at the folder time so that logic is omitted. Same code but easier to read:
$LastWrite = (Get-Date).AddDays(-7)
Get-ChildItem $TargetFolder | Where-Object{$_.LastWriteTime -le $LastWrite} | Select-Object -ExpandProperty FullName | ForEach-Object{
Move-Item $_ $TargetPath
}
Caveat
There could be an issue where you are trying to move a folder and a parent might have been previously moved. Don't really have the test environment to check that right now. Could just use a little test before the copy just in case.
If(Test-Path $_){Move-Item $_ $TargetPath}
Email
A starting point for working with email would be Send-MailMessage. There are other methods as well.
Folder Exclusion
If you wanted to omit certain folders there is a couple of ways to accomplish that. If you know the whole folder name you want to omit you could add this $exclude =#('test1', 'test2') like you already have and change the Where clause.
Where-Object{$_.LastWriteTime -le $LastWrite -and $exclude -notcontains $_.Name}
If you didnt know the whole name and maybe that $exclude only contained the partial name you could do this as well using a little regex
$exclude =#('test1', 'test2')
$exclude = "({0})" -f ($exclude -join "|")
#..... other stuff happens
Where-Object{$_.LastWriteTime -le $LastWrite -and $_.Name -notmatch $exclude}
I am working in a windows environment.
I have a project that requires a short script to determine if a file with a modified date of today exists in a folder. If the file exists, it should copy it, if a file does not exist, it should return an error code.
I prefer to not use 3rd party apps. I am considering powershell.
I can pull a list to visually determine if the file exists, but I am having trouble batching to return an error if the count is zero.
Get-ChildItem -Path C:\temp\ftp\archive -Recurse | Where-Object { $_.lastwritetime.month -eq 3 -AND $_.lastwritetime.year -eq 2013 -AND $_.lastwritetime.day -eq 21}
Any help is greatly appreciated!
You can compare the current date against the date part only of each file LastWriteTime short date:
Get-ChildItem -Path C:\temp\ftp\archive -Recurse | Where-Object {
$_.LastWriteTime.ToShortDateString() -eq (Get-Date).ToShortDateString()
}
Get-ChildItem $path -r | % {if((!($_.psiscontianer))-and(Get-Date $_.LastWriteTime -Uformat %D)-eq(Get-Date -UFormat %D)){$_.FullName}else{Write-Warning 'No from Today'}}
F.Y.I. when doing large jobs, like if you'll be going through TB of files, use a foreach-object. It's faster then Where-Object. This method processes the objects collected in the array directly when available and doesn't wait until all objects are collected.
In summary, there always a lot of different ways to achieve the same result in PowerShell. I advocate using what is easiest for you to remember. At the same time, PowerShell can provide some big performance differences between the approaches – and it pays to know more!
You can still make the line a little more efficient by calculating the date
$date = (Get-Date -UFormat %D)
Get-ChildItem $path -r | % {if((!($_.psiscontianer))-and(Get-Date $_.LastWriteTime -Uformat %D)-eq$date){$_.FullName}else{Write-Warning 'No from Today'}}
I was able to use the following script:
$Date = Get-Date
$Date = $Date.adddays(-1)
$Date2Str = $Date.ToString("yyyMMdd")
$Files = gci "C:\\Temp\\FTP\\Archive"
ForEach ($File in $Files){
$FileDate = $File.LastWriteTime
$CTDate2Str = $FileDate.ToString("yyyyMMdd")
if ($CTDate2Str -eq $Date2Str) {Copy-Item $File.Fullname "C:\\Temp\\FTP"; exit}
}
Throw "No file was found to process"
To test if there are no files:
$out = Get-ChildItem -Path C:\temp\ftp\archive -Recurse | Where-Object {
$_.LastWriteTime.ToShortDateString() -eq (Get-Date).ToShortDateString()
};
if ($out.Count -gt 0)
//do something with your output
else
//sorry no file