Compare Date from CSV Import To Get-Date - date

I have a CSV that contains a number of columns but I want to import just the description column, a department column and a date column. I then want to create a new object with the description, department and date information but only for items that have a date 45 days or older. I know that the Import-Csv is bringing in the "Item Date" column as a string so that I need to use something like Get-Date or datetime to get it to a date format for comparison.
$data = import-csv .\items.csv | select "Description", "Department", "Item Date"
$CheckDate = (Get-Date).AddDays(-45)
$data2 | Foreach {get-date $_."Item Date"} |
select "Description", "Department", "Item Date"
$newdata = $data2 | where {$data."Item Date" -lt $CheckDate}
There may be an easier way to do this or there may be a way to get this to work but I am having trouble.

Definitely some room for simplification here.
$CheckDate = (Get-Date).AddDays(-45)
$data = Import-Csv .\items.csv |
Where-Object {
($_."Item Date" -as [DateTime]) -lt $CheckDate
}
Just cast the "Item Date" string as a [DateTime] with the -as operator and then compare that to your $CheckDate in the Where-Object call.

Depending on the date format used in the CSV and the computer's regional settings simply casting the string to a DateTime value may or may not work. If you find that it doesn't use the ParseExact() method instead. And perhaps a calculated property, since you're selecting columns anyway.
$fmt = 'dd\/mm\/yyyy'
$culture = [Globalization.CultureInfo]::InvariantCulture
$data = Import-Csv .\items.csv |
Select-Object Description, Department, #{n='Item Date';e={
[DateTime]::ParseExact($_.'Item Date', $fmt, $culture)
}} |
Where-Object { $_.'Item Date' -lt $CheckDate }
Note that forward slashes in the format string must be escaped if you need to match literal forward slashes, otherwise they will match whatever date separator character is configured in the computer's regional settings.

Related

Powershell - Formatting column as date

I am importing a CSV which has 5 "columns". One of them is a date and time. The 3rd party software that is reading this column, then does not sort the date well.
IE: (4/8/2022 1:24:08 PM) will sort above (4/13/2022 8:51:52 AM)
Even though 4/13 is after 4/8 it will not sort it properly. I would like to add a leading zero in front of the month and date with powershell. I did do some searching but nothing seems to make sense to me, I am not a HUGE programmer.
Thanks for any help!
This is what I am currently doing. I am using unique to remove duplicate rows (this is needed for what I am doing).
$FinalSessions = Import-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv" | Sort-Object * -Unique
$FinalSessions | Export-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv" -NoTypeInformation
$FinalSessions
You can use Get-Date to actually get a datetime object and then reformat it.
It would look something like this:
$FinalSessions = Import-Csv -Path "C:\Windows\AdminArsenal\UserSessions.csv"| Sort-Object * -Unique
$FinalSessions | % { $_.DateColumn = Get-Date $_.DateColumn -Format "MM/dd/yyyy hh:mm:ss tt" }
$FinalSessions | Export-Csv -Path
"C:\Windows\AdminArsenal\UserSessions.csv" -NoTypeInformation
$FinalSessions
Just replace "DateColumn" with the name of your column
Assuming that the column that contains the date-time string is named Date (adjust as needed):
Import-Csv -Path C:\Windows\AdminArsenal\UserSessions.csv |
ForEach-Object { $_.Date = ([datetime] $_.Date).ToString('s') } |
Sort-Object * -Unique -OutVariable finalSessions |
Export-Csv -Path C:\Windows\AdminArsenal\UserSessions.csv -NoTypeInformation
$finalSessions
Note that the s format specifier (in ISO 8601 format) is used to reformat the date-time strings, as that results in a string whose lexical sorting reliably indicates chronological order, across year boundaries; e.g. 2022-05-05T17:52:47

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"

Comparing dates of a CSV column in PowerShell

