Bart Simons

scripting

A 2 post collection


Create GUI windows with PowerShell and XAML

 •  Filed under powershell, gui, xaml, scripting

GUI windows bring modern ways of interaction to your application and that is simply great: daily used applications like web browsers and e-mail client are all part of it. PowerShell has been proven to be great for automating tasks, but don't you sometimes want to bring GUI interaction to your script?

Visual Studio has great built-in functionality to design and create XAML layouts for your application:

XAML Designer in VS

The workflow is easy: just fill your form with items from the toolbox and copy all the XML code inside the XAML text editor. Start with a new PowerShell file,

Start with a new PowerShell file, and start with pasting the XML inside an PowerShell XML object like this:

[xml]$XAMLMain = @'
<Window  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Demo application" Height="350" Width="525">
        <Grid>
            <Label x:Name="label" Content="PowerShell + XAML demo application." HorizontalAlignment="Center" Margin="38,10,37.4,0" VerticalAlignment="Top" RenderTransformOrigin="1.056,1.635" Cursor="" FontSize="24" FontWeight="Bold"/>
            <Border BorderBrush="Black" BorderThickness="1" Height="238" Margin="20,57,20,0" VerticalAlignment="Top"/>
        </Grid>
</Window>  
'@  

The code copied from Visual Studio also contains the following:

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
xmlns:local="clr-namespace:WpfApplication2"  
mc:Ignorable="d"  

One can strip these tags out of the copied code safely, the script won't run with this code included, so that's why this is necessary.

Next up is creating the code that launches the form. Append the following code to the end of the PowerShell file:

$reader=(New-Object System.Xml.XmlNodeReader $XAMLMain)
$windowMain=[Windows.Markup.XamlReader]::Load( $reader )

$windowMain.ShowDialog() | out-null

Run the code, and you should be presented with a form like this:

Result

Can PowerShell replace your old batch installation scripts?

 •  Filed under powershell, batch, automation, scripting, windows

PowerShell can be a very useful scripting language for specific tasks. Back in the old days batch scripts were the way to go for software deployment automation, often shipped with other executables to extend functionality. PowerShell adds tons of available features in one package by Microsoft, which was not possible with just a single bash script. My goal was to create a script that automates the deployment of Git for Windows, with features like architecture detection and more.

The plan

A great project always starts with a great plan, so here is a feature list that I have written and used for the development process of the script:

  • 32/64-bit detection;
  • Install path in the current user's PATH-variable;
  • Download the latest version of Git for Windows and VLC;
  • Remove any left over files automatically

Fetching installation files at runtime

Another great thing about PowerShell is that it perfectly integrates with the .NET framework. For example, you can create new .NET objects with the New-Object function. Here's a working example to download a file from the internet to your computer:

<# Simple download script demonstration #>

$SystemDrive = $env:SystemDrive
$downloadFile = "http://get.videolan.org/vlc/2.2.3/win32/vlc-2.2.3-win32.exe";
$destinationFile = "$SystemDrive\Users\Bart\Desktop\vlc-x86.exe";

(New-Object System.Net.WebClient).DownloadFile($downloadFile, $destinationFile);

There are also different ways of downloading files in PowerShell, but this is the fastest way of getting the job done. The minimal PowerShell version required to run this script is version 2. An alternative way of downloading files, called Invoke-WebRequest was introduced in PowerShell version 3 and that explains why this command didn't work on a Windows 7 install.

Architecture detection

Most software vendors supply their applications as a 32-bit and 64-bit version, and since PowerShell is able to work with WMI, you can just obtain the needed information from the Win32_OperatingSystem WMI class. Here's a code snippet to check the OS architecture:

<# Simple script to detect OS architecture #>

$OSArch = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
If ($OSArch -eq "64-bit") {  
    Write-Host "OS is 64-bit!";
} ElseIf ($OSArch -eq "32-bit") {
    Write-Host "OS is 32-bit!";
}

You can replace the code located within the If statements with your own code.

Running software installers

Powershell can start processes for you with the needed arguments, wait for the process to complete and then it can delete the installer file for you. The PowerShell functions needed for this are Start-Process and Remove-Item. Here's an example:

<# Simple script to start the installation + cleanup afterwards #>

$SystemDrive = $env:SystemDrive
Start-Process "$SystemDrive\Users\Bart\Desktop\vlc-x86" -ArgumentList "/L=1033 /S" -Wait  
Remove-Item "$SystemDrive\Users\Bart\Desktop\vlc-x86.exe"  

Append directory to PATH variable

