Creating a Custom Logon Script Using PowerShell and WPF

Introduction

In this article, we will walk through a PowerShell script that creates a custom logon window using Windows Presentation Foundation (WPF). This script allows you to display a window with a custom message, an image, and a close button. It also includes a timer that automatically closes the window after a specified time or makes the close button visible after a delay.

Script Breakdown

Let’s break down the script into its major components and explain the purpose of each section.

1. Parameters

Param(
    [string]$ArgMes = "Line1`nLine2",
    [INT]$ArgTime = 0,
    [INT]$CloseTime = 120,
    [string]$ArgMesWindow = "Logon script",
    [INT]$ArgButton = 1
)

Explanation: The script begins with a Param block that defines several parameters:

  • $ArgMes: The message to display in the window. It can include multiple lines separated by \n.
  • $ArgTime: The time in seconds after which the window should close automatically.
  • $CloseTime: The time in seconds after which the close button becomes visible.
  • $ArgMesWindow: The title of the window.
  • $ArgButton: A parameter to control button behavior, though in this script it’s not used extensively.

2. Loading WPF Assembly

[void][System.Reflection.Assembly]::Load('PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35')

Explanation: This line loads the WPF assembly, which is necessary to create and display a WPF window in PowerShell. Without this, the script wouldn’t be able to use WPF elements.

3. Defining the XAML for the Window

[xml]$XAML = @'
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PleaseWaitLogon"       
        WindowStyle="None"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen"
        AllowsTransparency="True"
        Opacity="0.8">
    <!-- XAML content here -->
</Window>
'@

Explanation: This section defines the layout of the window using XAML (Extensible Application Markup Language). Key features include:

  • WindowStyle="None": Removes the standard window frame.
  • ResizeMode="NoResize": Disables resizing.
  • WindowStartupLocation="CenterScreen": Centers the window on the screen.
  • AllowsTransparency="True" and Opacity="0.8": Makes the window slightly transparent.

4. Reading and Parsing XAML

$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
try{$Form=[Windows.Markup.XamlReader]::Load($reader)}
catch{Write-Host "Unable to load Windows.Markup.XamlReader."; exit}

Explanation: The XAML is parsed into a WPF window object ($Form). This object can now be manipulated within the script.

5. Storing Form Objects

$xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)}

Explanation: This code retrieves all the named elements in the XAML and creates corresponding PowerShell variables for them. For example, if the XAML contains a button with Name="CloseButton", a PowerShell variable $CloseButton is created.

6. Configuring Window Size and Position

$desiredWidth = [System.Windows.SystemParameters]::PrimaryScreenWidth * 0.99
$desiredHeight = [System.Windows.SystemParameters]::PrimaryScreenHeight * 0.90
$Form.Width = $desiredWidth
$Form.Height = $desiredHeight

Explanation: The script calculates the window size to be 99% of the screen width and 90% of the screen height. This ensures the window is large but not fullscreen.

7. Loading and Setting the Image

$Image_logo = ""
$bitmap_Logo = New-Object System.Windows.Media.Imaging.BitmapImage
$bitmap_Logo.BeginInit()
$bitmap_Logo.StreamSource = [System.IO.MemoryStream][System.Convert]::FromBase64String($Image_logo)
$bitmap_Logo.EndInit()
$bitmap_Logo.Freeze()

$logo.source = $bitmap_Logo

Explanation: This part decodes a base64-encoded image and sets it as the source for the image element in the window.

8. Setting the Window Title and Message

$Form.Title = $ArgMesWindow
$Titre.Content = $ArgMesWindow

$Messages = $ArgMes.Split("`n")
if ($Messages.Count -gt 0) { $Message1.Content = $Messages[0] }
if ($Messages.Count -gt 1) { $Message2.Content = $Messages[1] }
if ($Messages.Count -gt 2) { $Message3.Content = $Messages[2] }

Explanation: The title and content of the labels in the window are set based on the parameters passed to the script. The message can be split into multiple lines and displayed on separate labels.

9. Setting Up the DispatcherTimer

$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [TimeSpan]::FromSeconds($ArgTime)
$timer.Add_Tick({
    $Form.Close()
    $timer.Stop()
})

if ($ArgTime -ne 0) {
    $timer.Start()
}

Explanation: A DispatcherTimer is set up to close the window after a specified time ($ArgTime). If $ArgTime is 0, the timer is not started.

10. Making the Close Button Visible After a Delay

$showButtonTimer = New-Object System.Windows.Threading.DispatcherTimer
$showButtonTimer.Interval = [TimeSpan]::FromSeconds($CloseTime)

$showButtonTimer.Add_Tick({
    $Form.Dispatcher.Invoke([Action]{
        $CloseButton.Visibility = 'Visible'
    })
    $showButtonTimer.Stop()
})
$showButtonTimer.Start()

Explanation: Another DispatcherTimer is used to make the close button visible after $CloseTime seconds. This ensures that the user cannot close the window immediately, which might be useful in some logon scenarios.

11. Handling Window Closing Event

$Form.Add_Closing({
    param($sender, $e)

    if (-not $CloseRequested) {
        $e.Cancel = $true
    }
})

Explanation: This event handler ensures that the window cannot be closed unless the close button is clicked ($CloseRequested = $true). This is useful if you want to prevent the user from closing the window using other methods.

12. Displaying the Modal Window

$Form.ShowDialog()

Explanation: Finally, the window is displayed as a modal dialog, meaning it will stay on top and block interaction with other windows until it is closed.

https://github.com/DavidWuibaille/Tools/tree/main/logonscreen


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.