Huddled Masses
You can do more than breathe for free...
Browse: Home / Extending strings, and secure strings, in PowerShell.

Extending strings, and secure strings, in PowerShell.

By Joel 'Jaykul' Bennett on 05-Jun-2007

One of the coolest things about scripting in PowerShell is that they’ve enabled the addition of extension methods to any class (object). Essentially, this means that you can add whatever methods This enables all sorts of utility functions that would normally end up in a library to instead be added to the base objects. Just for example, this week I was working on a script that needed to do HTTP basic authentication, which requires Base64 encoding a string. Now, that’s not very hard to do, really:


$name = "Joel Bennett"
$encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes( $name ))
 

But really, that’s kind of a pain to remember, nevermind type each time. I mean, tab-completion helps, but what with all the square brackets and double-colons … So, instead, wouldn’t it be cool if I could just take my original string and call $name.AsBase64? Well, I can, with a pretty simple custom type.


<Types>
  <Type>
    <Name>System.String</Name>
    <Members>
      <ScriptProperty>
        <Name>AsBase64</Name>
        <GetScriptBlock>
          [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($this))
        </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>FromBase64</Name>
        <GetScriptBlock>
          [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($this))
        </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
</Types>
 

We take this XML, put it in a file with the .ps1xml extension, and then call Update-TypeData MyTypes.ps1xml … Now we can call .AsBase64 or .FromBase64 on any string.

So then I ran into this simple problem. I wanted (in my script) to have the user type a password in… but not have it show up in their console. It turns out there’s a very over-engineered, and extremely elegant solution for this in PowerShell: Read-Host -AsSecureString "Prompt". It’s exactly what I wanted, in that it results in the console showing ***** as you type your password in. The only problem is, what you get out is a System.Security.SecureString which is essentially … well, useless. ;)

Honestly, I know that there are times when you need to store a string in such a way that it’s encrypted even in memory … but the fact is that it’s complicated to get the text value back out, so it really isn’t very useful. Anyway, you could add this to your custom types file:


  <Type>
    <Name>System.Security.SecureString</Name>
    <Members>
      <ScriptProperty>
        <Name>AsInsecureString</Name>
        <GetScriptBlock>
          $BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($this)
          [System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR)
          [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
        </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
 

But then, of course … it wouldn’t be very secure anymore. The point of extending types instead of writing script libraries is that you want things to be discoverable, and a property that exposes a secure string as a regular string probably isn’t really something you wanted to make discoverable ;) .

For my purposes, I decided that was a bad idea, and settled on adding this function to my regular library of functions:


function Read-HostMasked([string]$prompt="Password") {
  $password = Read-Host -AsSecureString $prompt;  
  $BSTR = [System.Runtime.InteropServices.marshal]::SecureStringToBSTR($password);
  $password = [System.Runtime.InteropServices.marshal]::PtrToStringAuto($BSTR);
  [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR);
  return $password;
}
 

That lets you take advantage of the in-console masking, but returns a plain old string into your script so you can use it easily. (In my case, I wanted to handle HTTP Basic Authorization using System.Net.WebClient so I did something like: $webclient.Headers.Add("Authorization", "Basic "+((Read-Host Username)+':'+(Read-HostMasked Password)).AsBase64). Hopefully that makes it obvious how that Read-HostMasked function works and why it’s useful.

So. If anyone knows a better way to get a password from the user interactively without showing it on the console, I’m all ears! I’m not worried about having it in memory, in this case — in fact, I’m not even storing it, just passing it to the Base64 encoding … and I can’t avoid that.

Technorati Tags: PowerShell, Scripting, .Net, SecureString

Similar Posts:

  • Parenthesis in PowerShell
  • More Custom Attributes for PowerShell (Parameter Transformation)
  • How to: Invoke PowerShell and use the results from C#?
  • The problem with calling legacy/native apps from PowerShell
  • What Scope Am I In?

Posted in Huddled | Tagged .Net, PowerShell, Scripting, SecureString, String

« Previous Next »

Lijit Search

Tags

.Net .Net 2008 Scripting Games Automation Bugs Design Development Funny Gadgets GeoShell GUI Huddled Masses Internet licensing Microsoft Modules My Software News Personal PInvoke Pipeline Politics PoshCode PoshConsole PowerBoots PowerShell PowerShell Functions PowerTips Rants Recommender Repository Scripting ShowUI Software Solutions Textile Tips User Group UserInterface WalkThrough WebHosting Windows 7 WordPress WPF Xml

About Huddled Masses

This is web site is dedicated to the musings of Joel Bennett (aka Jaykul) about technology, software, software development, the web, and the world.

Any resemblance of the views expressed and the views of my employer, my terminal, or the view out my window are purely coincidental. The resemblance between them and my own views is non-deterministic. The question of the existence of views in the absence of anyone to hold them is left as an exercise for the reader.

P.S.: I occasionally link to things I think are great. When I do, I occasionally find a "referral code" so I can make a little cash. I promise that I don't link to anything just because of that cash (I wouldn't cross the street for the amount of cash those links bring in, never mind write a whole blog post) ... but I do not promise that things I link to will stay great as time passes, nor that you will agree with me about their greatness!

Archives

  • January 2012
  • October 2011
  • August 2011
  • July 2011
  • June 2011
  • March 2011
  • February 2011
  • January 2011
  • November 2010
  • August 2010

Copyright © 2012 Joel Bennett.

Powered by WordPress and Hybrid.