Your task is to write the shortest code to find one of the unused drive letters (excluding a,b and c). PowerShell’s default aliases are allowed. You have one week. Answers should be posted as a comment to this brain teaser. That’s it.
The winner gets a copy of the “VMware vSphere PowerCLI Reference” from Sybex!
We’ll post clues over the next couple days, stay tuned.
Good Luck!
[UPDATE] 1/23/2012
We have a winner: P!
Your code was 36 characters long:
for($j=67;gdr($d=[char]++$j)2>0){}$d
This is the breakdown of our solution (47 characters):
ls function:[d-z]: -n|?{!(test-path $_)}|random
We took a different approach (though more lengthy) to get a list of available by listing the default A-Z functions and using the Name switch to get the names only.
We then tested if a drive with the incoming drive letter name was available, if so, it was written back to the pipeline.
Finally, we used the Get-Random cmdlet to choose for us an available letter. As you can see we called Get-Random by its verb only. You may suspect that ‘random’ is an alias for that command but it isn’t. We used a known trick to shorten Get-Random – when PowerShell cannot resolve a command it tries to resolve it again by prepending the Get verb.
We hope you had fun and that you enjoyed participating and was able to learn a thing or two. See you in the next brain teaser.
We also would like to thanks our sponsors, Sybex, for giving away the book for the Winner.
68..90|%{$l=gwmi win32_volume|%{$_.driveletter -replace “:” }}{if($l -notcontains [char]$_){[char]$_}}
-jrich
http://jrich523.wordpress.com
68..90 | % { $d = [char]$_; if (!(gdr $d -erroraction SilentlyContinue)) { $d; break; }}
68..90|%{if(!(gdr ([char]$_) -EA 0)){[char]$_;break}}
68..90|%{$d=[char]$_;if(!(gdr $d -EA 0)){$d;break}}
68..90|%{[char]$_}|%{if(!(gdr $_ -EA 0)){$_;break}}
[char[]](68..90)|%{if(!(gdr $_ -EA 0)){$_;break}}
49 characters!
33!
[char[]](68..90)|?{!(gdr $_ -ea 0)}
Not the same; it shows all free drives, not ‘one of’ …
[char[]](68..90)|%{if(!(gdr $_)){break}}
Your script fails with an error
but this error shows first unused driveletter 🙂
if failure is an option, it can be done in 35
[char[]](68..90)|%{$x=gdr $_ -ea 1}
([char[]](68..90)|?{!(gdr $_ -ea 0)})[0]
38 with error checking
([char[]](68..90)|?{!(gdr $_ -ea 0)})[0]
38 with error checking
Not an option, it executes the gdr for eacy char in the array …
I can’t improve on JRich’s 38 chars to meet the original spec.
But I can over come Joe’s objection in 44.
for($j=67;gdr([char]$j)-ea 0){$j++};[char]$j
This is nice 🙂 Like the different approach.
seems to work just fine for me… good job!
PS C:UsersJeffrey> [char[]](68..90)|?{!(gdr $_ -ea 0)}FGHIJKLMNOPQRSTUVWXYZPS C:UsersJeffrey>
Get-PSDrive is not showing hidden drives (for example the one for AppV client), so had to use WMI. Running XP, so can’t use Win32_Volume:
([char[]](68..90)|?{@(gwmi win32_LogicalDisk|%{($_.deviceid)[0]}) -notcontains $_})[0]
BTW – I like the idea of short contests (not necessary with prizes). But please – not on Friday when I am busy in the office :))
Hey all
Thanks for participating, you rock! A few comments and clarifications:
1. Your answer should not generate an error.
2. You need to output just one drive letter (with or without a colon).
3. @jrich, the following is 40 char long, not 38 (and if you’re out of letters it may fail):
([char[]](68..90)|?{!(gdr $_ -ea 0)})[0]
4. @makovec, initially we didn’t think about AppV drives so we can’t change the requirements now 🙂
5. Our one-liner answer is 47 characters long.
6. Keep’em coming!
Going further with James’s idea
for($j=67;gdr([char]++$j)-ea 0){}[char]$j
Other ideas:
([char[]](68..90)|?{@(mountvol|Select-string “[A-Z]:\”|%{$_.toString().Trim()[0]}) -notcontains $_})[0]
([char[]](68..90)|?{@([system.io.DriveInfo]::GetDrives()|%{($_.Name)[0]}) -notcontains $_})[0]
([char[]](68..90)|?{@([io.Directory]::GetLogicalDrives()|%{($_)[0]}) -notcontains $_})[0]
([char[]](68..90)|?{@([io.DriveInfo]::GetDrives()|%{($_.Name)[0]}) -notcontains $_})[0]
([char[]](68..90)|?{@(wmic logicaldisk get name|%{($_)[0]}) -notcontains $_})[0]
net use ((((net use * \DCsysvol) -split “`n”)[0]).substring(6,1)+”:”) /d
# based on: http://powershell.com/cs/blogs/tips/archive/2009/10/21/find-next-available-drive-letter.aspx
(68..90|%{“$([char]$_):”}|?{([IO.DriveInfo]$_).DriveType -eq ‘noRootdirectory’})[0]
[char]([int][char](gdr -PS FileSystem)[-1].Name+1)
for($j=67;gdr($d=[char]++$j)-ea 0){}$d
Great exercise, it cost me whole morning, but learn a lot.
Thanks, Claudio
# 37 chars:
for($j=67;gdr($d=[char]++$j)2>$e){}$d
# pipeline approach, 38 chars:
([char[]](68..90)|?{!(gdr $_)})[0]2>$e
36
for($j=67;gdr($d=[char]++$j)2>0){}$d
That writes to disk though 😉
# 32 chars, implicit cast through the left hand rule:
[char](1+[char](gdr ?)[-1].name)
# 36 chars, globbing avoids error handling:
([char[]](68..90)|?{!(gdr [$_])})[0]
Is the contest still open for one last trick?
# 24 chars:
[char](1+”$(gdr ?)”[-1])
IMO gdr can lead to wrong results… prefer WMI/ .NET solutions. I just created ‘E’ drive that points to my registry and most of scripts here show F as first available letter. 😉 Solutions that assume that first available = next in alphabet after last used fail miserably, because I have virtual cd ‘Z’ 😉
My 2 attempts (I admit, I was using Emim’s ideas a lot:
([char[]](68..90)|?{!((gwmi cim_logicaldisk)-match”=.$_”)})[0]
([char[]](68..90)|?{!([io.driveinfo]::GetDrives()-match$_)})[0]
This code is awful to read (kill me for using -match in such a way, I deserve it ;)).
And most likely has other flaws that in turn I missed. :>
Unless otherwise indicated, brainteasers – and their solutions – should be set in a common and leveled field, i.e. a non-profile powershell session. Having said that, I don’t think many systems would have ‘Z’ logical drive by default