Removing lines with past dates from a text file - powershell

I have a text file called HelplineSpecialRoster.txt that looks like this
01/01/2019,6AM,0400012345,Kurt,kurt#outlook.com
02/01/2019,6AM,0412345676,Bill,bill#outlook.com
03/01/2019,6AM,0400012345,Sam,Sam#outlook.com
04/01/2019,6AM,0412345676,Barry,barry#outlook.com
05/01/2019,6AM,0400012345,Kurt,kurt#outlook.com
I'm in Australia so the dates are day/month/year.
I have some code that creates a listbox that displays the lines from the text file, but I want to edit the text file before it is displayed to only show older dates. A helpful person gave me this code and it worked once but now it stopped working for some reason. When I delete the whole text file and recreated it it started working again but only once.
If there is a future shift in the file say
05/02/2019,6AM,0400012345,Kurt,kurt#outlook.com
and todays date being 29/01/2019 it works to delete the older shifts. If there is only old shifts in the file as above, it doesn't delete them. When I add a date that is in the future, then it works to delete the older ones and only keep the future one.
$SpecialRosterPath = "C:\Helpline Dialer\HelplineSpecialRoster.txt"
$CurrentDate2 = (Get-Date).Date # to have a datetime starting today at 00:00:00
Function DeleteOlderShifts {
$CurrentAndFutureShifts = Get-Content $SpecialRosterPath | Where-Object {
$_ -match "^(?<day>\d{2})\/(?<mon>\d{2})\/(?<year>\d{4})" -and
(Get-Date -Year $Matches.year -Month $Matches.mon -Day $Matches.day) -ge $CurrentDate2
}
$CurrentAndFutureShifts
$CurrentAndFutureShifts | Set-Content $SpecialRosterPath
}
DeleteOlderShifts;
Any ideas?

When there are only older dates in your input file the result in $CurrentAndFutureShifts will be empty. Empty values in a pipeline are skipped over, meaning that nothing is written to the output file, so the output file remains unchanged.
You can avoid this issue by passing the variable to the parameter -Value. Change
$CurrentAndFutureShifts | Set-Content $SpecialRosterPath
into
Set-Content -Value $CurrentAndFutureShifts -Path $SpecialRosterPath

Rather than using a text file, use a CSV file with headers. This is essentially just a text file saved with a .csv file extension that includes headers for each column:
Note I have added an additional row at the bottom with a date older than today's to prove testing.
HelpineSpecialRoster.csv content:
Date,Time,Number,Name,Email
01/01/2019,6AM,400012345,Kurt,kurt#outlook.com
02/01/2019,6AM,412345676,Bill,bill#outlook.com
03/01/2019,6AM,400012345,Sam,Sam#outlook.com
04/01/2019,6AM,412345676,Barry,barry#outlook.com
05/01/2019,6AM,400012345,Kurt,kurt#outlook.com
01/02/2019,6AM,400012345,Dan,dan#outlook.com
Set the path of the CSV:
$csvPath = "C:\HelpineSpecialRoster.csv"
Import CSV from file:
$csvData = Import-CSV $csvPath
Get todays date # 00:00
$date = (Get-Date).Date
Filter csv data to show rows where the date is older than today's date:
$csvData = $csvData | ? { (Get-Date $date) -lt (Get-Date $_.Date) }
Export the CSV data back over the original CSV:
$csvData | Export-CSV $csvPath -Force

Related

How to modify the date-created attribute for multiple files using .csv data?

