Date comparison (French locale) - getting wrong positive - date

I want to know which accounts were not connected on AD since 3 months
Here's my code
# connexion ADSI
$objDomaine = [ADSI]’’
$objRecherche = New-Object System.DirectoryServices.DirectorySearcher($objDomaine)
$objRecherche.Filter=’(&(objectCategory=person)(objectClass=user))’
# Fichiers de sortie
$OutFile = "\\xxx\xx\Utilisateurs_inactifs.log"
remove-item $OutFile
ADD-content -path $OutFile -value "LOGIN;CN_COMPLET;LASTLOGON"
foreach ( $ADuser in $objRecherche.FindAll() )
{
$LastLogon = $ADuser.Properties[’lastlogon’]
$LastLogon = [int64]::parse($LastLogon)
$date = (Get-Date -Year 1601 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0)
$date_derniere_connexion = $date.AddTicks($LastLogon)
#On formatte un peu le tout. On enleve l'heure et on enleve les \, des CNs.
$DATE_RESULT = $date_derniere_connexion -replace " ..:..:..",""
$RESULT = "$($ADuser.properties[’samaccountname’]);$($ADuser.path);$($DATE_RESULT)" -replace "\\\,",""
# On prend la date du jour et on retire 3 mois
$DATE3MONTHS = (get-date).addmonths(-3).toShortdateString()
# On test la date (pour enlever les occurences de non-login)
if ( $DATE_RESULT -ne '01/01/1601' )
{
# tester si la date de derniere connexion est plus vieille que 3 mois, si oui on ecrit dans le fichier.
if ( $DATE_RESULT -lt $DATE3MONTHS )
{ ADD-content -path $OutFile -value $RESULT }
}
}
In my outfile, I can see many users which last connection is NOT older than 3 months (yesterday!)
here's an sample of my outfile
xx;LDAP://CN=xx;15/09/2015
xx;LDAP://CN=xx;09/09/2015
xx;LDAP://CN=xx;16/09/2015
xx;LDAP://CN=xx;07/05/2014
xx;LDAP://CN=xx;16/09/2015
xx;LDAP://CN=xx;09/01/2015
NOTE : My dates are in french version DD/MM/YYYY

[datetime]::parse("$DATE_RESULT") # this will convert string to date. Parse for my french locale.
Why does PowerShell always use US culture when casting to DateTime?

Related

powershell datetime subtraction

