Powershell: Range Operator work with date and ip

Created on 4 Jan 2020  路  19Comments  路  Source: PowerShell/PowerShell

its possible to do this

'2019-01-01'..'2020-01-05'
'monday'..'saturday'
'march'..'april'
'192.168.1.1'..'192.168.1.100'

Issue-Enhancement WG-Language

Most helpful comment

It would have to work in every supported language. You can not hard code names of months, days etc.

It would also need to accept a culture so that on a French machine, I could request Spanish days and months.

In the end it becomes far more sensible to implement this as a function not an operator

PS C:> December..August
August
September
October
November
December

This is wrong in multiple ways : does December..August mean December 2019 to August 2020, in which case it has selected the wrong months, or does it mean December, November, October in that order.

All 19 comments

How could we pick up a step for DateTime? Year? Month? Day? Minute? Seconds?

Probably could go by the smallest unit specified by the user. Would be interesting to see a POC for that.

smallest unit specified by the user

How do you can detect this if original object is a string type?

PowerRange operator this reduce a lot of code. and here implementation probably could detect if string match a pattern of ip or date next convert type in specified type before loop

In any case you must have:

  • a type
  • a step
    I think it is impossible to detect these in common. As result we can not use the proposed syntax.

You could resolve step and type problems with "-range" operator:

"StartString" -range "EndString", <step>, [Type]
$StartTypedObject -range $EndTypedObject, <step>

i think with day/month because the values its _static_ probably the solution is with _enum_

'monday'..'saturday'
'march'..'april'

with date and ip

use regex to detect the model next the step

with ip in ps code probably

$isip = @'
(?x)
 ^
   (?:[1-9]|1\d|[2-9]\d|1\d\d|2[0-4]\d|25[0-5])
   (?:
     [.]
     (?:[1-9]|1\d|[2-9]\d|1\d\d|2[0-4]\d|25[0-5])
   ){3}
 $
'@

@('198.2.3.100','1.1.1.300','255.256.255.255','1.2.3.4') -match $isip

with date probably this the regex must be more robust and flexible

$isdate = @'
(?x)
 ^
 (?:
   (?: 19\d\d | 20\d\d )        # year 1900..2099
   [/-]                         # separator - or /
   (?: 0[1-9] | 2\d | 3[01])    # day 01..02..31
   [/-]                         # separator - or /
   (?: 0[1-9] | 1[12])          # month 01..02..12
  )               
 $
'@

@('1987-01-12','2020/01/12','1999/13/13') -match $isdate

use regex to detect the model next the step

You ask about __operator__. Language operator must work for __all__ types. You can not use Regex.

It would be nice to have, but for date it would need to be two date objects, _not_ two strings because there is already a problem with US dates being wrong in every other country. 6/1/2020 to 7/2/2020 refers to Jan and Feb except in the States. Processing to date uses fixed (US) processing to string uses local culture. Days would need to look at the local culture and uses choice of first day of the week. lu..ve only makes sense if you have French set as a your culture. Does Fri..Mon make sense ? Sun..Sat _doesn't_ if you consider the week as starting on Monday, but is fine if you use Sunday. Etc

