Extending the PowerShell range operator


The PowerShell range operator ‘..’ can be used to create lists of sequential numbers with an increment (or decrement) of one:


This is quite handy. Wouldn’t it be even better if it would also support stepwise lists (FIRST, SECOND..LAST similar to Haskell where the step width is determined by the first and the second list entry), day, month and letter ranges? :

#range of numbers from 2 to 15 with steps of 3 (5 - 2)
#range of numbers from 1 to 33 with steps of .2 (1.2 - 1)
#range of letters from a to z
#range of letters from Z to A
#range of numbers from -2 to 1024 with steps of 6 (4 - -2)

At least I though it would be.
While PowerShell does not support something like language extensions in order to change the behavior of the range operator directly, it is possible to get this working (admittedly it feels a bit like a hack) by overriding the ‘PreCommandLookupAction’ event. The ‘PreCommandLookupAction’ event is triggered after the current line is parsed but before PowerShell attempts to find a matching command.
I’ve encountered timed out IntelliSense/tab completion issues with the custom ‘PreCommandLookupAction’ therefore, I’ve updated the solution to use the ‘CommandNotFoundAction’ instead. The CommandNotFoundAction is triggered if PowerShell cannot find a command (who would have thought)

	#if the command consists of two dots with leading trailing words optionally containing (:,.) + leading -
	if ($CommandName -match '^(-*\w+[:.]*)+\.\.(-*\w+)+$'){
		$CommandLookupEventArgs.StopSearch = $true
		#associate new command
		$range = $CommandName.replace('get-','')
			#no step specified
			if ($range -notlike '*:*') { 
				#check for month name or day name range
				if ($monthNames -contains $range.Split("..")[0]){$enum=$monthNames}
				elseif ($dayNames -contains $range.Split("..")[0]){$enum=$dayNames}
				if ($enum){
					$start,$end=$range -split '\.{2}'
					if ($start -gt $end){ $change=-1 }
					while($start -ne $end){
				#check for character range
				if ([char]::IsLetter($range[0])){
				Invoke-Expression $range
			$range = $range.Split(':')
			$step=$range[1].SubString(0,$range[1].IndexOf("..")) - $range[0]
			#use invoke-expression to support kb,mb.. and scientific notation e.g. 4e6
			[decimal]$start=Invoke-Expression $range[0]
			[decimal]$end=Invoke-Expression ($range[1].SubString($range[1].LastIndexOf("..")+2))
			for($i=0;$i -lt $times ;$i++){

Adding the code to your profile will make the “extended” range operator version available in all PowerShell sessions.
I’ve also create a separate Get-Range function which can be downloaded from my Github repository.


Photo Credit: zachstern via Compfight cc


I'd love to hear what you think

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s