PSDates.psm1
#Region '.\Classes\DateTimeExtended.ps1' -1 class DateTimeExtended { [datetime]$DateTime [datetime]$FirstDayOfYear [datetime]$LastDayOfYear [datetime]$StartOfWeek [datetime]$EndOfWeek [datetime]$StartOfMonth [datetime]$EndOfMonth [string]$WeekOfYear [System.TimeZoneInfo]$TimeZone [int]$Quarter [datetime]$Date [int]$Day [System.DayOfWeek]$DayOfWeek [int]$DayOfYear [int]$Hour [System.DateTimeKind]$Kind [int]$Millisecond [int]$Minute [int]$Month [int]$Second [long]$Ticks [timespan]$TimeOfDay [int]$Year DateTimeExtended( [DateTime]$Date ) { $local:StartOfWeek = Get-Date $date -hour 0 -minute 0 -second 0 $local:EndOfWeek = Get-Date $date -hour 23 -minute 59 -second 59 $local:StartOfMonth = Get-Date $date -day 1 -hour 0 -minute 0 -second 0 $this.DateTime = $Date $this.FirstDayOfYear = (Get-Date $date -hour 0 -minute 0 -second 0 -Day 1 -Month 1) $this.LastDayOfYear = (Get-Date $date -hour 0 -minute 0 -second 0 -Day 31 -Month 12) $this.StartOfWeek = ($StartOfWeek.AddDays( - ($StartOfWeek).DayOfWeek.value__)) $this.EndOfWeek = ($EndOfWeek.AddDays(6 - ($StartOfWeek).DayOfWeek.value__)) $this.StartOfMonth = ($StartOfMonth) $this.EndOfMonth = ((($StartOfMonth).AddMonths(1).AddSeconds(-1))) $this.WeekOfYear = (Get-Date $date -uformat %V) $this.TimeZone = ([System.TimeZoneInfo]::Local) $this.Quarter = [Math]::ceiling($Date.Month / 3) $this.Date = $Date.Date $this.Day = $Date.Day $this.DayOfWeek = $Date.DayOfWeek $this.DayOfYear = $Date.DayOfYear $this.Hour = $Date.Hour $this.Kind = $Date.Kind $this.Millisecond = $Date.Millisecond $this.Minute = $Date.Minute $this.Month = $Date.Month $this.Second = $Date.Second $this.Ticks = $Date.Ticks $this.TimeOfDay = $Date.TimeOfDay $this.Year = $Date.Year } # wrapper for the different datetime methods # had to be don this way since the datetime struct is sealed [DateTimeExtended] Add([timespan] $value) { Return [DateTimeExtended]::New($this.DateTime.Add($value)) } [DateTimeExtended] AddDays([double] $value) { Return [DateTimeExtended]::New($this.DateTime.AddDays($value)) } [DateTimeExtended] AddHours([double] $value) { Return [DateTimeExtended]::New($this.DateTime.AddHours($value)) } [DateTimeExtended] AddMilliseconds([double] $value) { Return [DateTimeExtended]::New($this.DateTime.AddMilliseconds($value)) } [DateTimeExtended] AddMinutes([double] $value) { Return [DateTimeExtended]::New($this.DateTime.AddMinutes($value)) } [DateTimeExtended] AddMonths([int] $value) { Return [DateTimeExtended]::New($this.DateTime.AddMonths($value)) } [DateTimeExtended] AddSeconds([double] $value) { Return [DateTimeExtended]::New($this.DateTime.AddSeconds($value)) } [DateTimeExtended] AddTicks([long] $value) { Return [DateTimeExtended]::New($this.DateTime.AddTicks($value)) } [DateTimeExtended] AddYears([int] $value) { Return [DateTimeExtended]::New($this.DateTime.AddYears($value)) } [DateTimeExtended] ToLocalTime() { Return [DateTimeExtended]::New($this.DateTime.ToLocalTime()) } [DateTimeExtended] ToUniversalTime() { Return [DateTimeExtended]::New($this.DateTime.ToUniversalTime()) } } #EndRegion '.\Classes\DateTimeExtended.ps1' 104 #Region '.\Classes\DateTimeFormats.ps1' -1 class DateTimeFormats { [string] $24HourTime [datetime] $DateTime [int32] $Day [string] $DayAbrv [string] $DayName [int32] $DayOfWeek [Int64] $FileTime [string] $FullDateShortTime [string] $FullDateTime [string] $GeneralDateShortTime [string] $GeneralDateTime [Boolean] $IsDaylightSavingTime [Boolean] $IsLeapYear [string] $ISO8601 [string] $ISO8601UTC [string] $LongDate [string] $LongDateNoDay [string] $LongTime [int32] $Month [string] $MonthAbrv [string] $MonthDay [string] $MonthName [int32] $Quater [string] $RFC1123 [string] $RFC1123UTC [string] $RoundTrip [string] $ShortDate [string] $ShortTime [string] $SortableDateTime [string] $SQL [string] $UniversalFullDateTime [string] $UniversalSortableDateTime [int32] $UnixEpochTime [string] $WimDatetime [int32] $Year [string] $YearMonth [string] $YearQuater [string] getStringProperty() { return $this.StringProperty } } #EndRegion '.\Classes\DateTimeFormats.ps1' 44 #Region '.\Classes\GroupTimeSpan.ps1' -1 class TimeSpanGroupInfo { [int] $Count [datetime] $DateTime [object] $Group TimeSpanGroupInfo([Int64]$Ticks, [int]$Count) { $this.Count = $Count $this.DateTime = (Get-Date 1/1/0001).AddTicks($Ticks) $this.Group = @() } TimeSpanGroupInfo([Microsoft.PowerShell.Commands.GroupInfo]$GroupInfo) { $this.Count = $GroupInfo.Count $this.DateTime = (Get-Date 1/1/0001).AddTicks($GroupInfo.Name) $this.Group = $GroupInfo.Group.Object } } #EndRegion '.\Classes\GroupTimeSpan.ps1' 17 #Region '.\Classes\SunTime.ps1' -1 class SunTime { [double] $Latitude [double] $Longitude [int64] $Now [double] $JulianDate [double] $JulianDay [double] $MeanSolarTime [double] $SolarMeanAnomaly [double] $EquationOfTheCenter [double] $EclipticLongitude [double] $SolarTransitTime [double] $HourAngle [DateTime] $Sunrise [DateTime] $Sunset [double] $DayLength [TimeZoneInfo] $TimeZone [string] ToDegreeString([double] $value) { $x = [math]::Round($value * 3600) $num = "∠{0:N3}°" -f $value $rad = "∠{0:N3}rad" -f ($value * ([math]::PI / 180)) $human = "∠{0}°{1}′{2}″" -f ($x / 3600), ($x / 60 % 60), ($x % 60) return "$rad = $human = $num" } [string] FromTimestamp([double]$Timestamp, [System.TimeZoneInfo]$TimeZone = $null) { $datetime = ConvertFrom-UnixTime $Timestamp if ($TimeZone) { $datetime = [System.TimeZoneInfo]::ConvertTimeFromUtc($datetime, $TimeZone) } return $datetime.ToString() } [double] JulianToTimestamp( [double]$Julian ) { return ($Julian - 2440587.5) * 86400 } [double] TimestampToJulian ( [double]$Timestamp ) { return $Timestamp / 86400.0 + 2440587.5 } } #EndRegion '.\Classes\SunTime.ps1' 47 #Region '.\Classes\TimeSpanMeasureInfo.ps1' -1 class TimeSpanMeasureInfo { [datetime] $DateTime [int] $Count [Nullable[System.Double]] $Average [Nullable[System.Double]] $Sum [Nullable[System.Double]] $Maximum [Nullable[System.Double]] $Minimum [string] $Property TimeSpanMeasureInfo([datetime]$DateTime, [Microsoft.PowerShell.Commands.GenericMeasureInfo]$Measure) { $this.DateTime = $DateTime $this.Property = $Measure.Property $this.Count = $Measure.Count if($null -ne $Measure.Average){$this.Average = $Measure.Average} if($null -ne $Measure.Sum){$this.Sum = $Measure.Sum} if($null -ne $Measure.Maximum){$this.Maximum = $Measure.Maximum} if($null -ne $Measure.Minimum){$this.Minimum = $Measure.Minimum} } TimeSpanMeasureInfo([datetime]$DateTime, [string]$Property, [int]$count) { $this.DateTime = $DateTime $this.Property = $Property $this.Count = $count } } #EndRegion '.\Classes\TimeSpanMeasureInfo.ps1' 26 #Region '.\Classes\TimeZoneConversion.ps1' -1 class TimeZoneConversion { [DateTime] $FromDateTime [String] $FromTimeZone [DateTime] $ToDateTime [String] $ToTimeZone [TimeSpan] $Offset TimeZoneConversion ($ToTimeZone, $Date, $FromTimeZone) { $DateTime = [DateTime]::SpecifyKind($Date, [DateTimeKind]::Unspecified) $from = [System.TimeZoneInfo]::FindSystemTimeZoneById($FromTimeZone) $to = [System.TimeZoneInfo]::FindSystemTimeZoneById($ToTimeZone) $utc = [System.TimeZoneInfo]::ConvertTimeToUtc($DateTime, $from) $newTime = [System.TimeZoneInfo]::ConvertTime($utc, $to) $this.FromDateTime = $Date $this.FromTimeZone = $FromTimeZone $this.ToDateTime = $newTime $this.ToTimeZone = $ToTimeZone $this.Offset = (New-TimeSpan -Start $date -End $newTime) } } #EndRegion '.\Classes\TimeZoneConversion.ps1' 22 #Region '.\Public\Convert-TimeZone.ps1' -1 Function Convert-TimeZone { <# .SYNOPSIS Convert a datetime value from one time zone to another .DESCRIPTION This function will allows you to pass a date to convert from one time zone to another. If no date is specified the local time is used. If no FromTimeZone is passed then the local time zone is used. If you don't know the time zone ID you can use the Find-TimeZone cmdlet. .PARAMETER ToTimeZone The time zone ID of the time zone you want to convert the date to .PARAMETER date The date to convert. If not specified the current time will be used .PARAMETER FromTimeZone The time zone ID of the time zone you want to convert the date from. If not specified the local time zone will be used .EXAMPLE Convert-TimeZone -ToTimeZone "GMT Standard Time" Convert the local system time to GMT Standard Time .EXAMPLE Convert-TimeZone -date '11/17/2017 12:34 AM' -FromTimeZone "China Standard Time" -ToTimeZone "US Mountain Standard Time" Converts the date and time 11/17/2017 12:34 AM from 'China Standard Time' to 'US Mountain Standard Time' .OUTPUTS A PSObject object containing the time zone conversion data #> [CmdletBinding()] [OutputType([TimeZoneConversion])] param( [parameter(Mandatory = $True)] [Validatescript( { try { $id = $_; [System.TimeZoneInfo]::FindSystemTimeZoneById($_) } catch { throw("'$Id' is not a valid time zone Id. Use the Find-TimeZone cmdlet to find the valid time zone Id.") } })] [string]$ToTimeZone, [Parameter(Mandatory = $false)] [datetime]$Date = $(Get-Date), [parameter(Mandatory = $false)] [Validatescript( { try { $id = $_; [System.TimeZoneInfo]::FindSystemTimeZoneById($_) } catch { throw("'$Id' is not a valid time zone Id. Use the Find-TimeZone cmdlet to find the valid time zone Id.") } })] [string]$FromTimeZone = [System.TimeZoneInfo]::Local.Id.ToString() ) [TimeZoneConversion]::new($ToTimeZone, $Date, $FromTimeZone) } #EndRegion '.\Public\Convert-TimeZone.ps1' 53 #Region '.\Public\Convert-ToDateTime.ps1' -1 function Convert-ToDateTime { <# .SYNOPSIS Converts various input objects to a DateTime object. .DESCRIPTION The `Convert-ToDateTime` function attempts to convert different types of input objects into a DateTime object. It supports input from various data types such as strings and objects that can be cast or converted to a DateTime. .PARAMETER InputObject Specifies the input object to be converted to a DateTime. This parameter accepts pipeline input and is mandatory. The input can be of any type: - If the input is already a DateTime, it will be returned as-is. - If the input is a string, it attempts to parse it into a DateTime. - Other input types will be processed accordingly, if possible. .EXAMPLE '2024-08-29' | Convert-ToDateTime Converts the string '2024-08-29' into a DateTime object representing the 29th of August, 2024. .INPUTS System.Object The function accepts objects from the pipeline, which are attempted to be converted to DateTime. .OUTPUTS System.DateTime The function outputs a DateTime object if the conversion is successful. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [Object]$InputObject ) process { $Return = $null try { # Attempt to convert directly if input is already a DateTime or string if ($InputObject -is [DateTime]) { $Return = $InputObject } elseif ($InputObject -is [string]) { try{ $Return = Get-Date $InputObject -ErrorAction Stop } catch{ # Attempt to parse string input to DateTime $Return = [DateTime]::ParseExact($InputObject, [System.Globalization.CultureInfo]::InvariantCulture.DateTimeFormat.GetAllDateTimePatterns(), [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::None) -as [DateTime] } } else { # Attempt conversion for other types using their string representation $Return = [DateTime]::Parse($InputObject.ToString(), [System.Globalization.CultureInfo]::InvariantCulture) -as [DateTime] } } catch { # Return error if conversion fails Write-Error "Unable to convert '$InputObject' to DateTime." } $Return } } #EndRegion '.\Public\Convert-ToDateTime.ps1' 70 #Region '.\Public\ConvertFrom-UnixTime.ps1' -1 Function ConvertFrom-UnixTime { <# .SYNOPSIS Converts a Unix Time value to a datetime value .DESCRIPTION This function will return the datetime based on the unix epoch time. .PARAMETER UnixTime The UnixTime value to return the datetime for .EXAMPLE ConvertFrom-UnixTime -UnixTime 1509512400 Gets datetime for the Unix time 1509512400 .OUTPUTS The datetime value based on the unix time #> [CmdletBinding()] [OutputType([datetime])] param( [Parameter(Mandatory = $true)] [double]$UnixTime ) (Get-Date '1970-01-01T00:00:00.000Z').ToUniversalTime().AddSeconds($UnixTime) } #EndRegion '.\Public\ConvertFrom-UnixTime.ps1' 29 #Region '.\Public\ConvertFrom-WmiDateTime.ps1' -1 Function ConvertFrom-WmiDateTime { <# .SYNOPSIS Converts a Wmi Time value to a datetime value .DESCRIPTION This function will return the datetime based on a WMI datetime string. .PARAMETER WmiTime The WmiTime value to return the datetime for .EXAMPLE ConvertFrom-WmiDateTime -WmiTime '20190912173652.000000-300' Gets datetime for the Wmi time 20190912173652.000000-300 .OUTPUTS The datetime value based on the wmi time #> [CmdletBinding()] [OutputType([datetime])] param( [Parameter(Mandatory = $true)] [string]$WmiTime ) # Extract individual components from the WMI DateTime string $year = [int]$WmiTime.Substring(0, 4) $month = [int]$WmiTime.Substring(4, 2) $day = [int]$WmiTime.Substring(6, 2) $hour = [int]$WmiTime.Substring(8, 2) $minute = [int]$WmiTime.Substring(10, 2) $second = [int]$WmiTime.Substring(12, 2) $millisecond = [int]$WmiTime.Substring(15, 6) # Create a DateTime object $dateTime = [datetime]::SpecifyKind(([datetime]"$year-$month-$day $($hour):$($minute):$second.$millisecond"), 'Utc') # Create a TimeSpan object for the UTC offset if ($WmiTime -match '\+') { $offsetMinutes = [int]$WmiTime.Split('+')[-1] $offset = New-TimeSpan -Minutes $offsetMinutes # Adjust for the UTC offset $dateTime = $dateTime.Add(-$offset) } elseif ($WmiTime -match '\-') { $offsetMinutes = [int]$WmiTime.Split('-')[-1] $offset = New-TimeSpan -Minutes $offsetMinutes # Adjust for the UTC offset $dateTime = $dateTime.Add($offset) } # Convert to local time and output $dateTime.ToLocalTime() } #EndRegion '.\Public\ConvertFrom-WmiDateTime.ps1' 55 #Region '.\Public\ConvertTo-UnixTime.ps1' -1 Function ConvertTo-UnixTime { <# .SYNOPSIS Converts a datetime value to Unix Time .DESCRIPTION This function will return the unix time based on the unix epoch time. If no date is passed in the current date and time is used. .PARAMETER Date The datetime value to return the unix time for .EXAMPLE ConvertTo-UnixTime Gets unix time for the current time .EXAMPLE ConvertTo-UnixTime -date "11/17/2017" Gets unix time for a specific date .OUTPUTS The int32 value of the unix time #> [CmdletBinding()] [OutputType([int32])] param( [Parameter(Mandatory = $false)] [datetime]$date = $(Get-Date) ) [int][double]::Parse((Get-Date ($date).touniversaltime() -UFormat %s)) } #EndRegion '.\Public\ConvertTo-UnixTime.ps1' 27 #Region '.\Public\ConvertTo-WmiDateTime.ps1' -1 Function ConvertTo-WmiDateTime { <# .SYNOPSIS Converts a datetime value to a Wmi datetime string .DESCRIPTION This function will return the WMI datetime string based on a datetime passed. .PARAMETER Date Specifies a date and time. .EXAMPLE ConvertTo-WmiDateTime -Date '06/25/2019 16:17' Return the WMI datetime string for the datetime of "06/25/2019 16:17" .OUTPUTS The string value based on the datetime #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $false)] [datetime]$Date = (Get-Date) ) $wmiString = $Date.ToString("yyyyMMddHHmmss.ffffff") if($Date.Kind -eq 'Utc'){ $wmiString += '+000' } else{ $offset = ([System.TimeZoneInfo]::Local).BaseUtcOffset.TotalMinutes $wmiString += "$($offset)" } $wmiString } #EndRegion '.\Public\ConvertTo-WmiDateTime.ps1' 37 #Region '.\Public\Find-TimeZone.ps1' -1 Function Find-TimeZone { <# .SYNOPSIS Returns Time Zone information .DESCRIPTION This function will return the information for the system time zones. You can search by name and/or hour offsets. You can also return the local time zone. .PARAMETER Name All or part of the time zone name. Will be used to perform a wildcard search on the time zones .PARAMETER Offset The number of hours the time zone is offset from UTC .PARAMETER local Use to return the time zone of the current system .PARAMETER OutGrid Use to output time zone selects to Grid View .EXAMPLE Find-TimeZone -local Return the time zone of the local system .EXAMPLE Find-TimeZone -Name "GMT" Search for time zones with 'GMT' in the name .EXAMPLE Find-TimeZone -Name "central" -Offset -6 Search for time zones with 'Central' in the name and have a UTC offset of -6 hours .OUTPUTS The TimeZoneInfo value or values found #> [CmdletBinding()] [OutputType([System.TimeZoneInfo])] param( [parameter(Mandatory = $false)][string]$Name, [parameter(Mandatory = $false)][int]$Offset, [parameter(Mandatory = $false)][switch]$Local, [parameter(Mandatory = $false)][switch]$OutGrid ) if ($Local) { [System.TimeZoneInfo]::Local } else { $TimeZones = [System.TimeZoneInfo]::GetSystemTimeZones() if ($Name) { $TimeZones = $TimeZones | Where-Object { $_.DisplayName -like "*$($Name)*" -or $_.DaylightName -like "*$($Name)*" -or $_.StandardName -like "*$($Name)*" -or $_.Id -like "*$($Name)*" } } if ($Offset) { $TimeZones = $TimeZones | Where-Object { $_.BaseUtcOffset.Hours -eq $Offset } } if ($OutGrid) { $TimeZones | Out-Gridview -Title "Select the timezone(s) to return" -PassThru } else { $TimeZones } } } #EndRegion '.\Public\Find-TimeZone.ps1' 71 #Region '.\Public\Get-CronDescription.ps1' -1 Function Get-CronDescription { <# .SYNOPSIS Convert a cron expression into a human readable description .DESCRIPTION Uses the .NET library CronExpressionDescriptor to convert cron expressions into human readable descriptions. .PARAMETER Crontab A valid crontab string .PARAMETER DayOfWeekStartIndexOne When used Sunday will equal 1, otherwise Sunday will be 0. (Default: Sunday = 0) .PARAMETER Use24HourTimeFormat If true, descriptions will use a 24-hour clock (Default: false but some translations will default to true) .PARAMETER Locale The locale to use (Default: "en") Supported values: cs-CZ, da, de, es, es-MX, fa, fi, fr, he-IL, hu, it, ja, ko, nb, nl, pl, pt, ro, ru, sl, sv, tr, uk, vi, zh-Hans, zh-Hant .EXAMPLE Get-CronDescription -Crontab '0 17 * * 1' Results with default options: At 05:00 PM, only on Monday .EXAMPLE Get-CronDescription -Crontab '0 17 * * 1' -DayOfWeekStartIndexOne Results with DayOfWeekStartIndexOne switch returns Sunday for the 1 instead of Monday: At 05:00 PM, only on Sunday .EXAMPLE Get-CronDescription -Crontab '0 17 * * 1' -Use24HourTimeFormat Results with Use24HourTimeFormat options: At 17:00, only on Monday .EXAMPLE Get-CronDescription -Crontab '0 17 * * 1' -Locale 'fr' Results with fr Locale options: At 05:00 PM, only on lundi .OUTPUTS A psobject that contains the crontable, a validation value, and any error messages returned #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)] [string]$Crontab, [Parameter(Mandatory = $false)] [switch]$DayOfWeekStartIndexOne = $false, [Parameter(Mandatory = $false)] [switch]$Use24HourTimeFormat = $false, [Parameter(Mandatory = $false)] [ValidateSet('cs-CZ','da','de','es','es-MX','fa','fi','fr','he-IL','hu','it','ja','ko','nb','nl','pl','pt','ro','ru','sl','sv','tr','uk','vi','zh-Hans','zh-Hant')] [string]$Locale = 'en' ) # Set options $options = [CronExpressionDescriptor.Options]::new() if($DayOfWeekStartIndexOne){ $options.DayOfWeekStartIndexZero = $false } $options.Use24HourTimeFormat = $Use24HourTimeFormat $options.Locale = $Locale # Get Description [CronExpressionDescriptor.ExpressionDescriptor]::GetDescription($Crontab, $options) } #EndRegion '.\Public\Get-CronDescription.ps1' 74 #Region '.\Public\Get-CronNextOccurrence.ps1' -1 Function Get-CronNextOccurrence { <# .SYNOPSIS Get the next occurrence for a crontab .DESCRIPTION This function will either return the next occurrence, or if an end date is supplied, it will return all the occurrences between the start and end date. .PARAMETER Crontab A valid crontab string .PARAMETER StartTime The datetime object to find the next occurrence from. Uses current time if not supplied. .PARAMETER EndTime The datetime object to stop finding occurrences for from the StartTime .EXAMPLE Get-CronNextOccurrence -Crontab '0 17 * * *' Will return the next occurrence of the crontab from the current time .EXAMPLE $Date = Get-Date '12/14/2032' Get-CronNextOccurrence -Crontab '0 17 * * *' -StartTime $Date Will return the next occurrence of the crontab from the time provided .EXAMPLE Get-CronNextOccurrence -Crontab '0 17 * * *' -StartTime $Date -EndTime $Date.AddDays(3) Will return the all occurrences of the crontab between the two times .OUTPUTS A datetime object for every occurrence returned #> [CmdletBinding()] [OutputType('datetime')] param( [Parameter(Mandatory = $true)] [string]$Crontab, [Parameter(Mandatory = $false)] [datetime]$StartTime = (Get-Date), [Parameter(Mandatory = $false)] [datetime]$EndTime ) # validat crontab $Schedule = Test-CrontabSchedule -Crontab $Crontab # if no end date, just get next occurrence, else find all occurrences between start and end if ($Schedule.valid -eq $true -and $null -eq $EndTime) { $schedule.schedule.GetNextOccurrence($StartTime) } elseif ($Schedule.valid -eq $true) { $schedule.schedule.GetNextOccurrences($StartTime, $EndTime) } else { throw $Schedule.ErrorMsg } } #EndRegion '.\Public\Get-CronNextOccurrence.ps1' 64 #Region '.\Public\Get-DateExtended.ps1' -1 Function Get-DateExtended { <# .SYNOPSIS Gets additional extended date values that are not included by default with the Get-Date cmdlet .DESCRIPTION This function includes added values for: FirstDayOfYear : First day of the year LastDayOfYear : Last day of the year StartOfWeek : First day of the week EndOfWeek : Last day of the week StartOfMonth : First day of the month EndOfMonth : Last day of the month TimeZone : Current machine timezone Quater : The quarter of the year. All dates are based on the date passed. If no date is passed in the current date and time are used. .PARAMETER Date The datetime value to return the information for .PARAMETER UnixTimeSeconds Date and time represented in seconds since January 1, 1970, 0:00:00. .PARAMETER Year Specifies the year that is displayed. Enter a value from 1 to 9999 .PARAMETER Month Specifies the month that is displayed. Enter a value from 1 to 12 .PARAMETER Day Specifies the day of the month that is displayed. Enter a value from 1 to 31. .PARAMETER Hour Specifies the hour that is displayed. Enter a value from 0 to 23. .PARAMETER Minute Specifies the minute that is displayed. Enter a value from 0 to 59. .PARAMETER Second Specifies the second that is displayed. Enter a value from 0 to 59. .PARAMETER Millisecond Specifies the milliseconds in the date. Enter a value from 0 to 999. .PARAMETER DisplayHint Determines which elements of the date and time are displayed. The accepted values are as follows: Date: displays only the date Time: displays only the time DateTime: displays the date and time .EXAMPLE Get-DateExtended Gets extended date and time information based on the current time .EXAMPLE Get-DateExtended "11/17/2017" Gets extended date and time information for a specific date .OUTPUTS A PSObject containing extended values for the date. #> [CmdletBinding()] [OutputType('DateTimeExtended')] param( [Parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias("LastWriteTime")] [DateTime]$Date = [DateTime]::Now, [Parameter()] [switch] $UnixTimeSeconds, [Parameter()] [ValidateRange(1, 9999)] [int] $Year, [Parameter()] [ValidateRange(1, 12)] [int] $Month, [Parameter()] [ValidateRange(1, 31)] [int] $Day, [Parameter()] [ValidateRange(0, 23)] [int] $Hour, [Parameter()] [ValidateRange(0, 59)] [int] $Minute, [Parameter()] [ValidateRange(0, 59)] [int] $Second, [Parameter()] [ValidateRange(0, 999)] [int] $Millisecond, [Parameter()] [ValidateSet('Date', 'Time', 'DateTime')] [string] $DisplayHint ) process { [DateTimeExtended]::New((Get-Date @PSBoundParameters)) } } #EndRegion '.\Public\Get-DateExtended.ps1' 114 #Region '.\Public\Get-DateFormat.ps1' -1 Function Get-DateFormat { <# .SYNOPSIS Returns common date and time formats .DESCRIPTION This function format date and time values into multiple different common formats. All dates are based on the date passed. If no date is passed in the current date and time are used. .PARAMETER Date The datetime value to return the formats for .EXAMPLE Get-DateFormats Gets formatted date and time information based on the current time .EXAMPLE Get-DateFormats -Date "11/17/2017" Gets formatted date and time information for a specific date .OUTPUTS A PSObject containing the diffent values for the datetime formats. #> [alias("Get-DateFormats")] [CmdletBinding(DefaultParameterSetName = "Full")] [OutputType([DateTimeFormats], ParameterSetName = "ID")] [OutputType([object], ParameterSetName = "Format")] param( [Parameter(Mandatory = $false, ParameterSetName = "Full")] [Parameter(Mandatory = $false, ParameterSetName = "Format")] [datetime]$Date = $(Get-Date), [Parameter(Mandatory = $false, ParameterSetName = "Format")] [string]$Format ) $offset = ([System.TimeZoneInfo]::Local).BaseUtcOffset.ToString() $offset = $offset.Substring(0, $offset.LastIndexOf(':')) $dateFormats = [DateTimeFormats]@{ DateTime = $Date.DateTime RFC1123UTC = $Date.ToUniversalTime().ToString('r') SQL = $Date.ToString("yyyy-MM-dd HH:mm:ss.fff") ISO8601UTC = $Date.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ") ISO8601 = $Date.ToString("yyyy-MM-ddTHH:mm:ss.fff") + $offset ShortDate = $Date.ToString('d') LongDate = $Date.ToString('D') LongDateNoDay = $Date.ToString('D').Substring($Date.ToString('D').IndexOf(',') + 2) FullDateShortTime = $Date.ToString('f') FullDateTime = $Date.ToString('F') GeneralDateShortTime = $Date.ToString('g') GeneralDateTime = $Date.ToString('G') MonthDay = $Date.ToString('M') RoundTrip = $Date.ToString('o') RFC1123 = $Date.ToString('r') SortableDateTime = $Date.ToString('s') ShortTime = $Date.ToString('t') LongTime = $Date.ToString('T') UniversalSortableDateTime = $Date.ToString('u') UniversalFullDateTime = $Date.ToString('U') YearMonth = $Date.ToString('Y') "24HourTime" = $Date.ToString("HH:mm") Day = $Date.Day DayAbrv = (Get-Culture).DateTimeFormat.GetAbbreviatedDayName($Date.DayOfWeek.value__) DayName = $Date.DayOfWeek.ToString() DayOfWeek = $Date.DayOfWeek.value__ Month = $Date.Month MonthName = (Get-Culture).DateTimeFormat.GetMonthName($Date.Month) MonthAbrv = (Get-Culture).DateTimeFormat.GetAbbreviatedMonthName($Date.Month) Quater = [Math]::ceiling($Date.Month / 3) YearQuater = "$($Date.Year)$("{0:00}" -f [Math]::ceiling($Date.Month/3) )" Year = $Date.Year WimDatetime = (ConvertTo-WmiDateTime $Date) UnixEpochTime = (ConvertTo-UnixTime $Date) IsDaylightSavingTime = $Date.IsDaylightSavingTime() IsLeapYear = [datetime]::IsLeapYear($Date.Year) FileTime = $Date.ToFileTime() } if ([string]::IsNullOrEmpty($PSBoundParameters['Format'])) { $dateFormats } else { $dateFormats."$($PSBoundParameters['Format'])" } } #EndRegion '.\Public\Get-DateFormat.ps1' 88 #Region '.\Public\Get-Easter.ps1' -1 Function Get-Easter { <# .SYNOPSIS This function offers a generic Easter computing method for any given year, using Western, Orthodox or Julian algorithms. .DESCRIPTION Shamelessly stolen from python dateutil (https://github.com/dateutil/dateutil/blob/master/src/dateutil/easter.py) .PARAMETER Year The year to get Easter from .PARAMETER Calendar Gregorian : is the default and valid from 1583 to 4099 Orthodox : valid from 1583 to 4099 Julian : valid from 326 .EXAMPLE Get-Easter -Year 2024 #> [CmdletBinding()] [OutputType([datetime])] param( [Parameter(Mandatory = $false)] [int]$year = (Get-Date).Year, [Parameter(Mandatory = $false)] [ValidateSet('Gregorian', 'Julian', 'Orthodox')] [string]$Calendar = 'Gregorian' ) # Golden year - 1 $g = $year % 19 $e = 0 if ($Calendar -ne 'Gregorian') { # Old method $i = (19 * $g + 15) % 30 $j = ($year + [math]::floor($year / 4) + $i) % 7 if ($Calendar -eq 'Orthodox') { # Extra dates to convert Julian to Gregorian date $e = 10 if ($year -gt 1600) { $e = $e + [math]::floor([math]::floor($year / 100) - 16 - ([math]::floor($year / 100) - 16) / 4) } } } else { # Century $c = [math]::floor($year / 100) # (23 - Epact) mod 30 $h = ($c - [math]::floor($c / 4) - [math]::floor((8 * $c + 13) / 25) + 19 * $g + 15) % 30 # Number of days from March 21 to Paschal Full Moon $i = $h - ([math]::floor($h / 28)) * (1 - ([math]::floor($h / 28)) * ([math]::floor(29 / ($h + 1))) * ([math]::floor((21 - $g) / 11))) # Weekday for PFM (0=Sunday, etc) $j = ($year + [math]::floor($year / 4) + $i + 2 - $c + [math]::floor($c / 4)) % 7 } # Number of days from March 21 to Sunday on or before PFM $p = $i - $j + $e $d = 1 + ($p + 27 + [math]::floor(($p + 6) / 40)) % 31 $m = 3 + [math]::floor(($p + 26) / 30) [datetime]::new($year, $m, $d) } #EndRegion '.\Public\Get-Easter.ps1' 67 #Region '.\Public\Get-PatchTuesday.ps1' -1 Function Get-PatchTuesday { <# .SYNOPSIS Returns the second Tuesday of the month .DESCRIPTION This function allow you to pass a date, or a month/year combination to find the second Tuesday (aka Patch Tuesday) of any month .PARAMETER Date The datetime value to return the second Tuesday for the month .PARAMETER Month The month to return the second Tuesday for. Enter a value from 1 to 12. .PARAMETER Year The year to return the second Tuesday for. Enter a value from 1 to 9999 .EXAMPLE Get-PatchTuesday Returns the second Tuesday for the current month .EXAMPLE Get-PatchTuesday -Date "11/17/2021" Returns the second Tuesday for November 2021 .EXAMPLE Get-PatchTuesday -Month 6 -Year 2020 Returns the second Tuesday for June 2020 .EXAMPLE Get-PatchTuesday -Month 4 Returns the second Tuesday for April of the current year .OUTPUTS A datetime object of the second Tuesday. #> [CmdletBinding(DefaultParameterSetName = 'Date')] [OutputType([datetime])] param( [Parameter(Mandatory = $false, ParameterSetName = "Date")] [datetime]$Date = $(Get-Date), [Parameter(Mandatory = $false, ParameterSetName = "MonthYear")] [ValidateRange(1, 12)] [int]$Month = $(Get-Date).Month, [Parameter(Mandatory = $false, ParameterSetName = "MonthYear")] [ValidateRange(1, 9999)] [int]$Year = $(Get-Date).Year ) if ($PsCmdlet.ParameterSetName -eq "MonthYear") { $date = (Get-Date -Day 1 -Month $Month -Year $Year).Date } # Get the first day of the month $StartOfMonth = Get-Date $date.Date -Day 1 # Get every Tuesday, and return the second one $ptdate = (0..30 | Foreach-Object { $StartOfMonth.adddays($_) } | Where-Object { $_.dayofweek.value__ -eq 2 })[1] $ptdate.Date } #EndRegion '.\Public\Get-PatchTuesday.ps1' 61 #Region '.\Public\Get-SunTime.ps1' -1 function Get-SunTime { <# .SYNOPSIS Find sunrise and sunset times for any location on planet Earth. .DESCRIPTION This function finds the time of day for sunrise, sunset based on the given latitude and longitude. You can also specify time zone and elevation. .PARAMETER Date The day to find the sunrise and sunset for. .PARAMETER Latitude The Latitude entered as a decimal number representing degrees and minutes .PARAMETER Longitude The Longitude entered as a decimal number representing degrees and minutes .PARAMETER Elevation The Elevation in meters .PARAMETER TimeZone The time zone for the final results .EXAMPLE Get-SunTime -Latitude 51.501005 -Longitude -0.1445479 # Get the sunrise and sunset for the given coordinates for the current day .EXAMPLE $address = '1600 Pennsylvania Avenue NW' $addr = Invoke-RestMethod "https://nominatim.openstreetmap.org/search?q=$($address)&format=json" | Select-Object -First 1 Get-SunTime -Latitude $addr.lat -Longitude $addr.lon # Use the free Nominatim API get the coordinates for an address, then use those results to get the sunrise and sunset for that location. .NOTES Use can use Google Maps to find the latitude and longitude coordinates. Right click a specific point on the Google map and you will see the latitude and longitude coordinates displayed, for example 45.51421, -122.68462. #> [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [datetime]$Date = $(Get-Date), [Parameter(Mandatory = $true)] [double]$Latitude, [Parameter(Mandatory = $true)] [double]$Longitude, [Parameter(Mandatory = $false)] [double]$Elevation = 0.0, [Parameter(Mandatory = $false)] [string]$TimeZone = $null ) $suntime = [SunTime]::new() $datetimeOffset = [DateTimeOffset]::new($Date) $CurrentTimestamp = $datetimeOffset.ToUniversalTime().ToUnixTimeSeconds() $TimeZoneInfo = [System.TimeZoneInfo]::Local if(-not [string]::IsNullOrEmpty($TimeZone)){ $TimeZoneInfo = [System.TimeZoneInfo]::FindSystemTimeZoneById($TimeZone) } Write-Verbose "Latitude f = $($suntime.ToDegreeString($Latitude))" Write-Verbose "Longitude l_w = $($suntime.ToDegreeString($Longitude))" Write-Verbose "Now ts = $($suntime.FromTimestamp($CurrentTimestamp, $TimeZoneInfo))" $J_date = $suntime.TimestampToJulian($CurrentTimestamp) Write-Verbose ("Julian date j_date = {0:N3} days" -f $J_date) # Julian day $n = [math]::Ceiling($J_date - (2451545.0 + 0.0009) + 69.184 / 86400.0) Write-Verbose ("Julian day n = {0:N3} days" -f $n) # Mean solar time $J_ = $n + 0.0009 - $Longitude / 360.0 Write-Verbose ("Mean solar time J_ = {0:N9} days" -f $J_) # Solar mean anomaly $M_degrees = [math]::IEEERemainder(357.5291 + 0.98560028 * $J_, 360) $M_radians = ($M_degrees * ([math]::PI / 180)) Write-Verbose "Solar mean anomaly M = $($suntime.ToDegreeString($M_degrees))" # Equation of the center $C_degrees = 1.9148 * [math]::Sin($M_radians) + 0.02 * [math]::Sin(2 * $M_radians) + 0.0003 * [math]::Sin(3 * $M_radians) Write-Verbose "Equation of the center C = $($suntime.ToDegreeString($C_degrees))" # Ecliptic longitude $L_degrees = [math]::IEEERemainder($M_degrees + $C_degrees + 180.0 + 102.9372, 360) Write-Verbose "Ecliptic longitude L = $($suntime.ToDegreeString($L_degrees))" $Lambda_radians = ($L_degrees * ([math]::PI / 180)) # Solar transit (julian date) $J_transit = 2451545.0 + $J_ + 0.0053 * [math]::Sin($M_radians) - 0.0069 * [math]::Sin(2 * $Lambda_radians) Write-Verbose "Solar transit time J_trans = $($suntime.FromTimestamp( $suntime.JulianToTimestamp($J_transit), $TimeZoneInfo))" # Declination of the Sun $sin_d = [math]::Sin($Lambda_radians) * [math]::Sin((23.4397 * ([math]::PI / 180))) $cos_d = [math]::Cos([math]::Asin($sin_d)) # Hour angle $some_cos = ([math]::Sin(-0.833 * [math]::PI / 180 - 2.076 * [math]::Sqrt($Elevation) / 60.0 * [math]::PI / 180) - [math]::Sin($Latitude * [math]::PI / 180) * $sin_d) / ([math]::Cos($Latitude * [math]::PI / 180) * $cos_d) $w0_radians = [math]::Acos($some_cos) $w0_degrees = $w0_radians * 180 / [math]::PI Write-Verbose "Hour angle w0 = $($suntime.ToDegreeString($w0_degrees))" $j_rise = $J_transit - $w0_degrees / 360 $j_set = $J_transit + $w0_degrees / 360 Write-Verbose "Sunrise j_rise = $($suntime.FromTimestamp( $suntime.JulianToTimestamp($j_rise), $TimeZoneInfo))" Write-Verbose "Sunset j_set = $($suntime.JulianToTimestamp($j_rise)) = $($suntime.FromTimestamp($suntime.JulianToTimestamp($j_set), $TimeZoneInfo))" Write-Verbose ("Day length {0:N3} hours" -f ($w0_degrees / (180 / 24))) [SunTime]@{ Latitude = $Latitude Longitude = $Longitude Now = $CurrentTimestamp JulianDate = $J_date JulianDay = $n MeanSolarTime = $J_ SolarMeanAnomaly = $M_degrees EquationOfTheCenter = $C_degrees EclipticLongitude = $L_degrees SolarTransitTime = $J_transit HourAngle = $w0_degrees Sunrise = (Get-Date $($suntime.FromTimestamp($suntime.JulianToTimestamp($j_rise), $TimeZoneInfo))) Sunset = (Get-Date $($suntime.FromTimestamp($suntime.JulianToTimestamp($j_set), $TimeZoneInfo))) DayLength = ($w0_degrees / (180 / 24)) TimeZone = $TimeZoneInfo } } #EndRegion '.\Public\Get-SunTime.ps1' 136 #Region '.\Public\Group-TimeSpan.ps1' -1 Function Group-TimeSpan { <# .SYNOPSIS Groups objects by a specified time span. .DESCRIPTION The `Group-TimeSpan` function takes a collection of objects and groups them based on a specified time span. It supports grouping by properties such as days, hours, minutes, etc., allowing for flexible data grouping. .PARAMETER InputObject Specifies the input objects to be grouped. This parameter accepts pipeline input. .PARAMETER Property Specifies the property name of the InputObject to use for grouping. The property should be of a DateTime type. .PARAMETER Years Specifies the number of years to group by. .PARAMETER Months Specifies the number of months to group by. .PARAMETER Days Specifies the number of days to group by. .PARAMETER Hours Specifies the number of hours to group by. .PARAMETER Minutes Specifies the number of minutes to group by. .PARAMETER Seconds Specifies the number of seconds to group by. .EXAMPLE Get-ChildItem $PSHOME | Group-TimeSpan -Property CreationTime -Hours 1 Groups the files by each hour based on their CreationTime. .EXAMPLE Get-ChildItem $PSHOME | Group-TimeSpan -Property CreationTime -Days 7 Groups the files by 7 days based on their CreationTime. .OUTPUTS TimeSpanGroupInfo[] Returns an array of TimeSpanGroupInfo objects. #> [CmdletBinding()] [OutputType([TimeSpanGroupInfo[]])] param ( [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true )] [Alias("PSObject")] [object]$InputObject, [Parameter(Mandatory = $false)] [string]$Property = $null, [Parameter(Mandatory = $false)] [switch]$IncludeAllTimes = $false, [Parameter(Mandatory = $true, ParameterSetName = "Years")] [int]$Years, [Parameter(Mandatory = $true, ParameterSetName = "Months")] [int]$Months, [Parameter(Mandatory = $true, ParameterSetName = "Days")] [int]$Days, [Parameter(Mandatory = $true, ParameterSetName = "Hours")] [int]$Hours, [Parameter(Mandatory = $true, ParameterSetName = "Minutes")] [int]$Minutes, [Parameter(Mandatory = $true, ParameterSetName = "Seconds")] [int]$Seconds ) begin { $Null = $Years, $Months # Prevent PSReviewUnusedParameter false positive [Collections.Generic.List[PSObject]] $objects = @() switch ($PsCmdlet.ParameterSetName) { "Days" { $ticks = 36000000000 * 24 * $Days } "Hours" { $ticks = 36000000000 * $Hours } "Minutes" { $ticks = 600000000 * $Minutes } "Seconds" { $ticks = 10000000 * $Seconds } } } process { $InputObject | Foreach-Object { if (-not [string]::IsNullOrEmpty( $Property )) { $timeValue = $_.$Property } else { $timeValue = $_ } $objects.Add([pscustomobject]@{ TimeProperty = $timeValue | Convert-ToDateTime Object = $_ }) } } end { $min = [datetime]::MinValue $groupedDates = $objects | Group-Object { if ($PSBoundParameters['Months']) { # Monthly $monthsDifference = (($_.TimeProperty.Year - $min.Year) * 12 + $_.TimeProperty.Month - $min.Month) $groupStartMonth = [math]::Floor($monthsDifference / $Months) * $Months $month = $min.AddMonths($groupStartMonth) (Get-Date -Year $month.Year -Month $month.Month -day 1 -hour 0 -minute 0 -second 0 -Millisecond 0).Ticks } elseif ($PSBoundParameters['Years']) { # Yearly $yearDifference = $_.TimeProperty.Year - $min.Year $groupStartYear = [math]::Floor($yearDifference / $Years) * $Years $year = $min.AddMonths($groupStartYear * 12) (Get-Date -Year $year.Year -Month 1 -day 1 -hour 0 -minute 0 -second 0 -Millisecond 0).Ticks } else { $min.Ticks - (($min.Ticks - $_.TimeProperty.Ticks) - (($min.Ticks - $_.TimeProperty.Ticks) % $ticks)) } } [TimeSpanGroupInfo[]]$output = $groupedDates | ForEach-Object { [TimeSpanGroupInfo]::new($_) } if($IncludeAllTimes){ $FirstTime = $output | Sort-Object DateTime | Select-Object -First 1 -ExpandProperty DateTime | Select-Object -ExpandProperty Ticks $LastTime = $output | Sort-Object DateTime | Select-Object -Last 1 -ExpandProperty DateTime | Select-Object -ExpandProperty Ticks $blankTimes = while($FirstTime -lt $LastTime){ $toAdd = [TimeSpanGroupInfo]::new($FirstTime, 0) if($output.DateTime -notcontains $toAdd.DateTime){ $toAdd } if ($PSBoundParameters['Months']) { $FirstTime = $toAdd.DateTime.AddMonths($Months).Ticks } elseif ($PSBoundParameters['Years']) { $FirstTime = $toAdd.DateTime.AddMonths($Years * 12).Ticks } else{ $FirstTime += $ticks } } $output = @($output) + $($blankTimes) } $output | Sort-Object DateTime } } #EndRegion '.\Public\Group-TimeSpan.ps1' 157 #Region '.\Public\Measure-TimeSpan.ps1' -1 Function Measure-TimeSpan { <# .SYNOPSIS Measures statistical properties (such as sum, average, and maximum) of a specified property within grouped time spans. .DESCRIPTION The `Measure-TimeSpan` function calculates various statistical measures (sum, average, maximum, minimum) for a specified property across a collection of grouped time spans. It is designed to work with objects grouped by the `Group-TimeSpan` function, focusing on numerical properties for aggregation. .PARAMETER TimeSpanGroupInfo Specifies the input objects that represent grouped time spans. This parameter accepts pipeline input and is mandatory. .PARAMETER Property Specifies the property name of the TimeSpanGroupInfo objects to measure. This property should be numeric and is mandatory. .PARAMETER Sum Switch parameter that, when specified, calculates the sum of the specified property across all input objects. .PARAMETER Average Switch parameter that, when specified, calculates the average of the specified property across all input objects. .PARAMETER Maximum Switch parameter that, when specified, calculates the maximum value of the specified property across all input objects. .PARAMETER Minimum Switch parameter that, when specified, calculates the minimum value of the specified property across all input objects. .EXAMPLE $groupedData = Get-EventLog -LogName System | Group-TimeSpan -Property TimeGenerated -Days 1 $groupedData | Measure-TimeSpan -Property Count -Sum Measures the sum of the 'Count' property for each grouped time span in the system event log. .EXAMPLE $groupedData = Get-ChildItem $PSHOME | Group-TimeSpan -Property CreationTime -Hours 1 $groupedData | Measure-TimeSpan -Property Length -Average -Sum Measures the sum and average size of files grouped by each hour based on their CreationTime. .INPUTS TimeSpanGroupInfo[] The function accepts grouped time span objects from the pipeline. .OUTPUTS TimeSpanMeasureInfo[] Returns the calculated statistical value(s) based on the input and specified parameters. #> [CmdletBinding()] [OutputType([TimeSpanMeasureInfo[]])] param ( [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [TimeSpanGroupInfo[]]$TimeSpanGroupInfo, [Parameter(Mandatory = $true)] [string]$Property, [Parameter(Mandatory = $false)] [switch]$Sum = $false, [Parameter(Mandatory = $false)] [switch]$Average = $false, [Parameter(Mandatory = $false)] [switch]$Maximum = $false, [Parameter(Mandatory = $false)] [switch]$Minimum = $false ) begin { [Collections.Generic.List[TimeSpanMeasureInfo]] $objects = @() $MeasureParameters = @{} $PSBoundParameters.GetEnumerator() | Where-Object { $_.Key -ne 'TimeSpanGroupInfo' } | ForEach-Object { $MeasureParameters.Add($_.Key, $_.Value) } } process { $TimeSpanGroupInfo | Foreach-Object { $m = $_.Group | Measure-Object @MeasureParameters if($m){ $objects.Add([TimeSpanMeasureInfo]::new($_.DateTime, $m)) } else{ $blankFill = [TimeSpanMeasureInfo]::new($_.DateTime, $Property, $_.Count) if($Average){$blankFill.Average = 0} if($Sum){$blankFill.Sum = 0} if($Maximum){$blankFill.Maximum = 0} if($Minimum){$blankFill.Minimum = 0} $objects.Add($blankFill) } } } end { $objects } } #EndRegion '.\Public\Measure-TimeSpan.ps1' 102 #Region '.\Public\New-Duration.ps1' -1 Function New-Duration { <# .SYNOPSIS Calculates the time span between two dates and returns the duration in the ISO 8601 format .DESCRIPTION Calculates the timespan between two dates and returns the duration in the ISO 8601 format https://en.wikipedia.org/wiki/ISO_8601#Durations .PARAMETER Start Specifies the start of a time span. .PARAMETER End Specifies the end of a time span. End date must be greater than the start date .PARAMETER Years Specifies the number for yearly interval .PARAMETER Months Specifies the number for monthly interval .PARAMETER Days Specifies the number for daily interval .PARAMETER Hours Specifies the number for hourly interval .PARAMETER Minutes Specifies the number for minute interval .PARAMETER Seconds Specifies the number for second interval .PARAMETER Weeks Specifies the number for weekly interval .EXAMPLE New-Duration -Start '2/3/2023' -End (Get-Date) .EXAMPLE New-Duration -Days 1 -Hours 4 .EXAMPLE New-Duration -Weeks 3 #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true, ParameterSetName = "datetime")] [datetime]$Start, [Parameter(Mandatory = $true, ParameterSetName = "datetime")] [datetime]$End, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Years = 0, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Months = 0, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Days = 0, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Hours = 0, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Minutes = 0, [Parameter(Mandatory = $false, ParameterSetName = "numbers")] [int]$Seconds = 0, [Parameter(Mandatory = $false, ParameterSetName = "week")] [int]$Weeks = 0 ) if ($Start -gt $End) { throw "Start date must be before the end date" } if ($PSCmdlet.ParameterSetName -eq 'datetime') { # If start date is later in the month offset by 1 $daysOffset = if ($start.Day -gt $End.Day) { 1 }else { 0 } # Get the total months between dates $TotalMonths = ($End.Month - $start.Month - $daysOffset) + ($End.Year - $start.Year) * 12 # Get the number of years $Years = [math]::floor($TotalMonths / 12) # Get the number of months less the years $Months = $TotalMonths % 12 # Calculate the remaining timespan $TimeSpan = New-TimeSpan -Start $start.AddYears($Years).AddMonths($Months) -End $End # Set variables to build the string $Days = $TimeSpan.Days $Hours = $TimeSpan.Hours $Minutes = $TimeSpan.Minutes $Seconds = $TimeSpan.Seconds } $Duration = 'P' if ($Years -ne 0) { $Duration += "$($Years)Y" } if ($Weeks -ne 0) { $Duration += "$($Weeks)W" } if ($Months -ne 0) { $Duration += "$($Months)M" } if ($Days -ne 0) { $Duration += "$($Days)D" } if (($Hours + $Minutes + $Seconds) -ne 0) { $Duration += "T" if ($Hours -ne 0) { $Duration += "$($Hours)H" } if ($Minutes -ne 0) { $Duration += "$($Minutes)M" } if ($Seconds -ne 0) { $Duration += "$($Seconds)S" } } if($Duration -eq 'P'){ $Duration = 'PT0S' } $Duration } #EndRegion '.\Public\New-Duration.ps1' 127 #Region '.\Public\Test-CrontabSchedule.ps1' -1 Function Test-CrontabSchedule { <# .SYNOPSIS Tests that a crontab string is valid .DESCRIPTION This function attempts to parse a crontab string to ensure it is valid. .PARAMETER Crontab The datetime value to return the second Tuesday for the month .EXAMPLE Test-CrontabSchedule -crontab '0 17 * * *' Valid schedule that returns: Crontab Valid ------- ----- 0 17 * * * True .EXAMPLE Test-CrontabSchedule -crontab '0 17 * 13 *' Invalid schedule that returns: Crontab Valid ErrorMsg ------- ----- -------- 0 17 * 13 * False 13 is higher than the maximum allowable value for the [Month] field. Value must be between 1 and 12 (all inclusive). .OUTPUTS A psobject that contains the crontable, a validation value, and any error messages returned #> [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory = $true)] [string]$Crontab ) $Result = [ordered]@{ Schedule = $Crontab Valid = $false } try { $Result['Schedule'] = [NCrontab.CrontabSchedule]::Parse($Crontab) $Result['Valid'] = $true } catch { $ErrorMsg = $_.Exception.ErrorRecord.ToString() $ErrorMsg = $ErrorMsg.Substring($ErrorMsg.IndexOf(': "') + 3) $ErrorMsg = $ErrorMsg.Substring(0, $ErrorMsg.Length - 1) $Result.Add('ErrorMsg', $ErrorMsg) } [PSCustomObject]$Result } #EndRegion '.\Public\Test-CrontabSchedule.ps1' 57 # Argument Completers $ArgumentCompleters = Join-Path $PSScriptRoot 'Resources\ArgumentCompleters.ps1' . $ArgumentCompleters |