Cover of the original UK paperback edition of ...
Image via Wikipedia
The day upon which the answer to the ultimate question of life the universe and everything will be revealed!

Well, ok, we already know that the answer is 42 … which, in binary, is 101010 …

Clearly we need to make sure that everyone celebrates The Hitchhikers’ Guide to the Galaxy on October 10 this year, but I’m not sure what to suggest as an appropriate celebration. Should I just recommend you read through the series again? Should we have group readings on that day? Try blogging in binary? The one thing I do know, is that I won’t even suggest viewing the movie(s). Anyone have some good ideas? They must be Mostly Harmless of course, but I’m sure some of you will have some good ideas :) . We’re definitely having a party at my house!

Reblog this post [with Zemanta]

I just posted an article to the FAQ on the PoshCode Wiki answering this question that came up again on our IRC PowerShell user group today. It came up in the context of determining whether a function was the last function on the pipeline, because one of our users was looking for a way (other than creating ps1xml files) to output objects onto the pipeline for use in other functions, but still format those objects nicely if they were output directly.

Before I give the solution, I just want to say: don’t change your output based on where you are in a pipeline.

There are numerous scenarios where your function will be the last one on a pipeline, but still be participating in further pipelines, including formatting and output modification. For example, take our function Test-Pipeline (defined below) in these three scenarios below. In none of these scenarios would it be appropriate for the function to write formatted output instead of outputting the raw object, but in each case, the function is the last function in the pipeline.


# Assignment
$order = Get-ChildItem | Test-Pipeline
$order | Format-Table *

# Nested Pipelines
Get-ChildItem | Where-Object { $_.PsIsContainer} | ForEach-Object {
Get-ChildItem $_ | Test-Pipeline
} | Select-Object Pipe*

# Nested Expressions
@( Get-ChildItem | Test-Pipeline )[0].PipelineLength | ForEach-Object { $_ }
 

However, if you want to determine your function’s position in the pipeline for some other reason, the answer is simple. You need to use $MyInvocation and compare the PipelineLength and PipelinePosition properties:


## Useful for testing all sorts of things about the pipeline
function Test-Pipeline {
[CmdletBinding()]
Param(
   [Parameter(ValueFromPipeline=$true)]
   [PSObject]$InputObject,
   [Switch]$Passthru,
   [Switch]$PassCmdlet
)
BEGIN {
   Write-Output $MyInvocation
   if($PassCmdlet) {
      Write-Output $PsCmdlet
   }
}
PROCESS { if($Passthru){ $_ } }
}

## Shows
function Test-LastInPipeline {
Param(
   [Parameter(ValueFromPipeline=$true)]
   [PSObject]$InputObject,
   [Switch]$Passthru
)
BEGIN {
   $IsLast = $MyInvocation.PipelineLength -eq $MyInvocation.PipelinePosition
   if(!$IsLast) { $MyInvocation }
}
PROCESS { if($Passthru){ $_ } }
}
 
Reblog this post [with Zemanta]

So, the Windows PowerShell 2.0 Software Development Kit is basically a collection of samples, and it has been released separately from the Windows Platform SDK for a change, making the download a tiny 2.35MB …

There are lots of examples in there in C# (no other languages), and honestly, some of them ought to make it into PSCX or some other project where people could grab pre-compiled versions ;)

  • A Template for creating PSProviders, and a sample PSProvider (for Access databases).
  • A sample of participating in Transactions (a set of “transacted comment” cmdlets for creating comments that go along with a transaction).
  • Example cmdlets: Select-Object, Select-String, Get-Process, Stop-Process
  • Dealing with issues with Serialization in PowerShell
  • PowerShell Eventing:
    • Deriving from ObjectEventRegistrationBase to create Register-FileSystemEvent
    • Receiving notifications from PowerShell Events on remote computers.
    • Hosting APIs, including (among others):
    • Restricted runspaces
    • Runspace pools
    • Remote runspaces (and remote runspace pools)
    • Running commands in parallel or sequentially
    • Calling Cmdlets and passing parameters
  • Reproducing the default PowerShell.exe output

