PowerShell Object comparison issues - powershell

I am writing a PowerShell script that reads a calendar file in the following format:
date
20220914
20221014
20221114
20221214
20230116
I want to find the last date from that calendar before a date (normally today's date) and based on that generate a list of file names from that date +1 day up to today's date, the script below was working up to the moment that I have added 2023 calendar dates to the calendar file, not sure how to address the comparison issue between the date from the calendar file date object, find the script below for reference:
$fileNamePrefix = "Daily_File_"
$filesToProcess = ""
$fileType = ".csv"
$fileDate = "20221018"
# Import calendar
$calendarDates = Get-Content -path "C:\Users\me\CutOff_Clndr.txt" | Select-Object -Skip 1
#Reduce calendar entries to contain dates previous to FILE_DATE
$calendarDates = $calendarDates | where-object{ $_.date -lt $fileDate }
#Get Last entry before FILE_DATE
$calendarDates = $calendarDates | Sort-Object -Property date -Descending | Select-Object -First 1
#Convert calendar entries to date object for date calculations
$calendarDates = [datetime]::ParseExact($calendarDates, "yyyyMMdd", $null)
#Convert FLE_DATE date object for date calculations
$fileDate = [datetime]::ParseExact($fileDate, "yyyyMMdd", $null)
#Generate file list
for ($i = $calendarDates.AddDays(1); $i -le $fileDate; $i = $i.AddDays(1)) {
if ($filesToProcess)
{
$filesToProcess += '","' + $fileNamePrefix + $i.ToString("yyyyMMdd") + $fileType
$i.ToString("yyyyMMdd")
}
else
{
$filesToProcess += $fileNamePrefix + $i.ToString("yyyyMMdd") + $fileType
}
}
Write-Host $filesToProcess
Any help/suggestion addressing the conversion from the date object gathered from the calendar file or a different approach to this would be welcome.
Thanks

Related

Get a logfile for a specific date

I want to save in my computer "C:\logFiles" a specific date for logfile generated by program in another PC,
path that i will get from it the log file is "C:\Sut\Stat\03-2021.log"
Example : this file "C:\Sut\Stat\03-2021.Sutwin.log" contenant all the log of Mars month but i just want to get the log of last 7 Days from 19-03-2021 to 26-03-2021
I found this script in the internet but i doesn't work for me i need some help:
Example of the file .log in the photo attached:
Rest of image for the first screenshot :
my PC name : c01234
name of PC contenant log file : c06789
file that i will get from it the infos : 03-2021.Sutwin.log (exist in pc c06789)
i want to transfer the contents of just last 7 days in a folder in my PC c01234 with name Week11_LogFile
$log = "2015-05-09T06:39:34 Some information here
2015-05-09T06:40:34 Some information here
" -split "`n" | Where {$_.trim()}
#using max and min value for the example so all correct dates will comply
$upperLimit = [datetime]::MaxValue #replace with your own date
$lowerLimit = [datetime]::MinValue #replace with your own date
$log | foreach {
$dateAsText = ($_ -split '\s',2)[0]
try
{
$date = [datetime]::Parse($dateAsText)
if (($lowerLimit -lt $date) -and ($date -lt $upperLimit))
{
$_ #output the current item because it belongs to the requested time frame
}
}
catch [InvalidOperationException]
{
#date is malformed (maybe the line is empty or there is a typo), skip it
}
}
Based on your images, your log files look like simple tab-delimited files.
Assuming that's the case, this should work:
# Import the data as a tab-delimited file and add a DateTime column with a parsed value
$LogData = Import-Csv $Log -Delimiter "`t" |
Select-Object -Property *, #{n='DateTime';e={[datetime]::ParseExact($_.Date + $_.Time, 'dd. MMM yyHH:mm:ss', $null)}}
# Filter the data, drop the DateTime column, and write the output to a new tab-delimited file
$LogData | Where-Object { ($lowerLimit -lt $_.DateTime) -and ($_.DateTime -lt $upperLimit) } |
Select-Object -ExcludeProperty DateTime |
Export-Csv $OutputFile -Delimiter "`t"
The primary drawback here is that on Windows Powershell (v5.1 and below) you can only export the data quoted. On Powershell 7 and higher you can use -UseQuotes Never to prevent the fields from being double quote identified if that's important.
The only other drawback is that if these log files are huge then it will take a long time to import and process them. You may be able to improve performance by making the above a one-liner like so:
Import-Csv $Log -Delimiter "`t" |
Select-Object -Property *, #{n='DateTime';e={[datetime]::ParseExact($_.Date + $_.Time, 'dd. MMM yyHH:mm:ss', $null)}} |
Where-Object { ($lowerLimit -lt $_.DateTime) -and ($_.DateTime -lt $upperLimit) } |
Select-Object -ExcludeProperty DateTime |
Export-Csv $OutputFile -Delimiter "`t"
But if the log files are extremely large then you may run into unavoidable performance problems.
It's a shame your example of a line in the log file does not reveal the exact date format.
2015-05-09 could be yyyy-MM-dd or yyyy-dd-MM, so I'm guessing it's yyyy-MM-dd in below code..
# this is the UNC path where the log file is to be found
# you need permissions of course to read that file from the remote computer
$remotePath = '\\c06789\C$\Sut\Stat\03-2021.log' # or use the computers IP address instead of its name
$localPath = 'C:\logFiles\Week11_LogFile.log' # the output file
# set the start date for the week you are interested in
$startDate = Get-Date -Year 2021 -Month 3 -Day 19
# build an array of formatted dates for an entire week
$dates = for ($i = 0; $i -lt 7; $i++) { '{0:yyyy-MM-dd}' -f $startDate.AddDays($i) }
# create a regex string from that using an anchor '^' and the dates joined with regex OR '|'
$regex = '^({0})' -f ($dates -join '|')
# read the log file and select all lines starting with any of the dates in the regex
((Get-Content -Path $remotePath) | Select-String -Pattern $regex).Line | Set-Content -Path $localPath

Datetime in PowerShell can't convert my Time

I'm writing a Script to compare two sets of timevalues and then calculate a exact time.
My problem is the calculation with timestamps. I import the times from a .csv-file. The times look like this:
08:37;
11:47;
12:11;
17:34;
etc.
I made a variable for the times so i always have the correct time from the correct line from the csv file.
My goal ist to calculate the time from one timestamp to another like this: 11:47 - 08:37 = 3:10
If i do this in my PowerShell Script an error occurs: The value "time=12:39" can not be converted to type "System.DateTime". Error: "The string was not recognized as a DateTime. An unknown word starts at index 1"
Is datetime wrong in this case? How can i make this work?
Thx for your help.
If this has to do with your previous question and the CSV actually looks like this:
name;prename;date;time
Gantz;Mario;09.02.;07:37
Gantz;Mario;09.02.;11:23
Gantz;Mario;09.02.;12:34
Gantz;Mario;09.02.;17:03
Then this should do it
# create two variables to hold the times parsed from the CSV, Initialize to $null
$current, $previous = $null
# load the csv and loop through the records
$result = Import-Csv -Path 'D:\Test\times.csv' -Delimiter ';' | ForEach-Object {
$current = [datetime]::ParseExact($_.time, 'HH:mm', $null)
if (!$previous) { $previous = $current }
# subtracting two DateTime objects results in a TimeStamp
$elapsed = $current - $previous
$previous = $current
# output the record with column 'elapsed' appended
$_ | Select-Object *, #{Name = 'elapsed'; Expression = {$elapsed.ToString()}}
}
# output on screen
$result | Format-Table -AutoSize
# output to new CSV file
$result | Export-Csv -Path 'D:\Test\times_and_intervals.csv' -Delimiter ';' -NoTypeInformation
Output on screen:
name prename date time elapsed
---- ------- ---- ---- -------
Gantz Mario 09.02. 07:37 00:00:00
Gantz Mario 09.02. 11:23 03:46:00
Gantz Mario 09.02. 12:34 01:11:00
Gantz Mario 09.02. 17:03 04:29:00
Now that I see you also have a 'date' column in there, you should include that in the conversion to [datetime] aswell:
# create two variables to hold the times parsed from the CSV, Initialize to $null
$current, $previous = $null
# load the csv and loop through the records
$result = Import-Csv -Path 'D:\Test\times.csv' -Delimiter ';' | ForEach-Object {
$completeDate = '{0}{1} {2}' -f $_.date, (Get-Date).Year, $_.time
$current = [datetime]::ParseExact($completeDate, 'dd.MM.yyyy HH:mm', $null)
if (!$previous) { $previous = $current }
# subtracting two DateTime objects results in a TimeStamp
$elapsed = $current - $previous
$previous = $current
# output the record with column 'elapsed' appended
$_ | Select-Object *, #{Name = 'elapsed'; Expression = {$elapsed.ToString()}}
}
# output on screen
$result | Format-Table -AutoSize
# output to new CSV file
$result | Export-Csv -Path 'D:\Test\times_and_intervals.csv' -Delimiter ';' -NoTypeInformation
You are getting the error because you are not specifying the values that you are importing as [datetime]
I have replicated the error where I just specified 2 time values and subtracted them:
$st = "08:37" $et = "11:47" $di = $st - $et Cannot convert value
"08:37" to type "System.Int32". Error: "Input string was not in a
correct format."
Solution:
Specify the values of each entry like so:
[datetime]$starttime = "08:37"
[datetime]$endtime = "11:47"
$diff = $endtime - $starttime
If you just want the time in minutes etc. you can enter $diff.Minutes respectively
Hope this works for you.

Add a calculated field to an imported csv based on datetime

Could someone please assist with this one.
My current code imports a csv file which has three columns, so far it will update the column names to be more readable. I need to add a fourth column which is a calculated field based on a datetime field.
So need to check the datetime field then display a number of days before it is 90 days old.
e.g. "Today's date" - "03/03/2020 8:00:00 AM" = 31 days
90 days - 31 days = 59 days (the 59 days is to go into the calculated field column
Bit of a newb with powershell and have all other functions working, but this is what I'm left with and need to add it into the below call, when the csv is imported, header columns updated then exported to a new file.
$input = "C:\Data\test\unchanged101.csv"
$output = "C:\Data\test\unchanged101conv.csv"
$checkDate = (Get-Date).AddDays(-90)
$data = Import-Csv $input |
Where-Object {
($_."pwdlastset" -as [DateTime]) -lt $CheckDate
}
$headerConversion = #(
#{ Name = 'User account'; Expression = { $_.'cn' } }
#{ Name = 'Last modified date'; Expression = { $_.'pwdlastset' } }
#{ Name = 'Email address'; Expression = { $_.'mail' } }
)
(Import-Csv -Path $input) |
Select-Object -Property $headerConversion | Select-Object *,"Days Left" |
Export-Csv -Path $output -NoTypeInformation
The new column is the "Days Left" where I need to display the number of days left until it is 90 days old. How to I get the result from the code here, into that column for each row?
$checkDate = (Get-Date).AddDays(-90)
$data = Import-Csv $input |
Where-Object {
($_."pwdlastset" -as [DateTime]) -lt $CheckDate
}
Been working on this one for the past few days and just cant figure the last part out.
First of all, you should not use variable name $input as this is an Automatic variable
If you subtract one datetime object from another, the result is a TimeSpan object which has a property called Days you could use
$inputFile = "C:\Data\test\unchanged101.csv"
$outputFile = "C:\Data\test\unchanged101conv.csv"
$checkDate = (Get-Date).AddDays(-90).Date # .Date sets this to midnight
$result = Import-Csv $inputFile |
Where-Object { [DateTime]$_.pwdlastset -lt $CheckDate } |
Select-Object #{ Name = 'User account'; Expression = { $_.cn } },
#{ Name = 'Last modified date'; Expression = { $_.pwdlastset } },
#{ Name = 'Email address'; Expression = { $_.mail } },
#{ Name = 'Days Left'; Expression = { ($checkDate - [DateTime]$_.pwdlastset).Days } }
# output on screen
$result | Format-Table -AutoSize
# output to csv
$result | Export-Csv -Path $outputFile -NoTypeInformation
I would first add the new column and then go trough all the lines (with a foreach loop) check the remaining days and write them to the new "Days Left" column.
Note: I omitted your header conversion here. You need to run it first and then the "Days Left" code...
$data = Import-Csv $input #import everything
foreach($line in $data){
$daysLeft = 0
$daysSinceLastSet = ((Get-Date) - [DateTime]$line.pwdlastset).Days
if ($daysSinceLastSet -lt 90){
$daysLeft = 90-$daysSinceLastSet
}
$line."Days Left" = $daysLeft
}
$data | Export-Csv -Path $output -NoTypeInformation

How can I get the average lastwritetime from multiple files?

I have a PowerShell script that is modifying multiple files. I would like to verify that they were modified by checking the last write time property and comparing it to the current time minus 30 minutes.
Is there anyway to get the average time from multiple different files?
For example:
$Var = Get-Childitem -path "C:\users\User\Documents\*.txt"
$lastwt = $var.Lastwritetime
If($lastwt -ge (Get-Date).addminutes(-30)){
Do stuff
}
The above won't work because multiple dates are returned all around the same time give or take a few milliseconds.
I want to just get the average of all the times and use that as time comparison instead. Any way to do this?
About
So you should probably use New-Timespan to do time comparisons. So your update code:
Code
$Files = Get-Childitem -path "C:\users\User\Documents*.txt"
$Files | ? {
# Filter by a timespan criteria (last write on this file is greater than 30 minutes before now)
$Mins = New-Timespan $_.LastWriteTime (Get-Date) | % TotalMinutes
return $Mins -ge 30
} | % {
# Work only on files that matched the top criteria
}
Does that help? If you still want the averaging solution, lmk, I'll add it in :)
To get an average (median) LastWriteTime [DateTime] object of a series of files, this may be what you want:
$files = Get-Childitem -Path 'C:\users\User\Documents' -Filter '*txt' -File
# get an array of the LastWriteTime properties and sort that
$dates = $files | Select-Object -ExpandProperty LastWriteTime | Sort-Object
$oldest = $dates[0]
$newest = $dates[-1]
# create a new DateTime object that holds the middle of the oldest and newest file time
$average = [datetime]::new((($oldest.Ticks + $newest.Ticks) / 2), 'Local')
# show what you've got:
Write-Host "Oldest LastWriteTime: $oldest"
Write-Host "Average LastWriteTime: $average" -ForegroundColor Green
Write-Host "Newest LastWriteTime: $newest"

Selecting items in CSV file using Date

I am trying to select items by date in a CSV file using PowerShell. The format in the CSV file for the date is 1/8/2018 10:04:00 AM. When I run this I get no data although I know that data exists.
$events = Import-Csv c:\normtest\server2_perf.csv | foreach {
New-Object PSObject -prop #{
Date = [DateTime]::Parse($_.Date);
CPULoad = $_.CPULoad;
MemLoad = $_.Memload
}
}
$events | Where { $_.Date -eq (Get-Date).AddDays(-4) }
As you have a time part to your date, this will only work for exactly 4 days from now (i.e. where time of day = right now).
Assuming this part works correctly: Date = [DateTime]::Parse($_.Date);, you can do this:
$start = (Get-Date).Date.AddDays(4)
$fin = $start.AddDays(1) # assuming 1 day window
$events |
Where {$_.Date -gt $start -and $_.Date -lt $fin}
Alternatively, you could treat the date field as string:
$events = Import-Csv c:\normtest\server2_perf.csv |
Where {$_.Date -like "$(Get-Date).AddDays(-4).ToString("M/d/yyyy"))*" }
Assuming your date format is "M/d/yyyy"