Why work so hard with hashtables?

Recently I’ve see hashtables all around: blog posts, videos, webcasts. And every time I see it I ask myself simple question: why people tend to work too hard when defining those? I mean technicaly:

  1. $MyHash = @{ ‘key’ = ‘value’;
  2.     ‘nextkey’ = ‘othervalue’ }

is correct syntax to define hashtable. But I ask myself instantly: why? I can compare it with writing few lines of code like that:

  1. Get-ChildItem ‘.\’;
  2. GetQADUser ‘DoeJ’;

For some reason I would guess nobody (once he know he does not have to) would not write code like that. If command expects string, and it contains only ‘good’ characters you don’t have to quote it. Also: if you need to write few commands, each in separate line, you do not need to finish each line with semicolon. The only reason why semicolon is used when defining hashtables is because it’s technically similar to having few lines of code in one line. Same for key names: if it contains something wacky – please, use single quotes, or it may fail. If not – why bother? So my example hashtable, when defined in few lines, can be easily done without few quotes and without any semicolon:

  1. $MyHash = @{ key = ‘value’
  2.     nextkey = ‘othervalue’ }

I honestly like PowerShell for that it knows usually what I want. It saves some time here, when I define $MyHash. But it save a lot of time when you don’t have to quote each string, and separate each line of code with semicolon.

Advertisement

ISE profile re-visited. :)

First of all – I finally had some time so I managed to finish reading PowerShell Cookbook v.2. It was awesome, educational and fun! Thank you Lee Holmes for sharing your knowledge with us! And it was very well spent $10, so I encourage anybody who looks for a book that has both learning material and some real life use cases to read this book. If I will be able to, I will try to write a review. 😉

With that book there were so many new things I learned and refreshed that I almost felt few switches moving in my brain during reading it. Let’s take my ISE profile. If someone read my post and is knowledgeable enough he was probably looking in disbelieve: why in the world did he use Invoke-Expression there!? Doesn’t he know about [ScriptBlock]::Create() static method?

Honestly I did not, now I know so I started with re-writing this part. Old code:

 

PowerShell, using GeSHi 1.0.8.8
  1. Invoke-Expression "`$SwitchToMe = { `$tabs.SetSelectedPowerShellTab(`$tabs[$NewTabIndex-1]) }"

YAK!

New code, that uses [scritpblock] method:

PowerShell, using GeSHi 1.0.8.8
  1. $SwitchToMe = [ScriptBlock]::Create("`$tabs.SetSelectedPowerShellTab(`$tabs[$($NewTabIndex-1)])")

It maybe not so different at first, but you know, if I create variable I prefer to see that I actually do it in the first place. It also clear what type of variable I’m creating. When I will read this code somewhere in future I may know how to modify it. 😉 Not so with that Invoke-Expression stuff.

Second thing I’ve changed was setting focus on command pane rather than script pane in my ‘NoProfile’ tab. And last but not least: I’ve added ssh function that basically changes tab name to match host name and Enter-PsSession. I was thinking of an easy way to get my tabs name back and eventually decided to use Prompt for that. Works nice – I have my remote name during remote session, and once I disconnect – I get name back. Both ssh function and prompt are of course part of my re-visited profile. Whole profile can be seen here:

PowerShell, using GeSHi 1.0.8.8
  1. $tabs = $psISE.PowerShellTabs
  2. $curtab = $tabs[$tabs.Count1]
  3. $ISEOpt = $psISE.Options
  4.  
  5. $ISEOpt.OutputPaneBackgroundColor = ‘black’
  6. $ISEOpt.OutputPaneTextBackgroundColor = ‘black’
  7. $ISEOpt.OutputPaneForegroundColor = ‘white’
  8. $TabsMenu = $curtab.AddOnsMenu.Submenus.Add(‘Tabs’,$null,$null)
  9. if ($curtab -eq $tabs[0]) {
  10.     $curtab.DisplayName = ‘NoProfile’
  11.     $newTab = $tabs.Add()
  12.     } else {
  13.     function prompt {
  14.         $psISE.CurrentPowerShellTab.DisplayName = "PoSh # $($tabs.IndexOf($curtab))"
  15.         $(if (test-path variable:/PSDebugContext) { ‘[DBG]: ‘ } else { }) + ‘PS ‘ + $(Get-Location) + $(if ($nestedpromptlevel -ge 1) { ‘>>’ }) + ‘> ‘
  16.     }
  17.     $curtab.DisplayName = "PoSh # $($tabs.IndexOf($curtab))"
  18.     $NewTabIndex = $tabs.Count
  19.     $SwitchToMe = [ScriptBlock]::Create("`$tabs.SetSelectedPowerShellTab(`$tabs[$($NewTabIndex-1)])")
  20.     for ($i = 0; $i -lt $tabs.Count 1; $i++) {
  21.        
  22.         if ($NewTabIndex -le 9) {
  23.             $SwitchTo = [ScriptBlock]::Create("`$tabs.SetSelectedPowerShellTab(`$tabs[$i])")
  24.             $MyMenu = $tabs[$i].AddOnsMenu.Submenus | Where { $_.DisplayName -eq ‘Tabs’ }
  25.             try {
  26.                 [void] $Mymenu.Submenus.Add($curtab.DisplayName, $SwitchToMe ,"ALT + $NewTabIndex")
  27.             } catch {
  28.                 Write-Debug ‘This menu item is already present!’
  29.             }
  30.         } else {
  31.             # That should not happen cause limit is 8
  32.             Write-Host -ForegroundColor Red "Can not add this tab to menu – move to it using CTRL + TAB"
  33.         }
  34.         [void] $TabsMenu.Submenus.Add($tabs[$i].DisplayName, $Switchto, "ALT + $($i+1)")
  35.     }
  36.     $tabs.SetSelectedPowerShellTab($tabs[0])
  37.     $tabs[0].CommandPane.Focus()
  38.     Add-PsSnapin Quest*
  39.     ImportModule @(‘WPK’,‘IsePack’,‘Inventory’,‘ISEFun’,‘WAD’)
  40.     . "C:\Program Files\Quest Software\Management Shell for AD\qsft.ps1"
  41.     $Inventory = ImportInventoryList
  42.     $HashPC = ImportInventoryHash
  43.     $hashPrinter = Import-Csv A:\Inventory\printers.csv | ForEach-Object -Begin { $__out = @{} } -Process { $__out.Add($_.Letter,$_) } -End { $__out; Remove-Variable __out }
  44.    
  45. }
  46.  
  47. function ssh {
  48.     param ([string]$remotehost =‘pl-war-ap001’)
  49.     $oldTab = $curtab.DisplayName
  50.     $curtab.DisplayName = $remotehost
  51.     try {
  52.         EnterPSSession $remotehost
  53.     } catch {
  54.         $curtab.DisplayName = $oldTab
  55.         Write-Host -ForegroundColor Red "There was a problem: $_"
  56.     }
  57. }