Honestly, if you’re a developer that’s been wondering about learning to code cmdlets, or host PowerShell as a scripting engine, now’s the time.

Consider this a reminder that December is ScriptClub month at our local PowerShell User Group.

What is Script Club?

Script clubs are like a hands on lab with no set topic or teacher.

You bring an idea for a script, and ask your fellow PowerShell users for help getting the script written. Pretty much anything goes — just bear in mind that it may be hard to test things like Exchange scripts or Active Directory management scripts unless you have a nice virtual lab on your laptop ;)

Please join us for PowerShell Script Club this Wednesday, and bring your friends! Script Club is a great way to learn PowerShell. Beginners through advanced users are equally welcome.

What are the Rules of Script Club?

  1. You always talk about script club
  2. You always talk about script club
  3. If someone asks for help, and you can help, you help
  4. Two people help one person at one time
  5. One module per person per night
  6. All scripts, all PowerShell
  7. Scripts will be as short as they can be
  1. If this is your first time at Script Club, You have to script! ;)

Please RSVP so we can get a head count (especially if you want Pizza)!

As usual, our meeting will be on the Third Wednesday of the month, with Pizza at 6pm, followed by Script Club at 6:30. And of course, we’ll be meeting at the New Horizon’s training center at 50 Methodist Hill Drive, Suite 50, Rochester, NY. Click here for directions and a map.

Putting together some scripts from Keith Hill and some of my own code … and using the System.Runtime.Serialization.Json namespace, I’ve managed to make a few pieces to import and export JSON for you to play with. I put it on PoshCode.

This code is very raw at the moment, and quite honestly, the only function here that you can really use on random JSON returned from existing web-services (that is, JSON which doesn’t map to a .Net class) is Convert-JsonToXml.

Convert-JsonToXml is very useful in PowerShell, since XML is a first class PowerShell citizen, and navigable via dot-notation almost as though it were a file-system structure (Hmm… that would actually make an interesting provider, with -Root set as an XML document). In any case, you could also use Select-Xml to dig deeper, and do all of the usual PowerShell stuff against the resulting XML, whereas without this, JSON is just a confusing string.

However, the most interesting JSON conversion in PowerShell would probably be to convert JSON to a series of nested hashtables and arrays (a very accurate translation of the data) — or to new up a dynamic PSobject or collection of objects … I’ll probably write one of those later today, just for fun :)

But Why JSON?

I honestly don’t know. The more I play with JSON, the more it looks like XML circa 1996 (that is, before the creation of XSLT, XPATH and the other tools which actually make XML useful as a data language). Obviously it’s much lighter than XML: it doesn’t have closing tags, it eschews namespaces … but from where I stand, those benefits don’t make up for the loss of the power of transformations and querying — not to mention the lack of tooling in .Net ;)

I had a look at JAQL and a few similar projects, and all of them are in their infancy, and restricted to javascript. That is, they’re not general-purpose query languages, and they’re not available in server-side programming environments … making JSON (generally speaking) a poor choice for a data language outside of it’s original place: sending well-defined simple data from your back end to your front end.

I certainly wouldn’t choose to use JSON in PowerShell, nor would I consider it a good choice for the output of web-services (bear in mind that without namespaces it also has no standard way of doing versioning either).

Reblog this post [with Zemanta]

I know that I just wrote a post last week about XPath and namespaces in PowerShell, but at the time I left out one possible way of dealing with namespaces, because it’s not the right way of doing things. However, sometimes it’s nice to have options, and when you’re working on the command-line in PowerShell, or just trying to figure out a proof-of-concept call to a web service, you really don’t need to deal with namespaces correctly, you just need it to work.

With that in mind, I present to you the fourth option: just strip the namespaces out! The simplest way to do that is to run the XML through an XSL stylesheet which just outputs the local-name() of each node (including attributes), and remove any namespace definitions (processing instructions).

