Skip to content

nosari20/Windows-Desktop-Script-UI

Repository files navigation

Windows Desktop Script UI

License MIT Version alpha

Visual Studio Windows C# .Net Windows App SDK

Screenshot

Full demo video here

Latest release and demo code available here

Presentation

This project aims to offer easy to use and modern UI for Windows desktop devices during setup. You can use it from PowerShell scripts by writing commands in a file wich is watched by the app.

Samples:

Tech

This project is developped with the following libraries:

  • Windows App SDK
  • WinUI 3
  • .NET 6

Prerequisites

Target devices must have the following runtime installed:

Usage

Launch UI

# Launch app
Start-Process -FilePath "./Windows Desktop Script UI.exe" -ArgumentList "--WatchPath=`"commands.txt`" --WindowTitle=`"Hello World!`" --WelcomeMessage=`"Hello Folks`"" -NoNewWindow | Out-Null
  • --WatchPath : path of command file
  • --WindowTitle : title of widow (optional)
  • --WelcomeMessage : main text (optional)
  • --Height : window height (optional)
  • --Width : window width (optional)
  • -FullScreen : fullscreen flag (optional)
  • -AlwaysOnTop : always on top flag (optional)
  • -Debug : debug flag (optional)

Note: if you are running in system context you must launch it in user context (with KelvinTegelaar/RunAsUser or Microsoft deployment toolkit ServiceUI.exe for example)

Manipulate UI

The app listen to commands written in a file, you just have to write your own function to write to the command file.

# Define file path
$FILE = "demo.txt"

# Remove file if already exist
if (Test-Path $FILE) {
    Remove-Item $FILE | Out-Null
}

# Create file
New-Item $FILE | Out-Null

## Create writting function for clearer code
function UI {
    param(
        [Parameter(Position=0)]
        [string] $command
    )

    Write-Host($command)
    $command | out-file -append $FILE
}

Close window

UI "Terminate"

Main text

UI "MainText --Text='Hello John'"
  • --Text : text to display

Sub text

UI "SubText --Text='We are setting up BitLocker to protect your data.'"
  • --Text : text to display

Main image

UI "MainImage --Source='$PSScriptRoot/Windows_logo.png' --Height=200 -Width=200"
  • --Source : image source
  • --Height : image height (optional)
  • --Width : image width (optional)

Progress

UI "Load --Text='Please wait..'"
  • --Text : text behind progresss ring (optional, use \n for line break)
  • -Hide : hide progress ring (optional)

Input

   UI "Input --Type=Password --PlaceHolder='Florent NOSARI' --Header='Type BitLocker password' --Button=OK --Out=input.txt"
  • --Type : input type (see details below)
  • --PlaceHolder : placeholder for supported types (optional)
  • --Value : default value for supported types(optional)
  • --AllwowedValues : allowed values for supported types (optional)
  • --Header : header for supported types (optional)
  • --Button : submit button text (optional)
  • --Out : file path where user input is store after submit (optional)
  • --Height : input height (optional)
  • --Width : input width (optional)

User input is stored in a file (file is empty if value is not provided on input is simple button), you have to wait for file change before continuig you script, here is a short example.

## Function towait for file change
function Wait-FileChange {
    param(
        [string]$File
    )
    $FilePath = Split-Path $File -Parent
    $FileName = Split-Path $File -Leaf

    $global:FileChanged = $false

    $Watcher = New-Object IO.FileSystemWatcher $FilePath, $FileName -Property @{ 
        IncludeSubdirectories = $false
        EnableRaisingEvents = $true
    }
    
    Unregister-Event -SourceIdentifier "filechanged" -ErrorAction SilentlyContinue

    Register-ObjectEvent $Watcher Changed -Action {$global:FileChanged = $true} -SourceIdentifier "filechanged" | Out-Null

    while ($global:FileChanged -eq $false){
        Start-Sleep -Milliseconds 100
    }

    Unregister-Event -SourceIdentifier "filechanged"
}

....

# Define file path
$INPUTFILE = "./out"

# Request input
UI "Input --Type=Password --Header='Type BitLocker password' --Button=OK --Out=$INPUTFILE"

# Wait for file to be created
Wait-FileChange -File $INPUTFILE

## Get content
$PIN = $(Get-Content -Path $INPUTFILE)

# Remove file
Remove-Item $INPUTFILE

The following input types are supported:

Type Description WINUI 3 Object Supported options
Text Basic text field TextBox Header
PlaceHolder
Value
Password Password text field PasswordBox Header
ComboBox Predefined value selector ComboBox Header
AllowedValues (separated by "|")
Value (represent the default value)
ImageChooser Grid with images as available values GridView Header
AllowedValues (separated by "|")
ButtonImage Button with image to display Image
ButtonVideo Button with video MediaPlayerElement Autoplay
ShowControl
SoundOn
ButtonText Button with rich text RichTextBlock
# Text
UI "Input --Type=Text --Header='Enter value' --Button=OK --Out=$INPUTFILE"

# Password
UI "Input --Type=Password --Header='Enter password' --Button=OK --Out=$INPUTFILE"

# ComboBox
UI "Input --Type=ComboBox --Header='Select option' --AllowedValues='One|Two|Three' --Value='Two' --Button=OK --Out=$INPUTFILE"

# ImageChooser
UI "Input --Type=ImageChooser --Header='Select option' --AllowedValues='$PSScriptRoot/One.png|$PSScriptRoot/Two.png|$PSScriptRoot/Three.png' --Button=OK --Out=$INPUTFILE"