I am unsure on how to word my problem as it's not something I am familiar with,
but Powershell is probably what I'm need to use.
I saw this: need to change file created date based on csv (4 years ago)
and would like to know how I can apply this to my problem.
I have many .mp4 files in the folder videos that have incorrect date-created attributes.
I also have a .csv file that lists the all the files in videos in chronological order (using the respective filenames).
The first file starts at 15 Nov 2019, and each successive video is created 1 day after the prior.
How can powershell help me modify the date-created attribute of every file using the rows of the files in the .csv file.
CSV FILE: contains the filenames IN CHRONOLOGICAL ORDER
video1
video2
video3
...
videos Folder:
name date created
video1 dd/mm/yyyy
video2 dd/mm/yyyy
video3 dd/mm/yyyy
... ... <---- dates are incorrect
What I would like:
name date created
video1 15/11/2019
video2 16/11/2019
video3 17/11/2019
... ... <---- dates are in chronological order according to .csv file
Thanks for your help!
Assuming that:
A) all your files are in the same folder
OR B) you have the full paths in your CSV
AND C) your csv files header is called filename
$csvfile = 'Path\to\csvfile.csv'
$startdate = Get-Date 11/15/2019
Set-Location Path\to\videofiles
Import-Csv $csvfile | ForEach-Object {
#set creationtime
(Get-Item $_.filename).CreationTime = $startdate
#increase date by one day
$startdate = $startdate.AddDays(1)
}
#Doug Maurer provided an incomplete answer (did not work) so here is the working solution:
$csvfile = 'path/to/csvfile.csv'
$startdate = [datetime]::ParseExact('15/11/2019','dd/MM/yyyy',$null)
Set-Location 'path/to/folder'
Import-Csv $csvfile | ForEach-Object {
#set creationtime
(Get-Item $_.filename).CreationTime = $startdate
#increase date by one day
$startdate = $startdate.AddDays(1)
}

How to compare to string in PowerShell foreach loop to files

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

Importing csv rows to powershell, with date specified as greater than

I have two csv files. One with a report from AD, containing accounts created during last month, second is manually kept database, that should theoretically contain the same information, but from all history of our company, with some additional data needed for accounting. I imported the AD report to powershell, now I need to import specific rows of the database. The rows I need are defined by a value in column "Date added". I need to import only rows, where the date exceeds specific value. I have this code:
$Report = Read-Host "File name" #AD report, last ten chars are date of report creation, in format yyyy-MM-dd
$Date_text = $Report.Substring($Report.get_Length()-10)
$Date = Get-Date -Date $Date_text
$Date_limit = (($Date).AddDays(-$Date.Day)).Date
$Date_start = $Date_limit.AddMonths(-1)
$CSVlicence = Import-Csv $Database -Encoding UTF8 |
where {(Where-Object {![string]::IsNullOrWhiteSpace($_.'Date added')} |
ForEach-Object{$_.'Date added' = $_.'datum Pridani' -as [datetime] $_}) -gt $Date_start}
When run like this, nothing is imported. Without the condition the database is imported successfully, but it's extremely large and the rest of the script takes for ever. So I need to work only with relevant data. I don't care, that when Date_limit is 30th Sep, the Date_start would be 30th Aug instead of 31st Aug. That's just few more rows, but all those 10 years or so really takes for ever, if everything is imported.
So based on your current logic, it filters the PSCustomObject based on your constraints, which is the wrong way to handle it since any item in the object will cause it to be filtered out. You want to filter the source.
$Report = Read-Host -Prompt 'Filename'
## Grabs the datestamp at the end
$Date = Get-Date -Date $Report.Substring($Report.Length - 10)
## Grabs last day of previous month
$Limit = $Date.AddDays(-$Date.Day)
## Grabs last day of two months ago, inaccuracy of one day
$Start = $Limit.AddMonths(-1)
Get-Content -Path $Database -TotalCount 1 | Set-Content -Path 'tempfile'
Get-Content -Path $Database -Encoding 'UTF8' |
## Checks that the entry has a valid date entry within limits
ForEach-Object {
## For m/d/yy or d/m/yy variants, try
## '\d{1,2}\/\d{1,2}\/\d{2,4}'
If ($_ -match '\d{4}-\d{2}-\d{2}')
{
[DateTime]$Date = $Matches[0]
If ($Date -gt $Start -and $Date -lt $Limit) { $_ }
}
} |
Add-Content -Path 'tempfile'
$CSV = Import-Csv -Path 'tempfile' -Encoding 'UTF8'

Find and replace strings in files in a given date range by filename