<xsl :stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   </xsl><xsl :output method="xml" indent="yes">
   </xsl><xsl :template match="/|comment()|processing-instruction()">
      </xsl><xsl :copy>
         </xsl><xsl :apply-templates>
      </xsl>
   

   <xsl :template match="*">
      </xsl><xsl :element name="{local-name()}">
         </xsl><xsl :apply-templates select="@*|node()">
      </xsl>
   

   <xsl :template match="@*">
      </xsl><xsl :attribute name="{local-name()}">
         </xsl><xsl :value-of select=".">
      </xsl>
   
 

That stylesheet and the basic steps of the process will work anywhere, from Java to C# to the web … but since my current language of choice for prototyping is PowerShell, I’ll show you how to implement it there as Remove-XmlNamespace. Once you have that, I think you’ll see that it was relatively simple for me to write a new Select-XML which adds a parameter RemoveNamespace which is implemented by calling this Remove-XmlNamespace

That actually allows you to call Select-Xml with the -RemoveNamespace parameter just as though the namespaces didn’t exist. Of course, the returned XML nodes will, in fact, NOT have namespaces … so they may not be quite the same as the source, but the data will all be there. :-)

Read the rest of this entry »
The style I use has a nice black background...

The style I use has a nice black background...

A while back Thell Fowler (with a little help, and a lot of testing from me) wrote a very good PowerShell Lexer for Notepad++ 5.2 and later… it’s very thorough, has good code-folding, and full support for PowerShell 2.0 syntax highlighting.

