Wednesday, July 6, 2011

Adding a Certificate to the Trusted Root CA Store using PowerShell

Here is a little reminder for myself.

My scenario is that I am adding a simple public certificate to a Local Computer certificate store.  And I need to script it with PowerShell.

I have actually been searching around for this one for a bit and all the results I find make it seem really really complex and complicated and it isn’t.  But there are some gotchas that need to be dealt with.

Here is the script:

$certFile = get-childitem $exPath | where {$_.Extension -match "cer"}
if ($certFile -ne $NULL) {
    "Discovered a .cer in the same folder as this script, installing it in the LocalMachine\Root certificate store.."
    $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certFile.FullName)
    $store = get-item Cert:\LocalMachine\Root
    $store.Open("ReadWrite")
    $store.Add($cert)
    $store.Close()
}

$exPath is the path where my script is executing.  I get that with: $exPath = Split-Path -parent $MyInvocation.MyCommand.Definition

The gotchas are: 

  • Getting the certificate as a certificate object – notice that when I get $cert I am actually getting the $certFile object as a new object that is a certificate, not a file.
  • Opening the store – if you try $store.Add without opening it read/write you actually get a really strange .ctor (a constructor) error.

I use this to include a private Root Certificate Authority with my Azure Service.  I simply add the .cer to the same folder in the Role project as my PowerShell script and publish.

I have my Azure Service certificate and private key being injected by the Azure Fabric and I use this little loop to add my Private Certificate Authority Certificate to the Local Machine Trusted Root Certificate Authorities store.  Thus completing my certificate chain and making my certificate useful – without buying a public certificate or messing with a wildcard public certificate.

Tuesday, July 5, 2011

role discovery data is unavailable with Worker Role front end

When working with the current state of the Azure platform the only thing that I can say is that creativity is king and assumptions are many.

I have spent more time working around default behavior than I like to mention.  And, mind you, I am working with a lot of ‘beta’ features.

I recently ran into a problem with a script that I found simply baffling.  seems it is just a blocked / hidden setting.

For months now I have been tuning PowerShell scripts that interact with the Azure Service Runtime to enumerate internal endpoints and settings of other roles in the Azure environment.  The cmdlet Get-RoleInstance has been highly useful to me.

In my current environment I am using a Worker Role as my front end for the Service (oh, gosh, not a Web Role!?).  Here is where stuff gets weird.  It has an https input endpoint.  (gasp!)

First I have to make this a TCP endpoint since the rules of Visual Studio won’t let me use an input endpoint of https with a Worker Role.  Fair enough.  I can still have my certificated injected.

Now, I set it all up, I add my script, and my .CMD startup task (just as I have with other roles) and my script fails with this strange error:  Get-RoleInstance : role discovery data is unavailable 

All I can wonder is; what the heck?!  I RDP to the instance and try the cmdlet interactively and I get the same.  This makes no sense. This works in my Wen Role and my VM Role, why the problem here?

A bit of searching and I run across some WCF mentions and the local emulator and other things.  Okay, change the search string and try again.  After an hour or so I ran across a hidden property:      <Runtime executionContext="elevated" /> 

I added this to my Worker Role settings in the ServiceDefinition.csdef file and re-published.  And, hey, it works.

I can only speculate that this somehow affects the firewall and fencing set-up of the instance with the fabric.  Allowing both the input endpoint and the internal instance to fabric communication to share the same port.  A few articles that I found mentioned communication to the load balancers, however I don’t think this is really it as the Service Runtime should be querying the Fabric, however I am sure that a load balancer fencing rule was involved.

on to the next script bug.

Thursday, June 30, 2011

Using PowerShell to modify Apache httpd.conf files

Now, you might think this is easy and straightforward.  But when you touch an httpd.conf file with PowerShell – manipulate the contents of the file a bit and then write it back.  Then turn around and start the Apache service and all you get back is “invalid function” – this simple solution becomes a major achievement.

The root to this whole issue I found described in a powershellcommunity.org forum post:  “When you Get-Content, it returns an array of strings, and somewhere between assigning the array to the Body property, it is stripping out the formatting”

This poster had it close.  It is not that manipulating the object is stripping out formatting, it is actually that it is inserting some.

Another clue came from Linux.com:

image

