CodePlex Wiki now supports Syntax Highlighting

The CodePlex guys do it again. This is a great feature that will surely help large projects garner a bit more help and support through the use of better developer documentation for getting contributors up to speed. The only thing that’s missing is syntax highlighting support for the PowerShell language. Vote for the feature here - Wiki Syntax Highlighting for PowerShell

You’ll need a CodePlex account for this I think. More information on the July 22nd release:

Syntax highlighting has been added to project wiki pages. See the Wiki Markup Guide for details.
Also added is mailing list support for project discussions: start or respond to a discussion from your e-mail client; get notifications of new responses as they come in, or in daily digest format. Now users can subscribe to an entire project’s discussions, including all new discussions posted to the project. See Mailing Lists Documentation for more information.
Feature requests addressed in this release:
Syntax Highlighting Extension
Feature request: Mailing lists
Issues addressed in this release:
HTTPS should be dropped
HTTPS in forums causes browser warnings
Feature request: please let me input ENTER in release description textbox
Pressing enter while in textarea submits form

Pscx 1.2 progress – archive read and extract support coming

In the latest PowerShellCX changeset, archive read and extract support is finally available. Sorry there are no binary builds yet. Use the Extract-Archive cmdlet as a stand-alone to extract all files. Use Read-Archive to generate ArchiveEntry objects which can be piped through Where-Object for filtering and eventual consumption by Extract-Archive (which can accept ArchiveEntry as well as FileInfo pipeline input). I’ve got progress reporting working too for extract. I’ve added support for reading/extracting SevenZip, Arj, BZip2, Cab, Chm, Cpio, Deb, GZip, Iso, Lzh, Lzma, Nsis, Rar, Rpm, Tar, Wim, Z & Zip.  Yes, you did see ISO support in that list ;-) Write support is only zip, bzip2, tar and gzip still.

There are more features coming, including encrypted archive support.

Get a quick database connection with a nice GUI

I just hacked this one up a few minutes ago to let me get an Oracle, Access, Excel/CSV or SQL Server database connection quickly without fiddling with provider strings and other things that just fall out of my head as fast as they get put in. It uses an old trick of creating a zero-length file with an UDL extension and then executing it. The function returns an operable OleDbConnection object, albeit a closed one unless you specifiy –Open as a switch.

  1. function get-oledbconnection ([switch]$Open) {  
  2.     $null | set-content ($udl = "$([io.path]::GetTempPath())\temp.udl");  
  3.     $psi = new-object Diagnostics.ProcessStartInfo  
  4.     $psi.CreateNoWindow = $true 
  5.     $psi.UseShellExecute = $true 
  6.     $psi.FileName = $udl 
  7.     $pi = [System.Diagnostics.Process]::Start($psi)  
  8.     $pi.WaitForExit()  
  9.     write-host (gc $udl)  
  10.     if (gc $udl) {  
  11.         $conn = new-object data.oledb.oledbconnection (gc $udl)[2]  
  12.         if ($Open) { $conn.Open() }  
  13.     }  
  14.     $conn 
  15. }  

You’ll notice I said OleDbConnection. This means you should pick an OLEDB provider on the provider page for best (read: working) results. Cancelling returns nothing.

image

Ah, how I love the little blue box of typographical terrific-ness.

PSParser Tricks #1 – Resolve all Aliases to definitions in a script

Why do such a thing? Well, if you’ve created your own aliases for commands and you try to give someone your ps1 script file, it will not run because they have not got the same aliases defined as you. Also, scripts that use fully-resolved names like “Get-ChildItem” are more readable for a newcomer to PowerShell than one that is using the unix-like “ls" alias for example. "Get-ChildItem" leads quite directly to the MSDN documentation, but "ls" might lead you anywhere. Before you publish a script online somewhere for the world to use, it’s important that you try to remove any aliases and replace them with the native command names.