I have a CSV file spreadsheet (converted from an Excel xlsx) with around 21 columns and 74,000 rows. The four columns of interest to me are columns having to do with an employees start date, a termination date, a department name, and a vice president they report to.
I am trying to write a script that will return all employees whom have reached their start date, have not been terminated, work in a department that contains 'HR' in the name, and report to a specific VP. I will elaborate on my specific issues after the block of code.
$Lawson = Import-Csv .\Documents\Lawson_HR.csv
$startDate = $Lawson | where [datetime]::ParseExact($_.'LAW HIRE DATE', 'dd-MM-yyyy', $null) -le (Get-Date)
$endDate = $startDate | where {$_.'LAW TERM DATE' -eq ''}
$HR = $endDate | where {$_.'LAW DEPT NAME' -match 'HR'}
$VP = $endDate | where {$_.'VICE PRESIDENT' -match 'Croner'}
First, the $startDate variable does not work, I am unsure of the syntax needed to compare a given date (from the CSV) to today's date. (The $endDate variable functions as it should, but I was told that the method used is unreliable.)
Also, I would like to search the Dept Name column in each row for any instance of the letters 'HR' (note: dept names could be things like 'HR - Career Services' or 'HR - Diversity'. I want all rows that have 'HR' anywhere in the Dept Name field). I get the feeling the -match operator is not the way to do that, but I'm not certain.
Similarly, I would like for the $VP variable to return all items in which the Vice President column has a given name (in this case, Croner).
This line needs curly braces { } but looks otherwise OK to me:
$startDate = $Lawson | where { [datetime]::ParseExact($_.'LAW HIRE DATE', 'dd-MM-yyyy', $null) -le (Get-Date) }
To do a simple partial match you're better off using -Like and a wildcard character as -Match uses regex (although should work).
Also I just noticed you were piping the $enddate variable not $lawson:
$HR = $Lawson | where {$_.'LAW DEPT NAME' -like '*HR*'}
If you're trying to do all of these criteria together, just combine them with -and:
$Lawson | where { [datetime]::ParseExact($_.'LAW HIRE DATE', 'dd-MM-yyyy', $null) -le (Get-Date) -and $_.'LAW TERM DATE' -eq '' -and $_.'LAW DEPT NAME' -like '*HR*' -and $_.'VICE PRESIDENT' -match 'Croner'}

PowerShell ForEach removes leading zeros