I set up variables.
$script:current = [datetime]::Today
$r = 120
$global:eastern = [System.TimeZoneInfo]::convertTimeBySystemTimeZoneId([datetime]::Now, 'Eastern Standard Time')
How would I go abouts subtracting seconds from this oneliner?
$variable = (($script:current.DayOfWeek -match 'Monday|Tuesday|Wednesday|Thursday|Friday') -and $global:eastern.hour -eq 09 -and $global:eastern.Minute -eq 30 -and ([datetime]::Now.Second -eq 0))
This works, but trying to do so without an 'overload parsexact' error
$culture = [cultureinfo]::InvariantCulture
$format = 'HH:mm:ss'
$east = [datetime]::ParseExact('09:30:00',$culture,'AssumeUniversal, AdjustToUniversal').Addseconds(-$r)
[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($east, 'Eastern Standard Time')
The overload error you're getting on .ParseExact(..) method is because you're missing the string Format argument:
$r = 120
$culture = [cultureinfo]::InvariantCulture
$format = 'HH:mm:ss'
$styles = [System.Globalization.DateTimeStyles]'AssumeUniversal, AdjustToUniversal'
[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId(
[datetime]::ParseExact('09:30:00', $format, $culture, $styles).Addseconds(-$r),
'Eastern Standard Time'
)
If I understand you correctly, subtracting 2 minutes and returning a new [datetime]:
get-date; (get-date) - [timespan]'0:2:0'
Sunday, January 23, 2022 11:31:40 AM
Sunday, January 23, 2022 11:29:40 AM

How to send powershell script output to printer with formatting?

I need to send a script output (basically, agenda from my Outlook calendar filtered by category) that is made within the script to a printer. For the purpose of readability I'd like it to be formatted. At least print some words bold, some italics, maybe change font.
The text is assembled from a custom object and might looks something like this:
text =
#"
Monday
Meeting with Joe : 07:00 - 08:00
Meeting with Ann : 8:30 - 09:00
Tuesday
No meetings
"#
I would ideally like it to print something like this:
Monday
Meeting with Joe : 07:00 - 08:00
Meeting with Ann : 8:30 - 09:00
Tuesday
No meetings
What I have so far (leaving the code pulling calendar events out):
text =
#"
Monday
Meeting with Joe : 07:00 - 08:00
Meeting with Ann : 8:30 - 09:00
Tuesday
No meetings
"#
Add-Type -AssemblyName System.Drawing
$PrintDocument = New-Object System.Drawing.Printing.PrintDocument
$PrintDocument.PrinterSettings.PrinterName = 'Microsoft Print to PDF'
$PrintDocument.DocumentName = "PipeHow Print Job"
$PrintDocument.DefaultPageSettings.PaperSize = $PrintDocument.PrinterSettings.PaperSizes | Where-Object { $_.PaperName -eq 'Letter' }
$PrintDocument.DefaultPageSettings.Landscape = $true
$PrintPageHandler =
{
param([object]$sender, [System.Drawing.Printing.PrintPageEventArgs]$ev)
$linesPerPage = 0
$yPos = 0
$count = 0
$leftMargin = $ev.MarginBounds.Left
$topMargin = $ev.MarginBounds.Top
$line = $null
$printFont = New-Object System.Drawing.Font "Arial", 10
# Calculate the number of lines per page.
$linesPerPage = $ev.MarginBounds.Height / $printFont.GetHeight($ev.Graphics)
# Print each line of the file.
while ($count -lt $linesPerPage -and (($line = ($text -split "`r`n")[$count]) -ne $null))
{
$yPos = $topMargin + ($count * $printFont.GetHeight($ev.Graphics))
$ev.Graphics.DrawString($line, $printFont, [System.Drawing.Brushes]::Black, $leftMargin, $yPos, (New-Object System.Drawing.StringFormat))
$count++
}
# If more lines exist, print another page.
if ($line -ne $null)
{
$ev.HasMorePages = $true
}
else
{
$ev.HasMorePages = $false
}
}
$PrintDocument.add_PrintPage($PrintPageHandler)
$PrintDocument.Print()
which I took from the corresponding articles on the internet, replacing StremReader from the file by line-by-line reading the multiline string.
How would I format text like that? Put some markers in the text, just like I do here or in HTML? and then parse them within $PrintPageHandler? Would I use $printFont for that or StringFormat in DrawString?
Please give me some direction to keep digging...
Hm, because you have outlook, I'm going to assume you have Word as well. Using the Word COM object is the only really easy way I can think of doing what you're trying to do.
#didn't know how you generated the calender info, so I took liberties here, using nested hashtables
$calendarStuff = #{
week1 = #{
Monday = #(
"Meeting with Joe : 07:00 - 08:00",
"Meeting with Ann : 8:30 - 09:00"
);
Tuesday = #("No meetings")
}
}
#path where to save the doc
$docPath = "C:\temp\printTestThing.docx"
# instantiation of the com-object. It's by default not visible
$wordCom = New-Object -ComObject Word.Application
# uncomment this to see what's going on
#$wordCom.visible = $true
# creates and selects the word document we'll be working with
$doc = $wordCom.Documents.Add()
$selection = $wordcom.Selection
# go through and grab each week
foreach($week in $calendarStuff.Keys)
{
# go through each week and grab the days
foreach($day in $calendarStuff[$week].keys)
{
# Apply the style 'Heading 1' to what we're about to type
$selection.Style = "Heading 1"
# type out what the day is
$selection.TypeText($day)
# make a paragraph
$selection.TypeParagraph()
# switch the style back to normal
$selection.Style = "Normal"
foreach($thing in $calendarStuff[$week][$day])
{
# type out what the event is, prepending it with a 'tab' character
$selection.TypeText("`t" + $thing)
# make a paragraph
$selection.TypeParagraph()
}
}
}
# print the doc
Start-Process -FilePath $docPath -Verb print
You can add way more customization if you want, but hopefully this is the catalyst you needed.
Example of what this looks like if printed to pdf

Date created doesn't work but the hard coded does