Doing this kind of thing has been talked about before but it was always a very difficult thing to do with PowerShell v1.0, what with the lack of BNF documentation describing the grammar etc. Thankfully, it's a lot easier to do with PowerShell v2.0 (currently at release CTP2) because the team has exposed the Tokenizer for use in scripts. There's been suprisingly little use of it so far, so I figured I'd start the ball rolling with a series of articles based around it. So, let's look at an example script that uses aliases and put it through the meat grinder:

image

As you can see, it spits out the expanded script to the output stream. The informational messages are written to the host, so they won't interfere if you redirect the output to a file like: .\resolve-aliases.ps1 in.ps1 > out.ps1

Here's the Resolve-Aliases.ps1 script itself:

  1. #requires -version 2  
  2. param($filename = $(throw "need filename!"))  
  3.  
  4. $lines = $null 
  5. $path = Resolve-Path $filename -ErrorAction 0  
  6.  
  7. if ($path) {  
  8.     $lines = Get-Content $path.path  
  9. } else {  
  10.     Write-Warning "Could not find $filename" 
  11.     exit  
  12. }  
  13.  
  14. # Initialize  
  15. $parser = [system.management.automation.psparser]  
  16. $errors = new-object system.management.automation.psparseerror[] 0  
  17.  
  18. do {  
  19.     $tokens = $parser::tokenize($lines, [ref]$errors)     
  20.     $retokenize = $false 
  21.       
  22.     if ($errors.count -gt 0) {  
  23.         Write-Warning "$($errors.count) error(s) found in script." 
  24.         $errors 
  25.         exit  
  26.     }  
  27.  
  28.     # look through tokens for commands  
  29.     $tokens | % {  
  30.         if ($_.Type -eq "Command") {  
  31.             $name = $_.Content  
  32.               
  33.             # is it an alias?  
  34.             # we use -literal here so '?' isn't treated as wildcard  
  35.             if ((!($name -eq ".")) -and (Test-Path -LiteralPath alias:$name)) {  
  36.                   
  37.                 # gcm may return more than one match, so specify "alias"  
  38.                 # filtering against name kludges the '?' alias/wildcard   
  39.                 $command = gcm -CommandType alias $name | ? { $_.name -eq $name }  
  40.                               
  41.                 # resolve alias which may lead to another alias  
  42.                 # so loop until we reach a non-alias  
  43.                 do {  
  44.                     $command = Get-Command $command.definition  
  45.                 } while ($command.CommandType -eq "Alias")  
  46.                   
  47.                 Write-Host -NoNewline "Resolved " 
  48.                 Write-Host -NoNewline -ForegroundColor yellow $name 
  49.                 write-host -nonewline " to "   
  50.                 write-host -ForegroundColor green $command.name           
  51.                   
  52.                 # Use a stringbuilder to replace the alias in the line  
  53.                 # pointed to in the Token object. StringBuilder has a much  
  54.                 # more precise Replace method than String. This allows us to  
  55.                 # replace the token with 100% confidence.  
  56.                 $sb = New-Object text.stringbuilder $lines[$_.startline - 1]  
  57.                 $sb = $sb.replace($name, $command.Name, $_.startcolumn - 1, $_.length)  
  58.                 $lines[$_.startline - 1] = $sb.tostring()  
  59.                   
  60.                 # now that we've replaced a token, the script needs to be reparsed  
  61.                 # as offsets have changed on this line.   
  62.                 $retokenize = $true 
  63.                   
  64.                 # break out of pipeline, (not 'do' loop)  
  65.                 continue;  
  66.             }  
  67.         }  
  68.     }  
  69. } while ($retokenize)  
  70.  
  71. Write-Host "" # blank line  
  72.  
  73. # output our modified script  
  74. $lines 

Of course, this requires PowerShell v2.0 CTP2. Next in the series, I'll give you a script to check your ps1 scripts for backwards compatibility against PowerShell 1.0. That should be handy for those naughty admins out there who despite all the warnings have installed v2 in production. ;-)

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List