A nice tough one for you all. I'm trying to find and replace a given string in a bunch of files. The files have a date stamp in the file name i.e. YYYY_MM_DD_file.txt
I wish to search and replace within a date range for these files and then replace a string I define, I cannot use date modified as the date range, I must rely on the stamp in the filename.
So far I set my date range in WPF text fields:
$Filename = $Filenamebox.text
$startdate = [datetime] $startdatetext.text
$enddate = [datetime] $enddatetext.Text
$NewFilenamereal = $Newfilename.Text
$array =
do {
$startdate.ToString('yyyy_MM_dd*')
$startdate = $startdate.AddDays(1)
}
until ($startdate -gt [datetime] $enddate)
$files1 = $array | foreach-object {"C:\Users\michael.lawton\Desktop\KGB\Test folder\$_"}
write-host $files1
I then get child items using the $files1 array I have created as a search mask for the files in the date range and find all matches. Store this in a variable and replace the string $filename with the new string $Newfilenamereal.
$Matches1 = get-childitem $files1 | select-string $Filename | foreach-object {$_ -replace $Filename,$Newfilenamereal} | out-string
write-host $Matches1
However I cannot work out how to overwrite what has been found and replaced in the $Matches1 variable to the original files. I have tried set-content, however this will simply either erase everything I have in the date stamped files or cannot understand the $files1 array as a file path.
So my question to you lovely people is how do I write what I have replaced in the environment to the actual files?
Just retrieve the file content using the Get-Content cmdlet and replace the string. Finally write it back using the Set-Content cmdlet:
Get-ChildItem $files1 | ForEach-Object {
($_ | Get-Content -Raw) -replace $Filename,$Newfilenamereal |
Set-Content -Path $_.FullName -Encoding UTF8
}

Deleting records from a log/text file

I have several laptops that are generating daily activity logs for a process into txt files. I've figured out how to write a script to append the logs into one master file on a daily basis, but now I'm concerned about file size. I'd like to keep a rolling 60 days of data in my master file.
Here is my data format:
2016-06-23T04:02:33,JE5030UA,88011702312014569339,0000000034626,01451560610600980
Using Get-Date.AddDays(-60) I can get the cutoff date, but it's in MM/dd/yyy format.
If I set up a variable to get the date in the same format as my file (Get-Date -format 'yyyyMMdd), I can't use the .AddDays() method with it to get the cutoff date.
That's how far I've got so far. I'd include code, but there's not much there. The script to append the files was so easy. I can't believe it's difficult to purge old records.
My questions:
What am I missing on the date issue?
What is the best cmdlet to purge records > 60 days? There doesn't appear to be a 'delete' cmdlet for records in a file. I was expecting a 'if date > 60 days, then delete record' kind of function.
Do I need to add a header to the text file?
Take a look at the following code to read from your combined log and then filter out rows that are within your date range. You get a DateTime object from (get-date).AddDays(); you get a DateTime object from the time stamp in the file, then you can compare them. This is one way of doing it anyway.
$cutoffDate = (get-date).AddDays(-60);
$fileContents = get-content C:\your\path\combinedLog.txt
foreach($line in $fileContents)
{
write-host "Current line = $line"
$words = $line.Split(',')
$date=get-date $words[0];
write-host "Date of line = $date"
if($date -gt $cutoffDate)
{
# Append $line to your trimmed log
}
}
Since you're using an ISO date format you can remove records older than a given cutoff date by formatting the cutoff date accordingly and comparing the first field of each line to it:
$file = 'C:\path\to\your.log'
$cutoff = (Get-Date).AddDays(-60).ToString('yyyy-MM-dd\THH:mm:ss')
(Get-Content $file) |
Where-Object { $_.Split(',')[0] -ge $cutoff } |
Set-Content $file
However, rotating logs is usually a better appraoch than clearing out a single file. Write your logs to a different file each day, e.g. like this:
... | Set-Content "C:\path\to\master_$(Get-Date -f 'yyyyMMdd).log"
so you can simply remove logs by their last modification date:
$cutoff = (Get-Date).AddDays(-60)
Get-ChildItem 'C:\log\folder\master_*.log' |
Where-Object { $_.LastWriteTime -lt $cutoff } |
Remove-Item