Appending the installation directory requires a little bit more programming work and knowledge. Here is an example script for you that appends the VLC installation path to your current user's PATH-variable:

<# Simple script to append the current user's path variable #>

$SystemDrive = $env:SystemDrive
$VLCPath = "C:\Program Files";

Try {  
    $Path = (Get-ItemProperty -Path 'HKCU:\Environment' -Name PATH -ErrorAction Stop).PATH
    If ($Path -ne "") {
        $NewPath = "$Path;$SystemDrive\Program Files\VideoLAN\VLC";
    } Else {
        $NewPath = "$SystemDrive\Program Files\VideoLAN\VLC";
    }
    Set-ItemProperty -Path 'HKCU:\Environment' -Name PATH -Value $NewPath
} Catch {
    If ($_.Exception.Message -like "Property PATH does not exist at path HKEY_CURRENT_USER\Environment.*") {
        New-ItemProperty -Path 'HKCU:\Environment' -Name PATH
        $NewPath = "$SystemDrive\Program Files\VideoLAN\VLC";
        Set-ItemProperty -Path 'HKCU:\Environment' -Name PATH -Value $NewPath
    } Else {
        Write-Host "Unknown error.";
    }
}

As you can see, this script works with the registry. At first, the script tries to obtain information from the HKEY_CURRENT_USER\Environment\PATH item which does not exist by default, which results in an error catched by the Catch handler that creates the needed registry entry for you automatically.

The full script

Here is the full script for installing VLC Player:

<# Install-VLC.ps1 - An automated installation script for the VLC Player #>  
<# Made by Bart Simons - https://bartsimons.me #>  
$SystemDrive = $env:SystemDrive
$User = [Environment]::UserName
$destinationFile = "$SystemDrive\Users\$User\Desktop\vlc.exe";

$OSArch = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
If ($OSArch -eq "64-bit") {  
    $downloadFile = "http://get.videolan.org/vlc/2.2.3/win64/vlc-2.2.3-win64.exe";

} ElseIf ($OSArch -eq "32-bit") {
    $downloadFile = "http://get.videolan.org/vlc/2.2.3/win32/vlc-2.2.3-win32.exe"
}

(New-Object System.Net.WebClient).DownloadFile($downloadFile, $destinationFile);

Start-Process "$SystemDrive\Users\$User\Desktop\vlc.exe" -ArgumentList "/L=1033 /S" -Wait  
Remove-Item "$SystemDrive\Users\$User\Desktop\vlc.exe"  


Here is the full script for deploying Git for Windows:

<# Deploy-Git.ps1 - An automated deployment script for Git #>  
<# Made by Bart Simons - https://bartsimons.me #>  
$SystemDrive = $env:SystemDrive
$User = [Environment]::UserName
$destinationFile = "$SystemDrive\Users\$User\Desktop\git.exe";

$OSArch = (Get-WmiObject Win32_OperatingSystem).OSArchitecture
If ($OSArch -eq "64-bit") {  
    $downloadFile = "https://github.com/git-for-windows/git/releases/download/v2.8.3.windows.1/PortableGit-2.8.3-64-bit.7z.exe";

} ElseIf ($OSArch -eq "32-bit") {
    $downloadFile = "https://github.com/git-for-windows/git/releases/download/v2.8.3.windows.1/PortableGit-2.8.3-32-bit.7z.exe"
}

(New-Object System.Net.WebClient).DownloadFile($downloadFile, $destinationFile);

Start-Process "$SystemDrive\Users\$User\Desktop\git.exe" -ArgumentList "-y -gm2 -InstallPath=`"$User`"" -Wait  
Remove-Item "$SystemDrive\Users\$User\Desktop\git.exe"  

Try {  
    $Path = (Get-ItemProperty -Path 'HKCU:\Environment' -Name PATH -ErrorAction Stop).PATH
    If ($Path -ne "") {
        $NewPath = "$Path;$SystemDrive\Users\$User\git\bin";
    } Else {
        $NewPath = "$SystemDrive\Users\$User\git\bin";
    }
    Set-ItemProperty -Path 'HKCU:\Environment' -Name PATH -Value $NewPath
} Catch {
    If ($_.Exception.Message -like "Property PATH does not exist at path HKEY_CURRENT_USER\Environment.*") {
        New-ItemProperty -Path 'HKCU:\Environment' -Name PATH
        $NewPath = "$SystemDrive\Users\$User\git\bin";
        Set-ItemProperty -Path 'HKCU:\Environment' -Name PATH -Value $NewPath
    }
}