I mention this because Notepad++ 5.6 just released yesterday, and it has built-in support for PowerShell syntax courtesy of Scintilla ... but it’s very, very bad. The scintilla PowerShell lexer is probably the most minimal PowerShell lexer I’ve seen (it’s worse than the old “user style” I had created for Notepad++) and has no support for:

  • The ` escape character
  • Here-strings (which can contain quotes, etc)
  • The difference between strings and literal strings and literal here-strings
  • The begin/process/end block keywords and Param()
  • PowerShell operators (like -is or -gt or -notcontains)
  • [System.Namespace.Class]::Method() syntaxes
  • Nested $variables inside strings
  • Nested $( code blocks ) inside strings (with strings inside those, and …)
  • Any of the new PowerShell 2 syntax like:
    • multi-line comments
    • [Parameter()] and [Alias()] and [Validate …. ]
  • [CmdletBinding()]

There’s probably more, but I couldn’t be bothered to spend more than a couple of minutes with it. As you can probably guess … all of those features are supported by the external PowerShell Lexer plugin that Thell wrote, so if you’re a PowerShell and Notepad++ user, I apologize for not drawing your attention to our PowerShell Lexer for Notepad++ before :) .

Incidentally, I stuck a screenshot in this post so you can see how I use it, but there’s one a more complete example of the PowerShell Syntax Highlighting on that lexer download page. ;-)

Reblog this post [with Zemanta]

Although there are a few “CSS Selector” libraries, most browsers haven’t even implemented CSS3 selectors, never mind frameworks like .Net or scripting languages like Javascript or PowerShell ;) so XPath remains the most powerful way to deal with finding specific data in an XML file, and by extension, XHTML and even HTML files (if you can convert them using something like SgmlReader) is to use XPath queries.

There are a lot of XPath tutorials around the web, so there’s no need for me to get into that very much, but I just wanted to write a brief note about using XPath with documents that have namespaces (particularly, from .Net). The problem is that in order to select nodes that have a namespace assigned, you must use a namespace prefix and a NamespaceManager. So even if it’s the default namespace, if there’s an xmlns=”...” on the document, you have to create and use a prefix.

The bottom line is this: if you have an XML document that looks like this:


<event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <system>
    <eventid>100</eventid>
    <version>2</version>
    <level>1</level>
    <task>4002</task>
    <opcode>34</opcode>
  </system>
  <eventdata>
    <data name="BootTsVersion">2</data>
    <data name="BootStartTime">2009-11-22T08:45:11.640400200Z</data>
    <data name="BootEndTime">2009-11-22T08:48:23.432178500Z</data>
    <data name="SystemBootInstance">18</data>
    <data name="UserBootInstance">15</data>
  </eventdata>
</event>
 

That bit at the top where it says: xmlns="http://schemas.microsoft.com/win/2004/08/events/event" is assigning a default namespace. Sometimes you’ll see something like this (eg: in RSS):


<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
   <channel>
      <item>
         <title>Buttons</title>
         <link />http://www.flickr.com/photos/jaykul/4114286262/
         <description>Quick cut-n-paste from a screenshot</description>
         <pubdate>Tue, 17 Nov 2009 20:46:31 -0800</pubdate>
         <guid ispermalink="false">tag:flickr.com,2004:/photo/4114286262</guid>
                        <media:content url="http://farm3.static.flickr.com/2552/4114286262_001e2f8905_o.png" type="image/jpeg" height="157" width="337">
                        <media:title>Buttons</media:title>
                        <media:description type="html">&lt;p&gt;Quick cut-n-paste from a screenshot into your mockup&lt;/p&gt;</media:description>
                        <media:thumbnail url="http://farm3.static.flickr.com/2552/4114286262_cba8aaf967_s.jpg" height="75" width="75">
                        <media:credit role="photographer">Jaykul</media:credit>
                        <media:category scheme="urn:flickr:tags">screenshot snagit</media:category>
      </media:thumbnail>
       </media:content>
</item>
</channel></rss>

This one assigns a specific prefix “media” to the namespace url “http://search.yahoo.com/mrss/” ...

Selecting nodes with namespaces

In either case, if you want to select a node that’s assigned to a namespace (which is ALL the nodes in the first example, but just the ones that start with media: in the second example) in .net, you have to specify the namespace in order to select those nodes with XPath. PowerShell 2.0 has a Select-Xml cmdlet which accepts -Namespaces as a parameter: you simply provide a hashtable of names to urls.

If you had loaded the first document above into $xml, you could select the BootStartTime and BootEndTime using an XPath query like this: //e:Data[Name = ‘BootStartTime’ or Name = 'BootEndTime'] but we have to DEFINE that “e” namespace. To do so using Select-Xml you just pass it into the command


$xpath = @{
    Start="//e:Data[@Name = 'BootStartTime']/text()"
    End="//e:Data[@Name = 'BootEndTime']/text()"
}
$ns = @{ e = "http://schemas.microsoft.com/win/2004/08/events/event" }

[DateTime]$Start = Select-Xml -Xml $xml -XPath $xpath.Start -Namespace $ns |
                   Select -Expand Node | Select -expand Value

[DateTime]$End = Select-Xml -Xml $xml -XPath $xpath.End -Namespace $ns |
                 Select -Expand Node | Select -expand Value

($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Of course, you don’t have to use Select-Xml, you can do this in plain .Net without cmdlets (and this is what you would have to do in C#). In fact, depending on the situation, it might even be simpler:


$xpath = @{
    Start="//e:Data[@Name = 'BootStartTime']/text()"
    End="//e:Data[@Name = 'BootEndTime']/text()"
}

$ns = New-Object Xml.XmlNamespaceManager $xml.NameTable
$ns.AddNamespace( "e", "http://schemas.microsoft.com/win/2004/08/events/event" )

[DateTime]$Start = $xml.SelectSingleNode( $xpath.Start, $ns ).Value
[DateTime]$End   = $xml.SelectSingleNode( $xpath.End, $ns ).Value

($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Selecting nodes regardless of namespaces

There are, however, two ways that you could avoid specifying the namespaces. The first is to just avoid specifying the node name at all. In that first example, that would be fairly easy, because the “BootStartTime” and “BootEndTime” names are unique to the nodes we’re interested in (even if there were boatloads of identical events, you’ll never have a Name=“BootStartTime” attribute on the tag, for instance). The second way is to filter using the local-name function, and specify just the “local” name (which is the non-namespace-qualified part of the name).

So to ignore the tag name, we can just use a * for a wildcard. The only real difference is that we don’t need the namespace, and the XPath pattern will be different:


$xpath = @{
    Start="//*[@Name = 'BootStartTime']/text()"
    End="//*[@Name = 'BootEndTime']/text()"
}

[DateTime]$Start = (Select-Xml -xml $xml $xpath.Start).Node.Value
[DateTime]$End   = (Select-Xml -xml $xml $xpath.End).Node.Value
($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Or to specify the local name, we can use the Local-Name function. Again, we don’t need a namespace, we are just changing the XPath to be a more specific match:


$xpath = @{
    Start="//*[local-name() = 'Data' and @Name = 'BootStartTime']/text()"
    End="//*[local-name() = 'Data' and @Name = 'BootEndTime']/text()"
}

[DateTime]$Start = $xml.SelectSingleNode( $xpath.Start ).Value
[DateTime]$End   = $xml.SelectSingleNode( $xpath.End ).Value
($End - $Start).ToString() # Displays: 00:03:11.7917783
 

Reblog this post [with Zemanta]

For some reason, people are having trouble finding links to the release version of Windows PowerShell 2.0 … I suspect it’s because while it was in CTP, a lot of us bloggers wrote about it and linked to the various CTP downloads … but there aren’t nearly as many posts announcing the release of Windows PowerShell 2.0 as you would expect.

Of course, most of the fault is Microsoft’s, because they buried PowerShell 2 in a knowledge base article with a title that exceeds nondescript, even for Microsoft: Description of the Windows Management Framework on Windows XP, Windows Server 2003, Windows Vista, and Windows Server 2008. What? Even the Microsoft PowerShell Team Blog never actually wrote a post announcing the PowerShell 2.0 release is available for download but instead wrote about the Windows Management Framework being released.

But in any case, I’m calling on the blogging community to fix the search engines by linking Windows PowerShell and particularly “Windows PowerShell 2.0”: http://support.microsoft.com/kb/968929 to either the Knowledge base article 968929 which has the download links for PowerShell 2.0 for Windows XP, Vista, and Server 2003 and 2008 … or to Microsoft.com/PowerShell which has the latest download links in the side-column on the right hand side. :)

I can’t fix the search engines on my own, but what was that slogan? Together we can!

I write a lot of PowerShell scripts, and I work on modules a lot, including ones which I load automatically in my profile. Sometimes I forget to sign those modules before I restart my console/host, and then I get errors when they’re loaded from the profile. I wrote a script to solve this problem by automatically signing files every time they’re edited, and I figured I’d share it below, but first let me try explaining what code signing is, and why you should care.

What is code signing?

Code signing is the process of digitally signing files to confirm the author and guarantee that the file has not been altered or corrupted. It’s essentially the same as signing emails: it guarantees that they were actually authored by the person claiming to be the author, and that they weren’t changed after the author signed them. (For more information see Apple’s explanation and Microsoft’s).

How does digital signing work?

Basically, digital signing is cryptography, so a full understanding of it really requires taking a 400-level college course, but here are the basics: You take some data (binary bits) and use a well-known algorithm to calculate what is called a “hash” of the bits. This hash is mathematically-generated from the source data, and so it can be re-calculated by the receiver. The hash is then “signed” via another algorithm: using a private key (see Public Key Infrastructure (PKI) for more about how these keys are managed) the signer encrypts the hash and attaches it to the file.

With public/private key encryption, data that is encrypted by the private key can be decrypted by the public key, so the encryption of the hash (and sometimes the public key, as well) is attached to the file so that the end user can re-calculate the hash and decrypt the signature to verify: a) that it was encrypted by the private key belonging to the author, and b) that the hash matches the hash that the author signed.

What’s all this about keys?

In PKI, the “key” is actually part of what’s called an SSL certificate issued to you by a Certificate Authority (CA) who verifies your identity. Verisign introduced the idea of “classes” for certificates, and you can now get free, Class 1 certificates for email signing from most CA’s now (like Thawte and Comodo and StartCOM), where the only thing they verify is that the person being issued the certificate can send/receive email at that address.

Of course, if you want to verify yourself as the author of code, we want to know more about you than your email address. So to sign code, you need at least a Class 2 certificate, for which proof of identity is required. This typically comes in the form of providing (photos of) your passport, driver’s license and/or other photo ID to verify that you are who you claim to be, and answering a few questions on the phone to validate that you own the phone number provided… or providing tax or other documents to prove the existence of an organization and that you’re qualified to speak for them. There are also additional classes: Class 3, 4, and 5 are extended validation certificates used for servers, software signing, b2b transactions and government security.

Why should I sign PowerShell scripts?

Well, the chances are, you don’t need to. Script signing is really a feature for corporations. The idea is that scripts from your IT department need to be verifiable and unalterable… code-signing gives companies a way to lock down and secure PowerShell scripts: setting a global policy requiring script signing, and ensuring that all scripts produced by the corporate administrators are properly signed…

As an individual, script-signing doesn’t really offer you much unless you share your computer with other administrator users. After all, what it protects you from is intentional or accidental altering of the script. If there’s no one else who has access to your computer, then nobody can alter your scripts. Of course, if someone hacks your computer enough to alter or create files on your hard drive and wanted to do something malicious, scripts would be a silly thing to target :)

There is, however, one additional time when you might want to sign your scripts. If you’re distributing scripts, whether via PoshCode.org, the TechNet script gallery, or on CodePlex or the MSDN code gallery … signing them gives you (and your users) the assurance that you are the author, and they haven’t been altered. In fact, the PoshCode Module which is available on PoshCode.org, and which allows you to search and download (as well as upload) PoshCode scripts uses script signing to allow it to safely upgrade itself. It features a Get-PoshCode -Upgrade command which will check for, and fetch, the latest version of the PoshCode module, and then validate it’s code signature is the same as the previous one before using it.

Remember, code signing cannot:

  • Guarantee that code is free of security vulnerabilities.
  • Guarantee that a script doesn’t load unsafe or altered code during execution.
  • Prevent copying or altering of your scripts (although PowerShell policies can prevent accidental execution of altered scripts).

How do I sign scripts?

Assuming that after skimming all of that, you want to try signing your scripts, you need a certificate. You can generate one yourself (although it’s not easy, and the signed scripts which will only work locally on your system, and won’t be trusted by anyone else) or you can get one from a public Certificate Authority (I recommend StartCom/StartSSL which only costs $40 for two year certificates).

Typically, your certificate will be a .pfx file which you can load using Get-PfxCertificate, or you might have imported it into your local certificate store using CertMgr.msc, in which case you can load it using Get-Item Cert:\CurrentUser\My\ with the thumbprint of the certificate. In either case, you’ll have a certificate object you can pass to Set-AuthenticodeSignature along with the file path.

Wasn’t there supposed to be something automatic here?

Awhile back I wrote an Authenticode Script Module which has wrappers for signing and testing signatures on scripts. It uses a metadata file (which you have to create yourself) with a PrivateData variable that points to either the thumbprint of a certificate you’ve imported to your computer’s certificate store, or the path to a .pfx file … and allows you to sign files by just writing sign .\FileToSign.ps1 without having to Get-PfxCertificate each time, or even remember to turn on the -TimeStampUrl feature so that your signed scripts stay signed even after the certificate expires. That script helps a lot, but I’ve been wanting my text editor to sign the scripts automatically when I save them …

I mostly use Notepad++ for editing PowerShell scripts (with a PowerShell Syntax lexer I helped create), but after playing with the idea of writing a plugin to sign things after saving, I ended up deciding to go with something simpler: a PowerShell script to watch a folder for changes and sign any scripts I edit or save.

I’ve added a function I call Start-AutoSign to my authenticode script module which takes a path and a -Recurse flag and sets up a System.IO.FileSystemWatcher to detect saves, creates, and moves … and (re)sign the script if it needs it. Here is Start-AutoSign without the help docs or anything (so I can discuss it). You should just download the whole script module if you want to use it :)

PARAM($Path=".", $Filter= "*.ps*", [Switch]$Recurse, $CertPath, [Switch]$NoNotify)
if(!$NoNotify -and (Get-Module Growl -ListAvailable -ErrorAction 0)) {
   Import-Module Growl
   Register-GrowlType AutoSign "Signing File" -ErrorAction 0
} else { $NoNotify = $false }

$realItem = Get-Item $Path -ErrorAction Stop
if (-not $realItem) { return }

$Action = {
   $InvalidForm = "The form specified for the subject is not one supported or known by the specified trust provider"
   
   ForEach($file in Get-ChildItem $eventArgs.FullPath | Get-AuthenticodeSignature |
      Where-Object { $_.Status -ne "Valid" -and $_.StatusMessage -ne $invalidForm } |
      Select-Object -ExpandProperty Path )
   {
      if(!$NoNotify) {
         Send-Growl AutoSign "Signing File" "File $($eventArgs.ChangeType), signing:" "$file"
      }
      if($CertPath) {
         Set-AuthenticodeSignature -FilePath $file -Certificate $CertPath
      } else {
         Set-AuthenticodeSignature -FilePath $file
      }
   }
}
$watcher = New-Object IO.FileSystemWatcher $realItem.Fullname, $filter -Property @{ IncludeSubdirectories = $Recurse }
Register-ObjectEvent $watcher "Created" "AutoSignCreated$($realItem.Fullname)" -Action $Action &gt; $null
Register-ObjectEvent $watcher "Changed" "AutoSignChanged$($realItem.Fullname)" -Action $Action &gt; $null
Register-ObjectEvent $watcher "Renamed" "AutoSignChanged$($realItem.Fullname)" -Action $Action &gt; $null

A few things to notice: first, I’m assuming you’re using my Set-AuthenticodeSignature wrapper, so by default I don’t pass it an actual certificate. Second, in order to avoid eternally looping and re-signing the script over-and-over, you have to have a way to make sure you don’t re-sign it when it “changes” because you signed it. The approach I took was to test and see if the signature was valid or not (and if it’s valid, then don’t sign it again). Third: when you Get-AuthenticodeSignature, the Status codes leave much to be desired, returning the same “UnknownError” in several cases where they know exactly what the error is. You can check the StatusMessage and see that they even tell you what the error was:

  • The form specified for the subject is not one supported or known by the specified trust provider
  • A certificate chain could not be built to a trusted root authority
  • A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider
  • A required certificate is not within its validity period when verifying against the current system clock or the timestamp in the signed file

There may be other reasons too that I haven’t encountered yet, but the one thing we’re concerned with is the first one that the “form” isn’t supported. That means this is a file type which Set-AuthenticodeSignature can’t sign. PowerShell’s signing only works with executables, PowerShell scripts, modules, metadata, and xml files … so there’s no point trying to sign anything else. You may also notice that in my script (by default) I’m only signing .ps* files (that is: scripts, modules, metadata and ps1xml files), and that’s because with .dll and .exe files, I would prefer to sign them as part of my build step anyway.

One last thing: as with a few of my recent scripts, this one is designed to use Growl for Windows to notify you whenever it signs anything. If you don’t have the Growl module available, it should just skip right over that without any problems, but you can disable it in any case with the -NoNotify switch. Personally, I like seeing the popup so that I know it’s working, and know that I’m not accidentally signing something … and I love Growl for script notices because I can skin it, configure sounds, and forward the notices to other machines … or even temporarily disable them, all without having to tweak scripts.

Reblog this post [with Zemanta]