A..Z would be helpful, but is A..z 26 items, 52 items (A..Z a..z) or 62items (ASCII 65-122 , including [ \ ] ^ + ` )

IP addresses are probably wishful thinking. If I ask for 192.168.1.100 - 192.168.2.100 do you could 1.255 and 2.0 ? Etc. (they are valid addresses but with special uses).

Most people have learned how to do what they need with integers (e.g. 0..30 DateTime.add() ) so the need is fairly small and the complexity - and ability to create confusion - is relatively large.

@jhoneill 'a'..'z' is already a thing ^^

@jhoneill 'a'..'z' is already a thing ^^

"a".."z"
gives Cannot convert value "a" to type "System.Int32".In 5

I never picked up that it had changed by 7 RC1
'a'..'Z'
is not exactly intuitive.

Yeah, I don't remember exactly when it became a thing, it was sometime in 6.x from memory, maybe 6.1?

Ranges of chars is pretty common in languages that have a range concept (but they usually also have a char literal type). Supporting date or IP literals would be interesting except it would be a breaking change. (Heck - we don't even have regex literals to date.)

an eaxmple of implementation but maybe is more robust with switch with other type

PS C:\> $ExecutionContext.SessionState.InvokeCommand.PreCommandLookupAction = $null
$ExecutionContext.SessionState.InvokeCommand.PreCommandLookupAction = {
   param(
      $cmd,
      [System.Management.Automation.CommandLookupEventArgs]
      $eventargs
   )
     if($cmd -imatch '(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)\.\.(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday)') {
        $eventargs.StopSearch = $true
        $eventargs.CommandScriptBlock = {
          $ldow = $Matches[1]
          $rdow = $Matches[2]
          $dowk = ([int][dayofweek]"$ldow")..([int][dayofweek]"$rdow") -as [dayofweek[]]
          Microsoft.PowerShell.Utility\Write-Output $dowk
       }.GetNewClosure()
    }
}


PS C:\> sunday..monday
Sunday
Monday

PS C:\> sunday..saturday
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday

PS C:\> 

with date

[datetime]$ldate =  $Matches[1]  # 06/01/2020
[datetime]$rdate =  $Matches[2]  # 18/01/2020
if((get-date $rdate) -gt (get-date $ldate)) {
   (1..(($rdate-$ldate).days)).foreach{$ldate.AddDays($_).ToShortDateString()}
 } else {
  (1..(($ldate -$rdate).days)).foreach{$rdate.AddDays($_).ToShortDateString()}
 }

same concept with month:

$ExecutionContext.SessionState.InvokeCommand.PreCommandLookupAction = $null
$ExecutionContext.SessionState.InvokeCommand.PreCommandLookupAction = {
   param(
      $cmd,
      [System.Management.Automation.CommandLookupEventArgs]
      $eventargs
   )
     $month = @{
        January = 1
        February = 2
        March = 3
        April = 4
        May = 5
        June = 6
        July = 7
        August = 8
        September = 9
        October = 10
        November = 11
        December = 12
  }
     if($cmd -imatch '(January|February|March|April|May|June|July|August|September|October|November|December)\.\.(January|February|March|April|May|June|July|August|September|October|November|December)') {
        $eventargs.StopSearch = $true
        $eventargs.CommandScriptBlock = {
          $lm = $Matches[1]
          $rm = $Matches[2]
          if($month[$lm] -lt $month[$rm]) {
          $mth = $month[$lm]..$month[$rm]
          } else {
          $mth = $month[$rm]..$month[$lm]
          }
          $mth | % {(Get-Culture).DateTimeFormat.GetMonthName($_) }
       }.GetNewClosure()
    }
}


PS C:\> December..August
August
September
October
November
December

PS C:\>

It would have to work in every supported language. You can not hard code names of months, days etc.

It would also need to accept a culture so that on a French machine, I could request Spanish days and months.

In the end it becomes far more sensible to implement this as a function not an operator

PS C:> December..August
August
September
October
November
December

This is wrong in multiple ways : does December..August mean December 2019 to August 2020, in which case it has selected the wrong months, or does it mean December, November, October in that order.

@vexx32: 'a'..'z' is already a thing ^^

It's a thing because [char] (in most cases) "naturally" map onto an integer sequence (so we know how to step) and it seemed like an obvious target use case. The decision to accept strings as valid operands was based on the assumption that we would never attempt to implement "string range" functionality - Should it produce the cartesian product of all permutations? what alphabet would we pick - just visible ASCII chars, latin alphabet or exhaust all supported unicode planes? Does it even make sense from a space-complexity perspective?

So the key here is that .. doesn't need to "know" anything about the alphabet or what the host application renders on screen - it just needs boundary values from which it produces a directed range of values.

Even if we ignore the localization issue @jhoneill points out here, it's impossible to infer the behavior of a meaningful range expansion for months or weekdays exactly because they're cyclic in nature:

Range expansion behavior (which is directional) would dictate:

PS ~> December..August
December
November
October
September
August

Which is probably not what you want, and therefore not useful at all, 90% of the time - except for those 10% cases where it is, which we wouldn't be able to consistently implement if we were to respect the cyclic nature of time

Was this page helpful?
0 / 5 - 0 ratings