Format a column of dates in CSV - date

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'

Related

Importing CSV values with custom number formatting

I have a csv file with a timestamp column that has a custom number formatting in this format mm:ss.0.
I am trying to change that custom number formatting to h:mm:ss AM/PM, preferably during the Import-CSV command, but it doesn't have to be.
For example, 42:00.5 should be 12:42:00 AM.
Most of the examples I've seen had dates and times and could easily be converted using ToString and Get-Date but I couldn't get those examples working with just a time stamp.
Here's a few examples of what I've tried:
Import-Csv foo.csv |
Select *,#{label = 'timestamp';expression={get-date $_.Date -f 'h:mm:ss tt'}} -ExcludeProperty timestamp |
Export-Csv -NoTypeInformation foo2.cs
Import-Csv foo.csv |
Select-Object #{Name = 'timestamp'; Expression = { '{h:mm:ss tt}' -f [datetime]$_.'timestamp' }}, * -ExcludeProperty 'timestamp' |
Export-Csv -NoTypeInformation foo2.csv
What am I missing?
This is where I would go in Excel to change the custom number format. The selected is what the current number format is and the highlighted is what I need.

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

Logon time script | how to overwrite last logon Powershell

I have a script configured on my GPO that tracks a certain user group their logon times exported to a csv.
Now i've gotten the question, to make it show only the LAST logon time.
At the moment it just writes down every single logon time, but they would like only the last one.
Is there a way to make it overwrite it instead?
Let's say user1 logs in 3 times, i would like to only show it the last one, and that for every user in this group.
The script i have at the moment is a very simple one:
"logon {0} {1} {2:DD-MM-YYYY HH:mm:ss}" -f (Get-Date),$env:username, $env:computername >> \\server\folder\file.csv
Much appreciated if somebody could tell me if it is possible!
First of all, you are appending a line to a text file which is not a CSV file because the values aren't separated by a delimiter character.
Then also, you use the wrong order of values for the -f Format operator: While the template string clearly has the date as the last placeholder in {2:DD-MM-YYYY HH:mm:ss}, you feed that as the first value..
Please also notice that a date format is Case-Sensitive, so you need to change DD-MM-YYYY HH:mm:ss into dd-MM-yyyy HH:mm:ss
I'd advise to change the script you now have to something like:
[PsCustomObject]#{
User = $env:USERNAME
Computer = $env:COMPUTERNAME
LogonDate = '{0:dd-MM-yyyy HH:mm:ss}' -f (Get-Date)
} | Export-Csv -Path '\\server\folder\UserLogon.csv' -NoTypeInformation -Append
Then, when it comes down to reading that file back and preserving only the latest logons, you can do
$data = Import-Csv -Path '\\server\folder\UserLogon.csv' | Group-Object User | ForEach-Object {
$_.Group | Sort-Object {[datetime]::ParseExact($_.LogonDate, 'dd-MM-yyyy HH:mm:ss', $null)} |
Select-Object -Last 1
}
# output on screen
$data
# overwrite the CSV file to keep only the last logons
$data | Export-Csv -Path '\\server\folder\UserLogon.csv' -NoTypeInformation
I think one arrow > should be to overwrite a file.
There is also a command called Out-File with parameters to overwrite a file.
More information on the PowerShell documentation,
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-file?view=powershell-7.1
I must reiterate what others have commented about this not being the best approach to this problem however, given the output file that you have, you could process it like this to get the last record for a given user:
$last = #{} ; Get-Content \\server\folder\file.csv |% { $token = $_ -split ' ' ; $last.$($token[3]) = $_ }
$last
It creates a hash keyed with the username and updates it with the last line from the file. You can also access $last.foo to get the last entry for user foo.
I'd also note that your CSV isn't a CSV which makes it more difficult to process. You'd be better to use Export-CSV or at least putting the commas in. Also, while still not the best approach, you could create a file per user which you could just overwrite each time they login, thus:
new-object PSObject -Property #{ 'date'= (Get-Date); 'username'= $env:username; 'Computer' = $env:computername } | Export-CSV -Path "\\server\folder\$($env:username).csv" -NoTypeInformation
You could import everything for processing by doing:
gci \\server\folder\*.csv |% { import-csv $_ }

Replace One CSV Field With Another Through PowerShell

In PowerShell I'm importing a CSV SAMTemp2 which will have a field called SO. Sometimes SO will be populated with "NW" and in these cases I just want to pull the field called ProdProj from the same line and replace the data in SO with the data in ProdProj then export it the data in that condition.
$RepNW = Import-Csv $SAMTemp2
foreach($d in $data){
If($d.SO -eq "NW"){($d.SO).Replace($d.ProdProj)}}
$RepNW | Export-Csv $SAMTemp -NoTypeInformation
I don't get an error, but this doesn't seem to do anything, either. Can anyone assist me, please?
Update
Per Matt below, I tried:
$RepNW = Import-Csv $SAMTemp2
foreach($d in $RepNW){
If($d.SO -eq "NW"){$d.SO = ($d.SO).Replace($d.ProdProj)}}
$RepNW | Export-Csv $SAMTemp -NoTypeInformation
But I'm not seeing any change. Any assistance is appreciated.
As LotPings pointed out in this line foreach($d in $data){, you haven't defined $data and it seems that you mean it to be foreach($d in $RepNW){
Secondly, rather than using Replace() you can just set one property to be equal to the other.
Last, this probably easiest to do all in the pipeline with ForEach-Object
Import-Csv $SAMTemp2 | ForEach-Object {
If($_.SO -eq "NW"){
$_.SO = $_.ProdProj
}
$_
} | Export-Csv $SAMTemp -NoTypeInformation

Convert date format in CSV using PowerShell

I have two CSV file with 50 column and more than 10K row. There is a column having date-time value. In some records it is 01/18/2013 18:16:32 and some records is 16/01/2014 17:32.
What I want to convert the column data like this: 01/18/2013 18:16. I want to remove seconds value. I want to do it by PowerShell script.
Sample data:
10/1/2014 13:18
10/1/2014 13:21
15/01/2014 12:03:19
15/01/2014 17:39:27
15/01/2014 18:29:44
17/01/2014 13:33:59
Since you're not going to convert to a sane date format anyway, you can just do a regex replace of that column:
Import-Csv foo.csv |
ForEach-Object {
$_.Date = $_.Date -replace '(\d+:\d+):\d+', '$1'
} |
Export-Csv -NoTypeInformation foo-new.csv
You could also go the route of using date parsing, but that's probably a bit slower:
Import-Csv foo.csv |
ForEach-Object {
$_.Date = [datetime]::Parse($_.Date).ToString('MM/dd/yyyy HH:mm')
} |
Export-Csv -NoTypeInformation foo-new.csv
If you're sure that there are no other timestamps or anything that could look like it elsewhere, you can also just replace everything that looks like it without even parsing as CSV:
$csv = Get-Content foo.csv -ReadCount 0
$csv = $csv -replace '(\d{2}/\d{2}/\d{4} \d{2}:\d{2}):\d{2}', '$1'
$csv | Out-File foo-new.csv