I´m trying to consume an api with two dates: startDate and endDate, when I use harcoded endDate the program works, but when I try to use a date that I create it doesn´t
$date = Get-Date
$year = $date.year
$month = $date.Month
$startDate2 = $year.ToString() + "-" + $month.ToString() + "-" + 01 + "T00:00:00.000-00:00"
$startDate = "2020-5-1T00:00:00.000-00:00"
$endDate2 = Get-Date -Format "yyyy-MM-ddTHH:mm:ss"
$toAdd = ".205-07:00"
$endDate2 = $endDate2 + $toAdd
#2019-06-23T09:07:21.205-07:00
Write-Host $endDate2
#Armar el url con las dos fechas
$url_api2 = "https://api.mypurecloud.com/api/v2/billing/reports/billableusage?startDate=" + $startDate2 +"&endDate=" + `
$endDate2
Both look the same in structure:
Hardcoded:
2019-06-23T09:07:21.205-07:00
Created
2020-05-29T15:23:48.000-00:00
The api documentation says that this must be the format
"yyyy-MM-ddTHH:mm:ss.SSSZ"
It comes like this
2020-05-29T16:58:37.SSSZ
So I manipulate de final part to remove the letters
Looks like ISO 8601. Try this.
Get-Date -Format o
Round-trip specifier
You shouldn't need the $toAdd variable then.

Powershell get-date in 1st,2nd,2rd,4th Formats

I am trying to format a date in PowerShell as DayOfWeek Month Day(st|nd|rd|th) year format.
(Get-Date).AddDays(+1).ToString('D')
The output is "Tuesday, July 05, 2016"
but need it in this format: Tuesday July 5th 2016
if date(Get-Date) % 100 IN (11, 12, 13) THEN 'th'
if (Get-Date) % 10 = 1 THEN 'st'
if (Get-Date) % 10 = 2 THEN 'nd'
if (Get-Date) % 10 = 3 THEN 'rd'
One possible solution could look like this
function Get-DateOrdinalSuffix([datetime]$Date) {
switch -regex ($Date.Day.ToString()) {
'1(1|2|3)$' { 'th'; break }
'.?1$' { 'st'; break }
'.?2$' { 'nd'; break }
'.?3$' { 'rd'; break }
default { 'th'; break }
}
}
$d = (Get-Date).AddDays(1)
$suffix = Get-DateOrdinalSuffix $d
$dateFormatted = "{0} {1:MMMM} {2}{3} {4}" -f $d.DayOfWeek, $d, $d.Day, $suffix, $d.Year
Another solution without using regex to get the day suffix:
function Get-DaySuffix
{
Param(
[System.DateTime]$date
)
switch ($date.Day)
{
{$_ -in 1,21,31} { 'st'}
{$_ -in 2,22} { 'nd'}
{$_ -in 3,23} { 'rd'}
Default {'th'}
}
}
$date = (Get-Date).AddDays(1)
$output = $date.ToString('dddd MMMM d yyyy', [CultureInfo]::CreateSpecificCulture('en-US'))
$output -replace '( \d{4})$', ('{0}$1'-f (Get-DaySuffix $date))
Output:
Tuesday July 5th 2016

Display current time with time zone in PowerShell

I'm trying to display the local time on my system with the TimeZone. How can I display time in this format the simplest way possible on any system?:
Time: 8:00:34 AM EST
I'm currently using the following script:
$localtz = [System.TimeZoneInfo]::Local | Select-Object -expandproperty Id
if ($localtz -match "Eastern") {$x = " EST"}
if ($localtz -match "Pacific") {$x = " PST"}
if ($localtz -match "Central") {$x = " CST"}
"Time: " + (Get-Date).Hour + ":" + (Get-Date).Minute + ":" + (Get-Date).Second + $x
I'd like to be able to display the time without relying on simple logic, but be able to give the local timezone on any system.
While this is a bit ... naive perhaps, it's one way to get an abbreviation without a switch statement:
[Regex]::Replace([System.TimeZoneInfo]::Local.StandardName, '([A-Z])\w+\s*', '$1')
My regular expression probably leaves something to be desired.
The output of the above for my time zone is EST. I did some looking as I wanted to see what the value would be for other GMT offset settings, but .NET doesn't seem to have very good links between DateTime and TimeZoneInfo, so I couldn't just programmatically run through them all to check. This might not work properly for some of the strings that come back for StandardName.
EDIT: I did some more investigation changing the time zone on my computer manually to check this and a TimeZoneInfo for GMT+12 looks like this:
PS> [TimeZoneInfo]::Local
Id : UTC+12
DisplayName : (GMT+12:00) Coordinated Universal Time+12
StandardName : UTC+12
DaylightName : UTC+12
BaseUtcOffset : 12:00:00
SupportsDaylightSavingTime : False
Which produces this result for my code:
PS> [Regex]::Replace([System.TimeZoneInfo]::Local.StandardName, '([A-Z])\w+\s*', '$1')
U+12
So, I guess you'd have to detect whether the StandardName appears to be a set of words or just offset designation because there's no standard name for it.
The less problematic ones outside the US appear to follow the three-word format:
PS> [TimeZoneInfo]::Local
Id : Tokyo Standard Time
DisplayName : (GMT+09:00) Osaka, Sapporo, Tokyo
StandardName : Tokyo Standard Time
DaylightName : Tokyo Daylight Time
BaseUtcOffset : 09:00:00
SupportsDaylightSavingTime : False
PS> [Regex]::Replace([System.TimeZoneInfo]::Local.StandardName, '([A-Z])\w+\s*', '$1')
TST
You should look into DateTime format strings. Although I'm not sure they can return a time zone short name, you can easily get an offset from UTC.
$formatteddate = "{0:h:mm:ss tt zzz}" -f (get-date)
This returns:
8:00:34 AM -04:00
Be loath to define another datetime format! Use an existing one, such as RFC 1123. There's even a PowerShell shortcut!
Get-Date -format r
Thu, 14 Jun 2012 16:44:18 GMT
Ref.: Get-Date
This is a better answer:
$A = Get-Date #Returns local date/time
$B = $A.ToUniversalTime() #Convert it to UTC
# Figure out your current offset from UTC
$Offset = [TimeZoneInfo]::Local | Select BaseUtcOffset
#Add the Offset
$C = $B + $Offset.BaseUtcOffset
$C.ToString()
Output:
3/20/2017 11:55:55 PM
I'm not aware of any object that can do the work for you. You could wrap the logic in a function:
function Get-MyDate{
$tz = switch -regex ([System.TimeZoneInfo]::Local.Id){
Eastern {'EST'; break}
Pacific {'PST'; break}
Central {'CST'; break}
}
"Time: {0:T} $tz" -f (Get-Date)
}
Get-MyDate
Or even take the initials of the time zone id:
$tz = -join ([System.TimeZoneInfo]::Local.Id.Split() | Foreach-Object {$_[0]})
"Time: {0:T} $tz" -f (Get-Date)
I just combined several scripts and finally was able to run the script in my domain controller.
The script provides the output of time and timezone for all the machines connected under the domain.
We had a major issue with our application servers and used this script to cross check the time and timezone.
# The below scripts provides the time and time zone for the connected machines in a domain
# Appends the output to a text file with the time stamp
# Checks if the host is reachable or not via a ping command
Start-Transcript -path C:\output.txt -append
$ldapSearcher = New-Object directoryservices.directorysearcher;
$ldapSearcher.filter = "(objectclass=computer)";
$computers = $ldapSearcher.findall();
foreach ($computer in $computers)
{
$compname = $computer.properties["name"]
$ping = gwmi win32_pingstatus -f "Address = '$compname'"
$compname
if ($ping.statuscode -eq 0)
{
try
{
$ErrorActionPreference = "Stop"
Write-Host “Attempting to determine timezone information for $compname…”
$Timezone = Get-WMIObject -class Win32_TimeZone -ComputerName $compname
$remoteOSInfo = gwmi win32_OperatingSystem -computername $compname
[datetime]$remoteDateTime = $remoteOSInfo.convertToDatetime($remoteOSInfo.LocalDateTime)
if ($Timezone)
{
foreach ($item in $Timezone)
{
$TZDescription = $Timezone.Description
$TZDaylightTime = $Timezone.DaylightName
$TZStandardTime = $Timezone.StandardName
$TZStandardTime = $Timezone.StandardTime
}
Write-Host "Timezone is set to $TZDescription`nTime and Date is $remoteDateTime`n**********************`n"
}
else
{
Write-Host ("Something went wrong")
}
}
catch
{
Write-Host ("You have insufficient rights to query the computer or the RPC server is not available.")
}
finally
{
$ErrorActionPreference = "Continue"
}
}
else
{
Write-Host ("Host $compname is not reachable from ping `n")
}
}
Stop-Transcript
Russia, France, Norway, Germany:
get-date -format "HH:mm:ss ddd dd'.'MM'.'yy' г.' zzz"
Output for Russian time zone: 22:47:27 Чт 21.11.19 г. +03:00
Others - just change the code.
If you have a internet connection... API
Function tzAbbreviation {
Try {
$webData = Invoke-WebRequest -Uri "https://worldtimeapi.org/api/ip" -UseBasicParsing -TimeoutSec 3 -ErrorAction Stop
$Content = ConvertFrom-Json $webData.Content
Return $($Content.Abbreviation)
}
Catch {}
}
$tzAbbreviation = tzAbbreviation
In the Netherlands...
Output: CET