# ButtonImage
UI "Input --Type=ButtonImage --Value='$PSScriptRoot/Image.png' --Button='Next' --Out=$INPUTFILE"

# ButtonVideo
UI "Input --Type=ButtonImage --Value='$PSScriptRoot/Video.mp4' --Button='Next' --Out=$INPUTFILE"

# ButtonText
$content="<Paragraph>Lorem ipsum dolor sit amet.</Paragraph>" # be aware of " and ' interpretation
UI "Input --Type=ButtonImage --Value='$content' --Button='Accept' --Out=$INPUTFILE"

ButtonText value must be valid XAML wich can be included in RichTextBlock (See documentation). Find an example below:

<Paragraph TextAlignment="Center">
    <InlineUIContainer>
        <Image 
            Source="C:\temp\contoso.png"
            Width="100"/>
    </InlineUIContainer>
</Paragraph>
<Paragraph>
    Lorem ipsum dolor sit amet, consectetur
    adipiscing elit. Duis sit amet nisi eget ex gravida molestie. Nulla varius leo at nulla
    molestie, sit amet ultricies nisi efficitur. Proin non massa eros. Fusce convallis maximus risus
    ac aliquam. Fusce non tempus orci, at dignissim velit. Nulla at sollicitudin arcu. Proin arcu
    mi, gravida at suscipit a, gravida eu lorem. Nulla commodo, mi sit amet tincidunt pharetra,
    justo ipsum malesuada mi, eget malesuada est elit at ipsum.
</Paragraph>
<Paragraph>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sit amet nisi eget ex
    gravida molestie. Nulla varius leo at nulla molestie, sit amet ultricies nisi efficitur. Proin
    non massa eros. Fusce convallis maximus risus ac aliquam. Fusce non tempus orci, at dignissim
    velit. Nulla at sollicitudin arcu. Proin arcu mi, gravida at suscipit a, gravida eu lorem. Nulla
    commodo, mi sit amet tincidunt pharetra, justo ipsum malesuada mi, eget malesuada est elit at
    ipsum.
</Paragraph>

Sample code

$FILE = "demo.txt"

# Remove file if already exist
if (Test-Path $FILE) {
    Remove-Item $FILE | Out-Null
}

# Create file
New-Item $FILE | Out-Null

function UI {
    param(
        [Parameter(Position=0)]
        [string] $command
    )

    Write-Host($command)
    $command | out-file -append $FILE
}

function Wait-FileChange {
    param(
        [string]$File
    )
    $FilePath = Split-Path $File -Parent
    $FileName = Split-Path $File -Leaf

    $global:FileChanged = $false

    $Watcher = New-Object IO.FileSystemWatcher $FilePath, $FileName -Property @{ 
        IncludeSubdirectories = $false
        EnableRaisingEvents = $true
    }
    
    Unregister-Event -SourceIdentifier "filechanged" -ErrorAction SilentlyContinue

    Register-ObjectEvent $Watcher Changed -Action {$global:FileChanged = $true} -SourceIdentifier "filechanged" | Out-Null

    while ($global:FileChanged -eq $false){
        Start-Sleep -Milliseconds 100
    }

    Unregister-Event -SourceIdentifier "filechanged"
}

# Define input file
$INPUTFILE = "$PSScriptRoot/out"



################################################################################
############################### UI Launch ######################################
################################################################################

# Launch app
Start-Process -FilePath "./UI/Windows Desktop Script UI.exe" -ArgumentList "--WatchPath=`"$PSScriptRoot/$FILE`" --WindowTitle=`"Hello World!`" --WelcomeMessage=`"`" -AlwaysOnTop -FullScreen -Debug" -NoNewWindow | Out-Null


################################################################################
############################### Startup UI #####################################
################################################################################

UI "MainText --Text=`"Hello $($env:UserName)`""
UI "MainImage --Source=`"$PSScriptRoot/windows.png`" --Height=150"
UI "SubText --Text=`"Welcome to Windows, let's setup your device.`""
UI "Input --Type=ButtonVideo --Value=`"$PSScriptRoot/Windows11.mp4`" --Button=`"Continue`" --Height=300 --Width=500 -Autoplay --Out=`"$INPUTFILE`""
Wait-FileChange -File $INPUTFILE

################################################################################
############################### Reboot #########################################
################################################################################
UI "MainText --Text=`"Finalization"
UI "MainImage --Source=`"$PSScriptRoot/restart.png`" --Height=150"
UI "SubText --Text=`"Your device is ready to go but needs a restart, please wait.`""
UI "Load --Type='Waiting for reboot...'"

Start-Sleep -Seconds  3
UI "Terminate"

Todo

  • Window name
  • Window icon
  • User picture
  • Main text
  • Sub text
  • Sub image
  • ProgressBar inderterminate
  • ProgressBar derterminate
  • ProgressBar derterminate percentage
  • ProgressBar hide
  • Info Bar
  • Input text
  • Input password
  • Input button (use submit button)
  • Input combobox
  • Input image chooser
  • Input text
  • Input image
  • Input video
  • Input toggle switch
  • Input FlipView
  • Input WebView
  • Input FilePicker

Scenarios ideas

  • BitLocker PIN
  • Dark/light mode chooser
  • Prefered wallpaper
  • Theme color
  • Application installation (if user input is needed)

Contribute

The following tool are required to edit:

  • Visual Studio with Windows App SDK components (instructions)

Inspiration

This project was inspired by Mactroll/DEPNotify (macOS)

About

Simple Script UI inspired by Joel Rennich's DEPNotify

Resources

License

Stars

Watchers

Forks

Packages

No packages published