The key is in the first paragraph I included:  “Every operating system uses a special character (or sequence of characters) to signify the end of a line of text. They cannot use standard, common characters to represent the line end, because those could appear in normal text, so they use special, nonprinting characters -- but each operating system uses different ones:”

The other bit of information that I needed was that the application I was using actually runs Apache on Windows.  Apache being a Linux-centric application the pieces were beginning to fall into place.

So, the application generates a template httpd.conf file that I read in: 

$confFile = get-item -path $confFilePath

$conf = (get-content $confFile)

I create a new array abject to write my modifications to: $newConf = @()

I do this because the $conf (the contents of the configuration file) PowerShell actually treats as a String Array.  So, to read each line and find the lines and contents I want to change just needs a foreach loop and a switch.

foreach ($e in $conf) {
    $newConf += $e
    switch -wildcard ($e) {
        "Multiplexer*" {$newConf += "ProtocolMultiplexer " }
        "#Listen*" {$newConf += "Listen " + $Ipv4 }
     }
}
$conf = $newConf  # save the new array back to the original in memory, overwriting the original
Clear-Variable -Name newConf  # clear the variable to prevent duplication, why not reuse the variable.
$newConf = @()  # it has to be cast to an array again.

Now, if I didn’t create the empty array $newConf and just let the loop shove the lines in as it goes I end up with a big text blob.  Not very easy to find and edit things, nor does it give me a usable format to write out.

In the script I repeat this manipulation, inserting sections, modifying lines, etc.

At the end I write the file back out. and I start my Apache engine.

I tried Out-File, I tried Set-Content, I try Add-Content – nothing was working and this is a 200+ line configuration file.  This is when I started researching and thinking about the little tidbits I mentioned at the beginning.

In the end the solution was really rather simple – strip out all the formatting.  The following little loop fixed it all:

foreach ($e in $conf) {
    if ($e -ne $NULL) {
        $e = $e -replace "\r\n",""
        $e = $e -replace "\r", ""
        $e = $e -replace "\n", ""
        Add-content -path $confFile.FullName -Value "$e"
    }
}

Since I am using Add-Content I deleted the original (incomplete)  file prior to writing.  Those replacement strings are the regex representations of the  new line designators the Linux.com article describes.

After I stripped the file of all newline characters (which editors don’t show) then the Apache service started right up.

Tuesday, June 28, 2011

Replacing a backslash with a foreslash in PowerShell

Using the title Replacing “\” with “/” is not very search friendly so we talk of fore- and back- slashes instead.

This is an interesting a quick exercise in RegEx (I had no idea I was getting tangled up in this) syntax.

Lets begin with a path:  $myPath = (${env:ProgramFiles(x86)} + "\MyStuff")

This returns:  C:\Program Files (x86)\MyStuff

Now, I have an Apache config file, so I need to turn those “\” into Linux happy “/”

I first try: $myPath = $myPath -replace "\", "/"  and get the error: Invalid regular expression pattern: \.

Off to search land I go.  Oh, regular expressions, I remember this and I dutifully double escape both my slashes (just like I have to in scripts).  The command now looks like this:  $myPath = $myPath -replace "\\", "//"

No error had.  I return the string and I get C://Program Files (x86)//MyStuff    whoops.

Now.  The error was specific to the find side of the command, not the replace side.  So, to make this correct:  $myPath = $myPath -replace "\\", "/"

Friday, June 24, 2011

Secure Gateway SSL handshake from client failed with IE9

I recently ran into an issue with Internet Explorer 9 (IE9) and Citrix Secure Gateway.

Using two Windows 7 machines (one with IE9 one with IE8) it was quick to realize that this was an IE9 specific issue.

What I discovered was that I could logon, I would get my list of applications, but when I launched my application from the WebInterface the application never launched.

Interestingly, the download of the launch.ica file was never completed by IE9 either.

If I look at the logs on the Secure Gateway server I see the error message: “SSL handshake from client failed.”  But that does not intuitively fall into place with the download of the launch.ica file not completing.

I have further learned that this is most likely due to new security sandboxing that exists in IE9.

The workaround to all of this is to place the URL of your Citrix Secure Gateway server into the Trusted Sites security zone within IE9.

After doing this, it all works as before.

I hope this helps overcome some issues and moves you on to IE9 (I will admit, I am still not used to typing search strings into the same box that I have been typing URLs into for years).