Working with dates in extensionAttributes and Get-Date - date

I'm attempting to use Active Directory extensionAttributes to keep track of certain dates (like start date, termination date, etc) so that I can trigger certain actions when that date occurs.
I'm having an issue with the different variations that a date can be entered in (M/D/YY, MM/DD/YY, MM/DD/YYYY, etc). For example, I can use Get-Date to output to a format of M/D/YYYY, but I run into issues when someone enters MM/DD/YY.
Is there a way to make this work so that it can accept other variations (as long as it's month/date/year)?
Here are a couple of lines from the script in question. This runs once a day, and checks for new users starting the following day.
$StartingOn = (Get-Date).AddDays(1).ToShortDateString()
$NewUserCheck = Get-QADUser -DontUseDefaultIncludedProperties -IncludedProperties extensionAttribute11 | where { $_.extensionAttribute11 -eq $StartingOn }
Notice how it only returns as long as the date equals the Get-Date output. It was the only way I was able to get this to work properly. Even at that, if someone typed in 07/20/15, the output would return nothing.

Don't try to compare date strings. Use DateTime comparison which won't care about formatting details e.g.:
$StartingOn = (Get-Date).AddDays(1)
$NewUserCheck = Get-QADUser -DontUseDefaultIncludedProperties -IncludedProperties extensionAttribute11 |
Where { [DateTime]($_.extensionAttribute11) -eq $StartingOn}

Related

Set Expiry Date with CSV containing DD-MMM-YYYY format

Our HR Department's Termination system sends us a report at intermittent intervals of people who are leaving/people who have left.
Import-Csv -Path \C\Users\Leaver.csv | ForEach-Object {
$EmployeeNumber = $_.EmployeeNumber
$TerminationDate = $_.TerminationDate
$objADUser = (Get-ADUser -Filter {employeeid -eq $EmployeeNumber}).samAccountName
}
The report that HR give us doesn't have their sAMAccountName or even their email. Fortunately, it does have their Employee ID. I'm using this in the script to get their SAM name since I figure that's easier to work with.
Problem is, the termination date they give is actually the last day they work, not the first day of non-work.
Normally I'd have
Set-ADAccountExpiration -Identity $objADUser -DateTime "$TerminationDate"
But that means they can't work on their last day. I also can't add a time like "23:59:59" as Powershell doesn't seem to like that with a variable.
There's also the fact that the date format is in DD-MMM-YYYY (EG 01-Jan-2000) which does make it difficult to work with.
Anyone know what the best syntax to use here is?

Working with unusual date formats in Powershell?

I am working on a GUI-based Powershell tool to help users easily find out when their AD password is going to expire. Due to Covid restrictions, most users and not on-site and rely on VPN to connect to AD. A by-product of this is that many do not see the automatic pop-up in Windows to remind them of them to set a new password soon. Those that are on-site see the notification OK. It's a not a group-policy problem. The tool will be will be rolled-out in two different languages - one representing the 'mothership' (where is English is not normally spoken) and English for all other countries.
Some of the (mostly) Eastern European countries use a short date format that reads like 'd.M.yyyy.' - according to settings menu when one changes the 'Region' setting in Windows.
The tool calculates the difference between today and the expiry data and outputs the number of days to a text field. The actual expiry is display correctly in its own text field.
Some of the source code behind it all...
$thisUser = [Environment]::UserName
#make string
"net user " + $thisUser + " /domain"
#make cmd string
$fetch_net_user = "net user " + $thisUser + " /domain"
#execute command and store to variable
$net_user_data_array = Invoke-Expression $fetch_net_user
#Gets password expiry date (with header)
$password_expiry_with_header = $net_user_data_array[11]
#extracts only the date and assigns to new variable (the hours and minutes) can be ignored)
$password_expiry_as_string = $password_expiry_with_header.Split(' ')[-2]
# Home countries - works OK
try{
$password_expiry_as_dateTime = [datetime]::ParseExact($password_expiry_as_string, 'dd.MM.yyyy', $null)
}
# Others - works OK
catch{
$password_expiry_as_dateTime = [datetime]::ParseExact($password_expiry_as_string, 'dd/MM/yyyy', $null)
# where problem occurs
catch{
$password_expiry_as_dateTime = [datetime]::ParseExact($password_expiry_as_string, 'd.M.yyyy.', $null)
}
finally{
#show GUI error window...
}
#fetch date... converted to yesterday to fix an off-by-one bug!
$today = Get-Date
$rightNow = $today.AddDays(-1)
#calc days left
$daysRemaining = (New-TimeSpan -Start $rightNow -End $password_expiry_as_dateTime).Day
# some other code follows, manipulating date values etc. Works with most date formats.
When executed the script will throw several errors.
The first is...
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
Others will follow such as
You cannot call a method on a null-valued expression.
As the difference between today and the expiry date cannot be calulated.
Is there any easy fix for this? I'd rather avoid having to write a long list of 'if' statments for each country/culture. Thanks!
I'm sure the code could be a little bit more elegant, and that will be addressed in a later version. Right now, getting it to work some of the more obscure date formats is my priority.
Something else that I should stress is that this tool works in a 'read only' capacity. No 'Set-Item' commands are used.
Regards,
WL
You have 2 problems:
Multiple date formats used interchangeably
Trailing dots on some strings
The first problem can be solved by passing multiple format strings to ParseExact() - it'll try each in order until it successfully parses the input string (or reaches the end of the list):
[datetime]::ParseExact($password_expiry_as_string, [string[]]#('dd.MM.yyyy', 'dd/MM/yyyy', 'dd.M.yyyy', 'd.M.yyyy'), $null, [System.Globalization.DateTimeStyles]::None)
The second problem can be solved by trimming trailing dots:
[datetime]::ParseExact($password_expiry_as_string.TrimEnd('.'), [string[]]#('dd.MM.yyyy', 'dd/MM/yyyy', 'dd.M.yyyy', 'd.M.yyyy'), $null, [System.Globalization.DateTimeStyles]::None)

Trying to format ticks as datetime and export to excel

I am struggling a bit with an issue I hope you can help me with.
I am using get-winevent to grab specific events from a computer and export the results to a csv.
I am setting a variable to hold all of the returned events and then using a foreach loop to step through all the events and export them to a csv file.
When I export the timecreated object, the data is formatted as date-time and I can sort oldest to newest or newest to oldest. What I am running into is that the default format of "timecreated" is "MM/DD/YYYY hh:mm ". This causes a problem in that, unless I can see seconds and milliseconds, a lot of these events appear to happen at the same time.
To resolve this, I have been using the following to format the date:
$ticks = [datetime]$event.timecreated.Ticks
$date = $ticks.Tostring("MM/dd/yyyy hh:mm:ss:fff")
This works well when I just output to the screen, the date shows exactly like I want it to. However, since the variable is a string, when I export the variable to excel I can’t sort based on time.
Does anyone know of a way to convert ticks to the display format I want, but keep it as datetime rather than a string? Or any way to grab the timecreated object and format it the way I want, without having to convert it to a string?
I'm beginning to think I may have to create a PSObject and handle it that way, but I am not sure I can do it even then.
Thanks for reading.
if i understand your whole query and excepted result.
I have tested what your are looking for and result it to we doesn't have to add "fff" to string date format on excel because it's doesn't work.
Try this :
$ticks = [datetime]$event.timecreated.Ticks
$date = $ticks.Tostring("MM/dd/yyyy hh:mm:ss")
The full example we have using for testing :
$events =Get-WinEvent -ListLog * | Where {$_.IsClassicLog -eq ‘True’}
$events | Select-Object LogMode, RecordCount, LogName, #{n="DateWrite";e={$_.LastWriteTime.ToString("dd/MM/yyyy hh:mm:ss")}} | Export-Csv -Path c:\fso\event_tester.csv -Encoding ascii -NoTypeInformation
At result have the excepted Date column :
Resources :
How to represent a DateTime in Excel
pandas output timestamps to_excel with microseconds

Powershell - Find & Replace Dates

I'm looking for a bit of assistance here. I currently have a Powershell script which adjusts the dates within a file. I'm looking to stop myself having to manually adjust these dates every time. What I need is to replace the date two days ago, with the date from yesterday.
I believe that I'd have to use (Get-Date).AddDays(-1) and (Get-Date).AddDays(-2) but I'm not exactly sure how I'd script this in!
What I currently have:
echo "Adjusting Import Dates"
(Get-Content D:\Temp\Example.txt).replace('20180917', '20180918') | Set-Content D:\Temp\Example.txt
You could try this:
$yesterday = (Get-Date).AddDays(-1).tostring("yyyyMMdd")
$twodaysago = (Get-Date).AddDays(-2).tostring("yyyyMMdd")
(Get-Content D:\Temp\Example.txt).replace($twodaysago, $yesterday) | Set-Content D:\Temp\Example.txt
You just introduce variables for the two dates and format them to the required date format.
There is probably some other way of replacing in files, but the above should work.

Importing Data From CSV in Powershell Providing UK Date in CSV is Less Than 7 Days Away

so I've got a CSV file with 5 headings: name, collectionDate, location, equipmentNotes, manager.
Now my collectionDates are all in UK format so DD/MM/YYYY. I only want to import data from the CSV with collection dates that are 7 days or less in the future.
So today is 17/08, therefore I would only want to pull data from the CSV that is dated between 17/08 to 24/08.
Although Powershell sort of handles datetime objects in UK format if you tell it to, I seem to be unable to then manipulate the date to add on 7 days.
Here is my current code:
$today = Get-Date
$thisWeek = $today.AddDays(7)
$thisWeekString = $thisWeek.ToString()
$dateParts = $thisweekString -split " "
$weekFinal = $dateParts[0]
$import = Import-Csv #("\\location\EmailCSV.csv") | Where-Object {$_.collectionDate -lt $weekFinal}
Powershell correctly adds 7 days to the datetime to make it 24/08, and then when converting it to a string and removing the time from it, it correctly sets the variable as 24/08/2018. But when I then go to compare them in the Import cmdlet, it just returns all data in the CSV, rather than dates less than 24/08.
I also know Powershell can compare these, because if I create a separate variable $otherDate with 24/08/2018 in it, and then create an if statement that checks if $weekFinal is greater or less than $otherDate, it correctly runs the statement when true.
I've tried using both Where and Where-Object in the Import-Csv cmdlet, but both have returned the same results.
How do I get Powershell to correctly compare $_.collectionDate and $weekFinal to filter the imported data from the csv?
It is easiest to perform all calculations and comparisons using [datetime] instances - avoid string operations (except for converting a string representation of a date to a [datetime] instance).
First, express today's date and 1 week from now as a [datetime] instance without a time-of-day component:
$today = (Get-Date).Date # Today's date, without a time component (midnight)
$oneWeekFromToday = $today.AddDays(7)
Then use [datetime]::Parse() to convert the invariably string-typed CSV column value of interest to a [datetime] instance so you can perform proper date-comparison.
$import = Import-Csv \\location\EmailCSV.csv | Where-Object {
$thisDate = [datetime]::Parse($_.collectionDate)
# Process this row if its date falls between today and 1 week from now, inclusively.
$thisDate -ge $today -and $thisDate -le $oneWeekFromToday
}
Important: use [datetime]::Parse('...'), not a [datetime] '...' cast, because only [datetime]::Parse() respects the current culture's date and time formats; by design, PowerShell's casts and string interpolation always use the invariant culture, irrespective of the current culture - for more information, see this answer of mine.
Try casting the strings to [datetime] in your comparison. When using a sample set of data, I was able to get the expected results.
$import = Import-Csv #("\\location\EmailCSV.csv") | Where-Object {[datetime]$_.collectionDate -lt [datetime]$weekFinal}