Sunday, 25 May 2014

PowerShell Wix Extension

I've looked, but I couldn't find anyone who'd implemented a Wix Extension that would allow running PowerShell scripts. So I've spent a few hours this weekend writing one (and learned a bit more about Wix and MSIs along the way).

This extension allows you to run script from a file that is included in the MSI, or inline script (inside a CDATA section).

By hosting PowerShell in the custom actions, scripts also get access to the $session variable (which is of type Microsoft.Deployment.WindowsInstaller.Session), so you can call $session.Log("Running this") and it will add "Running This" to the MSI log!

Here's an example of what you can do:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:powershell="http://schemas.gardiner.net.au/PowerShellWixExtensionSchema">
  <Product Id="*" Name="PowerShellWixTest" Language="1033" Version="1.0.0.0" Manufacturer="David Gardiner" UpgradeCode="c61298af-d8c9-4179-903f-f42fa69b59ad">
    <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

    <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
    <MediaTemplate />

    <Feature Id="ProductFeature" Title="PowerShellWixTest" Level="1">
      <ComponentGroupRef Id="ProductComponents" />
    </Feature>

    <powershell:File Id="PSFile1" File="[#TestPs1]" Arguments="&quot;First Argument&quot; 2"/>

    <powershell:Script Id="Script2">
      <![CDATA[
        
        # Write-Host "Number 2";
        
        for ($i = 1; $i -le 100; $i++) 
        { 
          Write-Progress -Activity "Activity" -Status "Status $i% complete" -CurrentOperation "Operation $i" -PercentComplete $i
          Start-Sleep -Milliseconds 5 
        }
        
        ]]>
    </powershell:Script>
    
    <UI>
      <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
      <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
      <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />

      <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
      <Property Id="WixUI_Mode" Value="Minimal" />

      <DialogRef Id="ErrorDlg" />
      <DialogRef Id="FatalError" />
      <DialogRef Id="FilesInUse" />
      <DialogRef Id="ProgressDlg2" />
      <DialogRef Id="UserExit" />

      <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>

      <Property Id="ARPNOMODIFY" Value="1" />
    </UI>

    <UIRef Id="WixUI_Common" />
  </Product>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="PowerShellWixTest" />
      </Directory>
    </Directory>
  </Fragment>

  <Fragment>
    <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
      <Component Id="ProductComponent">
        <File Id="TestPs1" Source="Test.ps1" KeyPath="yes" />
      </Component>
    </ComponentGroup>
  </Fragment>
</Wix>

The code and releases are hosted on GitHub - https://github.com/flcdrg/PowerShellWixExtension

Development resources

Friday, 9 May 2014

Aussie Forecast

My latest app for Windows Phone is now available in the store – Aussie Forecast!

Aussie Forecast Lock Screen

Windows Phone 8 supports apps displaying custom information on the lock screen. The Bing Weather app is a nice example, but I was frustrated by the inaccurate forecast data that it was using. Not the first time I've seen this problem.

So I thought I'd create my own app that uses the Australian Bureau of Meteorology's data to display the forecast for a selected location. You can optionally choose to have the forecast displayed on your phone's lock screen, and a background task runs at regular intervals to keep the information current.

Application main page screenshotSettings screen

Future enhancements will include allowing a user-selected photo for the background image or the daily Bing Photo.

If you've got a Windows Phone 8 device, then please try it out!

Download from the Windows Phone Store

Sunday, 4 May 2014

Using BugSense for Windows Phone with Caliburn.Micro

BugSense is a 3rd party service I came across recently being promoted on Nokia's (now Microsoft's) DVLUP site. They provide aggregation and reporting of errors from your apps.

All of the usual platforms are supported, and conveniently they provide NuGet packages to facilitate integrating with Windows Phone 7, 8 and Windows Store apps.

I like using Caliburn Micro (CM) for most of my Windows Phone apps to help with using the MVVM pattern, and one of the requirements for using CM is to strip out the contents of the App.xaml.cs file's constructor, leaving just

public App()
{
    // Standard XAML initialization
    InitializeComponent();
}

The BugSense instructions however assume you're using a regular Windows Phone project that has the original App.xaml.cs contents. The workaround I've settled on is to add the BugSense code to the body of the Configure method in the CM AppBootstrapper class.

First, add the BugSense namespaces:

using BugSense;
using BugSense.Core.Model;

Then initialise BugSense (replacing API_KEY with the key displayed when you click on 'Help me integrate' on the BugSense site:

protected override void Configure()
{
    // Initialize BugSense
    BugSenseHandler.Instance.InitAndStartSession(new ExceptionManager(App.Current), RootFrame, "API_KEY");

You might also wish to add logging of handled exceptions too:

catch (Exception ex)
{
    BugSenseLogResult logResult = BugSenseHandler.Instance.LogException(ex);

    // Examine the ResultState to determine whether it was successful.
    Debug.WriteLine("Result: {0}", logResult.ResultState.ToString());

    Debug.WriteLine(ex);
}

In a future post I hope to describe logging exceptions for background tasks.