Monday, October 24, 2016

PowerShell Oneliner Contest 2016

A lot of time has passed since I have organized a PowerShell oneliner contest. So when I saw the post by fellow MVP and scripting champion Mike F Robbins on a PowerShell Function to Determine Available Drive Letters, I thought that it could be fun to organize a contest to see who can manage to write the shortest possible oneliner that achieves the same result as Mike's function.


As you can see reading his blogpost, the function accepts parameters such as -Random, to return one or more available drive letters at random, or -All, to return all the available drive letters. It also allows you to exclude some letters from the match (A, B, C, D, E, F and Z) by means of a -ExcludeDriveLetter parameter.

Now, for this specific contest, what I want to get in a comment to this post is:
  • a oneliner (meaning in particular no semi-colon) that
  • returns one and only one random available drive letter on the system where it runs
  • with the exception of A-F and Z
  • whose object type is a System.String (I'll check this Get-Member)
  • and whose formatting is, say, G: or h: (case doesn't matter, we are on Windows)
For sure
  • aliases are mandatory, meaning that you can't use a cmdlet unless it has an alias
  • backticks are accepted for readability
  • you can use every PowerShell version, including 5.1, just state in the comment what version you tested it with
  • should you find a shorter oneliner to solve a task you are allowed to post additional comments (just remember to sign your comments so that I know who's who and so that I can get in touch with the winner)
A few more rules:
  • Entries (comments) will not be made public until after the submission deadline.
  • The first person to produce the shortest working solutions to the task wins.
  • The winner will be announced on Friday, November 4th on this blog.
  • I'll be the only judge.
If you want to spread the word about this PowerShell contest, feel free to twit about it. You can use the hashtags #poshcontest2016 and #powershell so that other competitors can share their thoughts (not the solutions of course!).

UPDATE Nov 4 2016
We have a winner! Check it here.

91 comments:

  1. 97..122 | % {$($_ -as [Char])} | ? {$_ -notmatch '([a-f]|z)'} | % { if ($_ -notin (Get-PSProvider -PSProvider FileSystem).Drives.Name -as [Array]) {'{0}:' -f $($_ -as [String]).ToUpper()} } | Get-Random

    ReplyDelete
  2. Testing private comment: jeff.jerousek

    ReplyDelete
  3. Submission: Powershell v5:
    (diff((ls Function:[f-x]: -Name)-replace".$")(gdr).Name|?{$_.sideIndicator-eq"<="}|Random|select -exp I*)+":"

    Jeff.Jerousekatgmail

    ReplyDelete
  4. 71..89|%{if(!(ls "$([char]$_):" -ea 4)){@{([char]$_+":")=[Guid]::NewGuid().GetHashCode()}.GetEnumerator()}}|sort value|select -exp name -f 1

    ReplyDelete
  5. ([char[]](71..89) -replace '$',':\' | ?{(gwmi win32_volume).name -notcontains $_} | Get-Random) -replace '\\'

    ReplyDelete
  6. PowerShell 5.1 one-liner to get a random and free drive Letter from G..Y in 79-Chars by @roger_zander:
    (([char[]](71..89))|?{(gdr|? Used).Name-notcontains$_}|sort{Get-Random})[0]+":"

    ReplyDelete
  7. If you want a RANDOM available letter, you could use:
    while(gdr($l=[char](Get-Random -Mi 69 -Ma 90))-ea 0){}$l

    If you want the FIRST available(shorter):
    for($i=70;gdr($l=[char]++$i)2>0){}$l

    ReplyDelete
  8. Found an even shorter version for the random:
    (ls function:[g-y]:).name|?{!(test-path $_)}|random

    ReplyDelete
  9. I'm pretty sure you can go shorter than that, but just to have good baseline...:

    71..89|%{"$([char]$_):"}|?{!(ls $_\* -ea 0)}|random

    ReplyDelete
  10. Fixing typo:
    (diff((ls Function:[g-x]: -Name)-replace".$")(gdr).Name|?{$_.sideIndicator-eq <="}|Random|select -exp I*)+":"

    Jeff Jerousek

    ReplyDelete
  11. I assume you're ok with throwing lots of errors as it's not mentioned. I'm using 5.1


    ([char[]](71..90)|?{!(gdr $_)})[0]+':'

    ReplyDelete
  12. (71..89|%{[char]$_+":"}|%{if($_-NotIn(gwmi win32_logicaldisk).DeviceID){$_}})[[System.Random]::new().Next(0,(71..89|%{[char]$_+":"}|%{if($_-NotIn(gwmi win32_logicaldisk).DeviceID){$_}}).length)]

    ReplyDelete
  13. if randomness is a must:

    ([char[]](71..90)|?{!(gdr $_)})[(irm http://v.ht/7WBh)]+':'

    or, if v.ht is too ridiculous for you:

    ([char[]](71..90)|?{!(gdr $_)})[[random]::new().Next()%19]+':'

    Why isn't there a built in alias for get-random by the way? frustrating.

    ReplyDelete
  14. Assuming `random` for `get-random` satisfies your mandatory aliases requirement, this does it in 126 characters, albeit slowly:

    'GHIJKLMNOPQRSTUVWXY'.ToCharArray()|where{(gwmi win32_logicaldisk|%{$_.ToString().ToCharArray()[-3]}) -NotContains $_}|random

    ReplyDelete
  15. whoops, forgot to add the colon, which requires an extra four characters, totaling 132:

    ('GHIJKLMNOPQRSTUVWXY'.ToCharArray()|where{(gwmi win32_logicaldisk|%{$_.ToString().ToCharArray()[-3]}) -NotContains $_}|random)+':'

    ReplyDelete
  16. (71..89 | %{[string][char] $_}) | ?{(gdr -PSProvider 'F*').Name -notcontains $_} | %{"{0}:" -f $_} | random

    -PittsburghTech

    ReplyDelete
  17. # Tested on version 5.1
    ([char[]](71..89)|?{$_-notin(gdr).name}|random)+':'

    ReplyDelete
  18. @mickyballadelli

    ,((ls -Pa Function:[a-z]: -N) -match "['G-Y']")|%{$_[[Random]::new().Next(0,$_.count)]}

    88 chars

    ReplyDelete
  19. ls function:[g-y]: -n|?{!(gci $_)}|random

    Just a bit of fun,

    Seroko@gmail.com

    ReplyDelete
  20. @mickyballadelli

    [char](,(71..89|?{![io.file]::exists("$($_):")})|%{$_[[Random]::new().Next(0,$_.count)]})+':'

    94 chars
    Powershell V5

    ReplyDelete
  21. Could you please define 'random' in as much detail as you can?

    ReplyDelete
  22. Script created by Chris O'Neill, I can be contacted via email at chris.oneill {@} wildhorseresort {dot} com

    I am a novice at powershell but I'm nothing if not a Next-pert so I tried to use that to my advantage. The script below is my entry to the Powershell Oneliner Contest 2016. This script grabs paths A-Z, outputs this to a grid-view where the user selects G-Y so as to exclude A-F and Z. After this list is passed through get-random will select a random drive letter to be presented.


    $drive = Get-ChildItem -Path Function:[a-z]: -Name | Out-GridView -PassThru | get-random

    $drive

    ReplyDelete
  23. # ps 5.1
    @($d=(gdr).Root.Trim('\')|?{$_ -match'^[^A-F,Z]:'})|%{}{}{$d[([random]::new().Next(0,$d.count))]}

    ReplyDelete
  24. (gwmi –Query "SELECT * from win32_logicaldisk"|where {$_.DeviceID -match "[G-Y]"}).DeviceID[(20/(gci).GetHashCode())]

    ReplyDelete
  25. I've re-written my entry slightly. Available to contact at chris.oneill {@} wildhorseresort {dot} com.

    Get-ChildItem -Path Function:[a-z]: -Name | out-gridview -PassThru | get-random

    ReplyDelete
  26. Tested on 5.1 but should work on any version down to 3.0 (compare-object). It is slightly longer than "needed" due to .ToUpper() but I would argue that if you can't handle upper and lower case volume names then you didn't succeed.

    do{$i=([random](date).Second).Next(71,90)|diff ((gdr -psp FileSystem).Name.ToUpper().ToCharArray()|%{[int]$_})|?{$_.SideIndicator -eq "=>"}|%{[char]$_.InputObject+":"}}until($i)$i

    ReplyDelete
  27. Attempt 2.

    random((gwmi Win32_LogicalDisk).DeviceID-match"[G-Y]")

    - Gavin Eke

    ReplyDelete
  28. Okay I think this will be my last post. 1 less character then attempt 2.

    (gwmi Win32_LogicalDisk).DeviceID-match"[G-Y]"|random

    ReplyDelete
  29. I wish I could get it shorter.

    (,(ls function:[g-y]: -n|?{$_-notin(gwmi win32_volume).driveletter}))|%{$_[([random]([datetime]::now.second)).next($_.count)]}

    - /u/Taylor_Script

    ReplyDelete
  30. <#
    Hello. Please disregard my previous entry.
    This is my newest submission.
    #>

    #Random available drive letter. 55 Characters
    ls Function:[G-Y]: -N|?{$_[0] -notin (gdr).Name}|random

    #Selects first available drive. 60 Characters
    ls Function:[G-Y]: -N|?{$_[0] -notin (gdr).Name}|select -F 1

    <#
    Powershell 5.0

    Cheers,
    Briggzee
    #>

    ReplyDelete
  31. do{$d=([char](random 85 -mi 71)+':')}until(!(cd($d)2>0))$d

    ReplyDelete
  32. do{$d=([char](random 85 -mi 71)+':')}until(!(cd($d)2>0))$d

    Cheers, Javy de Koning

    ReplyDelete
  33. Darn, forgot to update the max int, final answer:

    do{$d=([char](random 89 -mi 71)+':')}until(!(cd($d)2>0))$d

    Cheers,

    Javy de Koning

    ReplyDelete
  34. If we aren't allowed errors in output
    ((71..89)|%{[char]$_}|%{if(!(dir $_":" -ErrorAction Ignore)){$_}}|get-random)+":"

    If you don't mind errors
    ((71..89)|%{[char]$_}|%{if(!(dir $_":")){$_}}|get-random)+":"

    Tested on Powershell 5.0

    Cheers,
    LatexGolem

    ReplyDelete
  35. irm 'https://www.random.org/integers/?num=1&min=70&max=88&col=1&base=10&format=plain&rnd=new'|%{for($j=$_;gdr($d=[CHAR]++$J)2>0){}$d +":"}

    ReplyDelete
  36. irm 'https://www.random.org/integers/?num=1&min=70&max=88&col=1&base=10&format=plain&rnd=new'|%{for($j=$_;gdr($d=[CHAR]++$J)2>0){}$d +":"}

    Tested with powershell 4.0

    Rob Hagman

    ReplyDelete
  37. ((71..89|%{"$([char]$_):"|?{-not(gi $_ -EA Ig)}})|sort{[guid]::newguid()})[0]

    ReplyDelete
  38. [char[]](71..89) | ?{(gdr).Name -notcontains $_} | %{"{0}:" -f $_} | Get-Random

    Are spaces counted? If so,

    [char[]](71..89)|?{(gdr).Name-notcontains$_}|%{"{0}:"-f$_}|Get-Random

    -PittsburghTech

    ReplyDelete
  39. Attempt 2 (tested 5.1):

    ((gdr -psp FileSystem).Name.ToCharArray()|%{[int]$_}|?{$_ -ge 71}|diff (71..89)).InputObject|random|%{[char]$_+":"}

    ReplyDelete
  40. [char[]](65..90)|?{(gdr).Name-notcontains$_}|%{$_+":"}|Get-Random

    -PittsburghTech

    ReplyDelete
  41. Sorry, had old numbers in before.

    [char[]](71..89)|?{(gdr).Name-notcontains$_}|%{$_+":"}|Get-Random


    -PittsburghTech

    ReplyDelete
  42. ([char[]](71..89)|?{!(gdr $_)2>0}|sort{[guid]::newguid()})[0]+':'

    Tested on PowerShell 5.1. If catching errors doesn't matter, we could remove 3 characters and take it down to this:

    ([char[]](71..89)|?{!(gdr $_)}|sort{[guid]::newguid()})[0]+':'

    ReplyDelete
  43. [char[]](71..89)|?{!(gdr($_)2>0)}|%{$_+":"}|Get-Random

    -PittsburghTech

    ReplyDelete
  44. ([char[]](65..89)|?{!(gdr($_)2>0)}|Get-Random)+":"

    -PittsburghTech

    ReplyDelete
  45. Sorry, I don't know if i had the right numbers. Same as last one, but has right number range.

    ([char[]](71..89)|?{!(gdr($_)2>0)}|Get-Random)+":"

    -PittsburghTech

    ReplyDelete
  46. hello, this is my contribution :
    ((71..89|%{[char]$_})|?{$_-NotIn(gdr).Name}|Get-Random)+':'
    seem to work on PS2+

    ReplyDelete
  47. Ooops too fast to post, another contrib :
    ([char[]](71..89)|?{$_-NotIn(gdr).Name}|Get-Random)+':'
    seem to work on Ps2+

    ReplyDelete
  48. (random ([char[]](71..89)|?{!(gdr $_ -ea 0)}))+":"

    ReplyDelete
  49. ([char[]](71..89)|?{!(gdr $_ -ea 0)})[([random]::new()).next($(([char[]](71..89)|?{!(gdr $_ -ea 0)})).count)]+":"

    ben@himsel.io

    ReplyDelete
  50. gci function:[g-y]: -n|?{!($_|ls -ea 4)}|random

    Tested with 5.0 but should work in 3+, maybe 2 as well.

    In this case, random is not really an alias; it's using PowerShell's behavior of prepending Get- to a command if it can't find a match any other way. I may try something else and submit it as a different answer if this doesn't count (it's not clear from your post).

    ReplyDelete
  51. gci function:[g-y]: -n|?{!($_|ls)}|random

    Tested with 5.0 but should work in 3+, maybe 2 as well.

    Here's a shorter version of my last submission. It throws non-terminating errors, but that's a different stream and the output of this is the same. Not sure if that makes it invalid or not.

    ReplyDelete
  52. That is at all not my idea - but I redisgned the oneliner to match the criteria. Mostly in many cases we have to reuse code and redisgne it for our goal. But I have to metion that, otherwise I will feel guilty.

    ls function:[g-y]: -n | ?{ !(test-path $_) } | random

    ReplyDelete
  53. <#
    this script uses get-random that doesn't have a alias
    created on powershell version 4.0
    written by Sjef.poppelaars@centric.eu
    #>
    [char[]](71..89)|?{$_-notin(gdr).name}|%{"${_}:"}|get-random

    ReplyDelete
  54. <#
    this script uses a workarround for get-random that doesn't have default alias, the new alias name is d
    the cmdlet get-random is not used until it has the alias d
    created on powershell version 4.0
    written by Sjef.poppelaars@centric.eu
    #>
    [char[]](71..89)|?{$_-notin(gdr).name}|% -begin{sal d get-random}-process{$p+=@("${_}:")}-end{$p|d}

    ReplyDelete
  55. ($a = (gdr -PSProvider 'filesystem').name | ? {$_ -in [char[]](71..89)})[[DateTime]::Now.Ticks%($a.count)]

    ReplyDelete
  56. ($a=(gdr -PSProvider "filesystem").name|?{$_-in[char[]](71..89)})[[DateTime]::Now.Ticks%($a.count)]

    ReplyDelete
  57. Entry:

    [char[]](71..90)|%{if($_-ne'Z'-and!(ls($_+':')-EA Ignore)){$_+':'}}|Get-Random

    Tested under PSVersion 5.0.10514.6

    - @aaspnas

    ReplyDelete
  58. ($a=(gdr -P "f*").name|?{$_-in[char[]](65..90)})[[DateTime]::Now.Ticks%($a.count)]

    ReplyDelete
  59. ($a=(gdr -P "f*").name|?{$_-in[char[]](71..89)})[[DateTime]::Now.Ticks%($a.count)]

    ReplyDelete
  60. ls function:[g-y]: -n|?{!($_|ls -ea 4)}|random

    or

    ls function:[g-y]: -n|?{!($_|ls)}|random

    Same as my last two, but saved a byte using ls instead of gci in the first call (duh, how didn't I see that before).

    ReplyDelete
  61. PS ISE 5.1:
    begin{$x=71..89|?{!(ls -ea 0 "$([char]$_):")}}end{"$([char]$x[[random]::new().Next(0,$x.count)]):"}

    ReplyDelete
  62. ([char[]](71..89)|?{$_-notin(gdr -P "f*").Name}|sort{[guid]::NewGuid()})[0]+':' Version5.0
    THD

    ReplyDelete
  63. <#
    this script uses a workarround for get-random that doesn't have default alias, the new alias name is d
    the cmdlet get-random is not used until it has the alias d
    Versie 2 reduced size of line
    created on powershell version 4.0
    written by Sjef.poppelaars@centric.eu
    #>
    [char[]](71..89)|?{$_-notin(gdr).name}|%{$p+=@("${_}:")}-b{sal d get-random}-en{$p|d}

    ReplyDelete
  64. Best I could do:

    (ls function:*:)-notMatch"[A-F,Z]"|Random|% na*

    /Tore

    ReplyDelete
  65. now, if I cheat:

    (ls function:[g-y]:)|random|% Na*

    /Tore

    ReplyDelete
  66. (ls Function:[G-Y]: -N|?{!(ls $_ 2>null)})[0]

    ReplyDelete
  67. Updated: An even shorter version as i noticed z is in sequence...

    [char[]](71..89)|%{if(!(ls($_+':')-EA Ignore)){$_+':'}}|Get-Random

    If you can't use Get-Random, as it has no alias...

    [char[]](71..89)|sort{[guid]::NewGuid()}|%{if(!(ls($_+':')-EA Ignore)){$_+':'}}|select -F 1

    @aaspnas

    ReplyDelete
  68. PS ISE 5.0:

    (nal x(gcm g*om)),"$(x(71..89|?{!(gdr [char]$_)}|%{[char]$_})):"

    ReplyDelete
  69. ((nal x(gcm g*om)),"$(x(71..89|?{!(gdr [char]$_)}|%{[char]$_})):")[1]

    ReplyDelete
  70. ([Random]::new()).Next(0,(($l=(gwmi Win32_logicalDisk).DeviceID -notmatch "[A-F|Z]").Length)) | % {$l[$_]}

    haffimt@gmail.com

    ReplyDelete
  71. #for v5.1

    ([char[]](71..89)|?{$_-notin(gdr|% N*)}|random)+":"

    ReplyDelete
  72. ([Random]::new()).Next(0,(($l=(gwmi Win32_logicalDisk).DeviceID -notmatch"[A-F|Z]").count)|%{$l[$_]}

    haffimt@gmail.com

    ReplyDelete
  73. [char](,(71..89|?{!(gi "$([char]$_):" -ea Si) })|%{$_[[Random]::new().Next($_.count)]})+':'

    92 chars
    PS V5
    @mickyballadelli

    ReplyDelete
  74. The no cmdlet w/o aliases rule is evil. Makes shuffling a list quite long, as well as figuring out how to get drive letters.

        ((gwmi win32_logicaldisk|% n*e|sort{[guid]::NewGuid()})-match'[g-y]')[0]

    72 characters, first attempt while having a cold. Will try to get better :)

    ReplyDelete
  75. # v5.1
    ($l=[char[]](71..89)|?{$_-notin(gdr|% N*)})[[random]::new().Next($l.count)]+":"

    ReplyDelete
  76. Hello,
    another one, without get-random.

    ,([char[]](71..89)|?{$_-NotIn(gdr).Name})|%{$_[[Random]::new().Next(0,$_.count)]+':'}

    Tested on PS5

    ReplyDelete
  77. #PowerShell 5.1 onliner to get a random and free drive Letter from G..Y in 77-Chars by roger_zander:
    (([char[]](71..89))|?{(gdr|? U*).Name-notcontains$_}|sort{Get-Random})[0]+":"

    ReplyDelete
  78. [char]((103..121).where{!(test-path([char]$_+':'))}|Get-Random)+':'

    ReplyDelete
  79. (ls function:[g-y]:|%{$_|select -ov x|%{try{sl $x.name -ea st}catch{write @{[guid]::NewGuid()=$x.name}}}}|sort Keys)[0].values

    PoSH: 5.0.10586.494

    ReplyDelete
  80. ls function:[g-y]: -n|?{!(ls $_ 2>0)}|random

    ReplyDelete
  81. the same thing as gihub gist: https://gist.github.com/nohwnd/5958eda5c9f6459c3cbe8acb6b7bfe25

    $oneliner = {(103..121|%{if(cd($d="$([char]$_):")2>&1){$d}})[0]}

    Describe "One liner contest" {
    It "contains no semicolons" {
    $oneliner | Should Not Match "\;"
    }
    It "outputs single string" {
    (&$oneliner) -is [string] | Should be $True
    }
    It "Outputs single letter followed by colon" {
    &$oneliner | Should Match "^[a-z]\:$"
    }
    It "Should not output drive letter " -TestCases `
    @{DriveLetter = "a:"},
    @{DriveLetter = "b:"},
    @{DriveLetter = "c:"},
    @{DriveLetter = "d:"},
    @{DriveLetter = "e:"},
    @{DriveLetter = "f:"},
    @{DriveLetter = "z:"}{
    param ($DriveLetter)
    &$oneliner | Should Not Be $DriveLetter
    }
    It "Resulting drive should not exist" {
    &$oneLiner | Should Not Exist
    }
    }

    "Length: " + $oneliner.ToString().Length
    "Result: " + (&$oneliner)

    50 characters, Tested on PowerShell 5. I am assuming default settings of error action preference (continue).

    @nohwnd

    ReplyDelete
  82. ... And an even shorter version now that i have had time to think...

    [char[]](71..89)|%{$_+':'}|?{(!(ls($_)-EA 0))}|Get-Random


    If Get-Random is not allowed (as not an alias):

    [char[]](71..89)|%{$_+':'}|?{(!(ls($_)-EA 0))}|sort{[guid]::NewGuid()}|select -F 1

    @aaspnas

    ReplyDelete
  83. # @FooBartn
    # PSVersion 5.1.14393.206

    ls Function:[a-z]: -N | ? {
    $_ -notmatch '[A-F]|[Z]'
    } | ? {
    $_ -notin (gwmi win32_logicaldisk).DeviceId
    } | random

    ReplyDelete
  84. In case the whitespace is an issue:

    # @FooBartn
    # PSVersion 5.1.14393.206

    ls Function:[a-z]: -N | ?{$_ -notmatch '[A-F]|[Z]'} | ?{$_ -notin (gwmi win32_logicaldisk).DeviceId} | random

    ReplyDelete
  85. ls function:[g-y]: -n|?{!(gci $_ -ea 0)}|random

    ReplyDelete
  86. This is my final. I'm not sure I put it here yet or not.
    ([char[]](71..89)|?{!(gdr($_)2>0)}|sort{[guid]::newguid()})[0]+":"

    -PittsburghTech

    ReplyDelete
  87. do{$a="$([char]([random]::new().Next(71,90))):"}while(gwmi win32_logicaldisk -F "deviceid='$a'")$a

    Tested on PS 5.1
    Twitter handle: @PSAdm

    ReplyDelete
  88. Update to last entry, and saved a character:
    do{$a="$([char]([random]::new().Next(71,90))):"}while(gwmi win32_logicaldisk|? deviceid -eq $a)$a

    ReplyDelete
  89. 127 characters. I know it won't win, so I'm curious what others are doing here. Tested on PS5.1.

    "$((71..89|%{[char]$_}|?{$_-notin(gdr|?{$_.name.length-eq1}|select -exp name)}|tee -v a)[Random]::New().Next(0,$a.count-1)]):"

    ReplyDelete
  90. If not too late by now, I managed to shorten it by two characters:

    ''+(gwmi win32_logicaldisk|% n*e|sort{[guid]::NewGuid()}|sls [g-y])[0]

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...