Last thing I do not like about Add-Ons menu: you always get your code when you invoke something from it. I would love to have some way to get rid of it. It’s not that I want to make it secret, I just want to make output-pane unaware of this code. But this is minor, and if James Brundage could live with that (ISEPack is so much bigger than what I did…), so can I. 😉

What I DON’T like about PowerShell.

I guess it’s clear that I love PowerShell as a whole. But there are some things inside that I do not like. Few of those are not PowerShell fault (probably some .NET or Windows limitations) but since I’m PowerShell user I would like to see them solved/ upgraded to my needs. Of course I may be alone about those and will never see it done, but… 😉

1. ACLs.

The concept of ACLs in Windows is… there. I’ve read about working with ACLs from PowerShell and honestly – I don’t see any value in *-ACL cmdlets. It’s really so much easier to do stuff with ancient cacls that I have no need to play with it in more PowerShellish way. I would love to have those designed in a way that I could just do something like:

Set-ACL –User MyUser –AccessLevel Full –Action Grant

and forget about it. Without storing current ACL in variable, using some .NET methods on it and creating some other types meanwhile to add to created on the fly ‘template’. Yak.

2. Providers/ Drives.

I know that concept itself is very nice. I thing browsing to HKLM:\Software is great, but for demos only. It has no option to map remote registry, nor easy way to get full info about properties (my first suggestion on connect is all about that). Next provider I’ve tried to use was SQL… It’s kind of nice, but man, try to press [TAB] there… One second after I do it I hate myself for it. It takes so much time to get my prompt back! It’s frustrating when what I need is a command, not ChildItem. (see next point too 😉 )

FileSystem is also nice, but only for nick-names to folders on local drive/ drives mapped with old net use. No credentials support renders it less convenient that it might be. I don’t mention other providers, I haven’t used them much. But I see a lot of space for improvements in this area. And I guess there are still some providers missing. WMI is the one I would like to see in v3 for sure. 🙂

3. Tab completion.

I know there are some tools out-there that can help me with that, but I would like just minor change. From my experience: PowerShell will try to look for completion in current path first. It’s usually not what I’m looking for. I mean: I very rarely start with filename, it’s usually argument to one of parameters. I know, I know, I can edit TabExpansion function and make it happen. But I’ve tried to understand logic used in this function several times and I really eventually found something better to do. 😉 Also TabExpansion behaviour in console host (powershell.exe) may be very annoying at times. Try to tab-expand something in the middle of edited line. But say bye-bye to the rest of your line first. 😉

4. Load time

I recently read some tweet from guy who was frustrated with load time for PowerShell so much, that he managed to use some other tool quicker (something with SharePoint administration). On my admin box I had some problems with that too and it was the moment when I decided to create new profile for ISE that would take care of that for me (post ISE is cool). But now that we are about to jump into windows 7 mode in our organization I will get my PowerShell box on client machines too. And if load time will be so long I will probably do cmd.exe instead for most of time, and jump into PoSh when I really have to. I already experience it on my w2k3 box, where I have to wait for quite a long time to get prompt. And my $profile there is very simple, not like the one I have on my primary box.

5. No XML in ISE.

I know, that primary goal with ISE was to replace notepad.exe and make something available out-of-the-box to support PowerShell users in their struggle with scripting. For that purpose however I see one not so small disadvantage: where is XML colouring? I mean really. When you get out of ad-hoc scripting and want to have a module or two – do you really have to look around for some 3rd party tool? In current situation I guess I should, otherwise I will have to check my syntax and hope it will be all fine. I don’t expect it to be very hard to implement it. But I’m not and expert in this area so maybe I’m wrong about that? 🙂 Anyway: I won’t resign from using ISE. After all I do not edit XML files so often, so I can just jump into something else when I really need it… 😉

Summary

As you can see that list is not very long. And trust me: opposite would be much, much bigger. That’s why I love to use PowerShell when I can. Even if it has area for improvements. That’s probably also good part: PowerShell team love to improve their product and they listen to the feedback. And prefer negative feedback over positive. 😉 Probably because it’s usually easier to see positives in your children, and negatives are overlooked. I know it very well from my personal experience. My kids are brilliant, beautiful and very, very kind. 😀