I am kind of new with PowerShell and programming in general, so I hope you have some patience while reading this. Before I explain my problem, I feel like I have to first tell you some background information:
I have all my transactions saved in $Transactions. Each transaction has Receiver, Date and Amount.
I have grouped the yearly transactions into $TransactionsPerYear the following way:
$TransactionsPerYear = $Transactions | Group-Object { [int]($_.date -replace '.*\.') }
(Btw. Could someone explain the regex in the end for me, what each character does?)
Next thing I am doing is grouping yearly income and expenses into separate variables. After this I am trying to extract the months from each year and save them into $Months. The date is in the following format dd.MM.yyyy
Question 1:
Here's how I can get all the dates, but how do I extract just the months?
$TransactionsPerYear | Select -ExpandProperty Group | Select -ExpandProperty date | Select -Unique
Question 2:
Because I don't know how to extract the months, I've tried it the following way:
[String[]]$Months = "01","02","03","04","05","06","07","08","09","10","11","12"
When I have each month in $Months I am trying to get monthly transactions and save them into new variables:
ForEach($Month in $Months){
New-Variable -Name "Transactions_$Month$Year" -Value ($Transactions | Where {$_.Date -like "*.$Month.$Year"} | Group-Object 'Receiver' | Select-Object Count, Name, #{L="Total";E={$_ | Select -ExpandProperty Group | Measure-Object Amount -Sum | Select -ExpandProperty Sum}} | Sort-Object {[double]$_.Total})
}
The problem that I am facing here is that ForEach removes the leading zero from each month, and when this happens, this part in ForEach doesn't match with anything, and the new variable is null:
Where {$_.Date -like "*.$Month.$Year"}
Let me know if you need more info. I'd be really thankful if anyone could help me.
The date looks like: 25.02.2016
From your post, it looks like you've jumped further down the rabbithole than necessary.
Instead of trying to do string manipulation every time you need to interact with the Date property, simply turn it into a DateTime object!
$Transactions = $Transactions |Select-Object *,#{Name='DateParsed';Expression={[datetime]::ParseExact($_.Date, 'dd.MM.yyyy', $null)}}
The DateTime.ParseExact() method allows us to specify the format (eg. dd.MM.yyyy), and parse a string representation of a date.
Now you can group on year simply by:
$TransactionsPerYear = $Transactions |Group-Object { $_.DateParsed.Year }
To group by both Year and then Month, I'd create a nested hashtable, like so:
# Create a hashtable, containing one key per year
$MonthlyTransactions = #{}
foreach($Year in $Transactions |Group {$_.DateParsed.Year})
{
# Create another hashtable, containing a key for each month in that year
$MonthlyTransactions[$Year.Name] = #{}
foreach($Month in $Year.Group |Group {$_.DateParsed.Month})
{
# Add the transactions to the Monthly hashtable
$MonthlyTransactions[$Year.Name][$Month.Name] = $Month.Group
}
}
Now you can calculate the transaction value for a specific month by doing:
$TotalValueMay2010 = ($MonthlyTransactions[2010][5] |Measure-Object Amount -Sum).Sum
(Btw. Could someone explain the regex in the end for me, what each character does?)
Sure:
. # match any character
* # zero of more times
\. # match a literal . (dot)
Taking your own example input string 25.02.2016, the first group (.*) will match on 25.02, and \. will match on the . right after, so the only thing left is 2016.
Do you mean this?
$dates = ([DateTime] "1/1/2016"),([DateTime] "1/2/2016"),
([DateTime] "2/1/2016"),([DateTime] "3/1/2016")
$uniqueMonths = $dates | ForEach-Object { $_.Month } | Sort-Object -Unique
# $uniqueMonths contains 1,2,3

Format a column of dates in CSV

I'm attempting to format some dates in the first column of a CSV. I would prefer to user something like powershell as I plan to automate this task. Does anyone have any advice on the best way to change the format of the date from something like MM/DD/YYY to YYYY-MM-DD? I've tried something like this:
$date = date -f ('yyyyMMdd')
$HMDA = Import-Csv "C:\HMDA\$date.YieldTableFixed.csv"
ForEach-Object {
$HMDA.Date = [datetime]::ParseExact($HMDA.Date).ToString('YYYY-MM-DD')
} |
Export-Csv -NoTypeInformation C:\HMDA\test.csv
Unfortunately, that didn't seem to do anything but give me a parse error and I can't seem to figure out why that is. Is there a way I can say something like:
ForEach-Object{
$HMDA.A2:$HMDA.A63 = HMDA.$AC.Date.Format('YYYY-MM-DD')
}
Ok, there's some basic errors here, but that's just a matter of not knowing better I think. Now this is hard to answer accurately because you did not give us an example of the incoming date field, so if it has some strange formatting this may throw errors as PowerShell fails to recognize that a string is in fact a date.
First off, if you pipe to a ForEach loop you reference the current object with $_. Such as:
Import-Csv "C:\HMDA\$date.YieldTableFixed.csv" | ForEach-Object {
$_.Date = get-date $_.Date -f 'yyyy-MM-dd'
} | Export-Csv -NoTypeInformation C:\HMDA\test.csv
What would probably be simpler, as I recently learned from somebody else here on SO, would be to use Select, create the updated property on the fly, and then exclude the original property, effectively replacing it with the new one. Something like this:
Import-Csv "C:\HMDA\$date.YieldTableFixed.csv" |
Select *,#{label = 'Date';expression={get-date $_.Date -f 'yyyy-MM-dd'}} -ExcludeProperty Date |
Export-Csv -NoTypeInformation C:\HMDA\test.csv
ParseExact() expects 3 parameters: the date string, a format string, and a format provider (which may be $null). Also, your output format string is incorrect (the year and day format specifiers need to be lowercase), and ForEach-Object reads from a pipeline.
Change this:
$HMDA = Import-Csv "C:\HMDA\$date.YieldTableFixed.csv"
ForEach-Object {
$HMDA.Date = [datetime]::ParseExact($HMDA.Date).ToString('YYYY-MM-DD')
} |
Export-Csv -NoTypeInformation C:\HMDA\test.csv
into this:
Import-Csv 'C:\HMDA\$date.YieldTableFixed.csv' | ForEach-Object {
$_.Date = [DateTime]::ParseExact($_.Date, '*M\/dd\/yyyy', $null).ToString('yyyy-MM-dd')
$_
} | Export-Csv -NoTypeInformation 'C:\HMDA\test.csv'