Project/MainWindow.ps1

# PoSHPF - Version 1.2
# Grab all resources (MahApps, etc), all XAML files, and any potential static resources
$Global:resources = Get-ChildItem -Path "$PSScriptRoot\Resources\*.dll" -ErrorAction SilentlyContinue
$Global:XAML = Get-ChildItem -Path "$PSScriptRoot\*.xaml" | Where-Object {$_.Name -ne 'App.xaml'} -ErrorAction SilentlyContinue #Changed path and exclude App.xaml
$Global:MediaResources = Get-ChildItem -Path "$PSScriptRoot\Media" -ErrorAction SilentlyContinue

# This class allows the synchronized hashtable to be available across threads,
# but also passes a couple of methods along with it to do GUI things via the
# object's dispatcher.
class SyncClass 
{
    #Hashtable containing all forms/windows and controls - automatically created when newing up
    [hashtable]$SyncHash = [hashtable]::Synchronized(@{}) 
    
    # method to close the window - pass window name
    [void]CloseWindow($windowName){ 
        $this.SyncHash.$windowName.Dispatcher.Invoke([action]{$this.SyncHash.$windowName.Close()},"Normal") 
    }
    
    # method to update GUI - pass object name, property and value
    [void]UpdateElement($object,$property,$value){ 
        $this.SyncHash.$object.Dispatcher.Invoke([action]{ $this.SyncHash.$object.$property = $value },"Normal") 
    } 
}
$Global:SyncClass = [SyncClass]::new() # create a new instance of this SyncClass to use.

###################
## Import Resources
###################
# Load WPF Assembly
Add-Type -assemblyName PresentationFramework

# Load Resources
foreach($dll in $resources) { [System.Reflection.Assembly]::LoadFrom("$($dll.FullName)") | out-null }

##############
## Import XAML
##############
$xp = '[^a-zA-Z_0-9]' # All characters that are not a-Z, 0-9, or _
$vx = @()             # An array of XAML files loaded

foreach($x in $XAML) { 
    # Items from XAML that are known to cause issues
    # when PowerShell parses them.
    $xamlToRemove = @(
        'mc:Ignorable="d"',
        "x:Class=`"(.*?)`"",
        "xmlns:local=`"(.*?)`""
    )

    $xaml = Get-Content $x.FullName # Load XAML
    $xaml = $xaml -replace "x:N",'N' # Rename x:Name to just Name (for consumption in variables later)
    foreach($xtr in $xamlToRemove){ $xaml = $xaml -replace $xtr } # Remove items from $xamlToRemove
    
    # Create a new variable to store the XAML as XML
    New-Variable -Name "xaml$(($x.BaseName) -replace $xp, '_')" -Value ($xaml -as [xml]) -Force
    
    # Add XAML to list of XAML documents processed
    $vx += "$(($x.BaseName) -replace $xp, '_')"
}
#######################
## Add Media Resources
#######################
$imageFileTypes = @(".jpg",".bmp",".gif",".tif",".png") # Supported image filetypes
$avFileTypes = @(".mp3",".wav",".wmv") # Supported audio/visual filetypes
$xp = '[^a-zA-Z_0-9]' # All characters that are not a-Z, 0-9, or _
if($MediaResources.Count -gt 0){
    ## Okay... the following code is just silly. I know
    ## but hear me out. Adding the nodes to the elements
    ## directly caused big issues - mainly surrounding the
    ## "x:" namespace identifiers. This is a hacky fix but
    ## it does the trick.
    foreach($v in $vx)
    {
        $xml = ((Get-Variable -Name "xaml$($v)").Value) # Load the XML

        # add the resources needed for strings
        $xml.DocumentElement.SetAttribute("xmlns:sys","clr-namespace:System;assembly=System")

        # if the document doesn't already have a "Window.Resources" create it
        if($null -eq ($xml.DocumentElement.'Window.Resources')){ 
            $fragment = "<Window.Resources>" 
            $fragment += "<ResourceDictionary>"
        }
        
        # Add each StaticResource with the key of the base name and source to the full name
        foreach($sr in $MediaResources)
        {
            $srname = "$($sr.BaseName -replace $xp, '_')$($sr.Extension.Substring(1).ToUpper())" #convert name to basename + Uppercase Extension
            if($sr.Extension -in $imageFileTypes){ $fragment += "<BitmapImage x:Key=`"$srname`" UriSource=`"$($sr.FullName)`" />" }
            if($sr.Extension -in $avFileTypes){ 
                $uri = [System.Uri]::new($sr.FullName)
                $fragment += "<sys:Uri x:Key=`"$srname`">$uri</sys:Uri>" 
            }    
        }

        # if the document doesn't already have a "Window.Resources" close it
        if($null -eq ($xml.DocumentElement.'Window.Resources'))
        {
            $fragment += "</ResourceDictionary>"
            $fragment += "</Window.Resources>"
            $xml.DocumentElement.InnerXml = $fragment + $xml.DocumentElement.InnerXml
        }
        # otherwise just add the fragment to the existing resource dictionary
        else
        {
            $xml.DocumentElement.'Window.Resources'.ResourceDictionary.InnerXml += $fragment
        }

        # Reset the value of the variable
        (Get-Variable -Name "xaml$($v)").Value = $xml
    }
}
#################
## Create "Forms"
#################
$forms = @()
foreach($x in $vx)
{
    $Reader = (New-Object System.Xml.XmlNodeReader ((Get-Variable -Name "xaml$($x)").Value)) #load the xaml we created earlier into XmlNodeReader
    New-Variable -Name "form$($x)" -Value ([Windows.Markup.XamlReader]::Load($Reader)) -Force #load the xaml into XamlReader
    $forms += "form$($x)" #add the form name to our array
    $SyncClass.SyncHash.Add("form$($x)", (Get-Variable -Name "form$($x)").Value) #add the form object to our synched hashtable
}
#################################
## Create Controls (Buttons, etc)
#################################
$controls = @()
$xp = '[^a-zA-Z_0-9]' # All characters that are not a-Z, 0-9, or _
foreach($x in $vx)
{
    $xaml = (Get-Variable -Name "xaml$($x)").Value #load the xaml we created earlier
    $xaml.SelectNodes("//*[@Name]") | %{ #find all nodes with a "Name" attribute
        $cname = "form$($x)Control$(($_.Name -replace $xp, '_'))"
        Set-Variable -Name "$cname" -Value $SyncClass.SyncHash."form$($x)".FindName($_.Name) #create a variale to hold the control/object
        $controls += (Get-Variable -Name "form$($x)Control$($_.Name)").Name #add the control name to our array
        $SyncClass.SyncHash.Add($cname, $SyncClass.SyncHash."form$($x)".FindName($_.Name)) #add the control directly to the hashtable
    }
}
############################
## FORMS AND CONTROLS OUTPUT
############################
<# Write-Host -ForegroundColor Cyan "The following forms were created:"
$forms | %{ Write-Host -ForegroundColor Yellow " `$$_"} #output all forms to screen
if($controls.Count -gt 0){
    Write-Host ""
    Write-Host -ForegroundColor Cyan "The following controls were created:"
    $controls | %{ Write-Host -ForegroundColor Yellow " `$$_"} #output all named controls to screen
} #>

#######################
## DISABLE A/V AUTOPLAY
#######################
foreach($x in $vx)
{
    $carray = @()
    $fts = $syncClass.SyncHash."form$($x)"
    foreach($c in $fts.Content.Children)
    {
        if($c.GetType().Name -eq "MediaElement") #find all controls with the type MediaElement
        {
            $c.LoadedBehavior = "Manual" #Don't autoplay
            $c.UnloadedBehavior = "Stop" #When the window closes, stop the music
            $carray += $c #add the control to an array
        }
    }
    if($carray.Count -gt 0)
    {
        New-Variable -Name "form$($x)PoSHPFCleanupAudio" -Value $carray -Force # Store the controls in an array to be accessed later
        $syncClass.SyncHash."form$($x)".Add_Closed({
            foreach($c in (Get-Variable "form$($x)PoSHPFCleanupAudio").Value)
            {
                $c.Source = $null #stops any currently playing media
            }
        })
    }
}

#####################
## RUNSPACE FUNCTIONS
#####################
## Yo dawg... Runspace to clean up Runspaces
## Thank you Boe Prox / Stephen Owen
#region RSCleanup
$Script:JobCleanup = [hashtable]::Synchronized(@{}) 
$Script:Jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList)) #hashtable to store all these runspaces
$jobCleanup.Flag = $True #cleanup jobs
$newRunspace =[runspacefactory]::CreateRunspace() #create a new runspace for this job to cleanup jobs to live
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("jobCleanup",$jobCleanup) #pass the jobCleanup variable to the runspace
$newRunspace.SessionStateProxy.SetVariable("jobs",$jobs) #pass the jobs variable to the runspace
$jobCleanup.PowerShell = [PowerShell]::Create().AddScript({
    #Routine to handle completed runspaces
    Do {    
        Foreach($runspace in $jobs) {            
            If ($runspace.Runspace.isCompleted) {                         #if runspace is complete
                [void]$runspace.powershell.EndInvoke($runspace.Runspace)  #then end the script
                $runspace.powershell.dispose()                            #dispose of the memory
                $runspace.Runspace = $null                                #additional garbage collection
                $runspace.powershell = $null                              #additional garbage collection
            } 
        }
        #Clean out unused runspace jobs
        $temphash = $jobs.clone()
        $temphash | Where {
            $_.runspace -eq $Null
        } | ForEach {
            $jobs.remove($_)
        }        
        Start-Sleep -Seconds 1 #lets not kill the processor here
    } while ($jobCleanup.Flag)
})
$jobCleanup.PowerShell.Runspace = $newRunspace
$jobCleanup.Thread = $jobCleanup.PowerShell.BeginInvoke() 
#endregion RSCleanup

#This function creates a new runspace for a script block to execute
#so that you can do your long running tasks not in the UI thread.
#Also the SyncClass is passed to this runspace so you can do UI
#updates from this thread as well.
function Start-BackgroundScriptBlock($scriptBlock){
    $newRunspace =[runspacefactory]::CreateRunspace()
    $newRunspace.ApartmentState = "STA"
    $newRunspace.ThreadOptions = "ReuseThread"          
    $newRunspace.Open()
    $newRunspace.SessionStateProxy.SetVariable("SyncClass",$SyncClass) 
    $PowerShell = [PowerShell]::Create().AddScript($scriptBlock)
    $PowerShell.Runspace = $newRunspace
    $PowerShell.BeginInvoke()

    #Add it to the job list so that we can make sure it is cleaned up
<# [void]$Jobs.Add(
        [pscustomobject]@{
            PowerShell = $PowerShell
            Runspace = $PowerShell.BeginInvoke()
        }
    ) #>

}
#================================================
# Customizations
#================================================
[string]$ModuleVersion = Get-Module -Name AutopilotOOBE | Sort-Object -Property Version | Select-Object -ExpandProperty Version -Last 1
#================================================
# Window Functions
# Minimize Command and PowerShell Windows
#================================================
$Script:showWindowAsync = Add-Type -MemberDefinition @"
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
"@
 -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru
function Hide-CmdWindow() {
    $CMDProcess = Get-Process -Name cmd -ErrorAction Ignore
    foreach ($Item in $CMDProcess) {
        $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $Item.id).MainWindowHandle, 2)
    }
}
function Hide-PowershellWindow() {
    $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 2)
}
function Show-PowershellWindow() {
    $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 10)
}
#================================================
# Sidebar
#================================================
if (Test-WebConnection) {
    $formMainWindowControlOnlineStatusLabel.Background = 'Green'
}
else {
    $formMainWindowControlOnlineStatusLabel.Background = 'Red'
}

try {
    $Tpm = (Get-CimInstance -Namespace "root\CIMV2\Security\MicrosoftTPM" -ClassName Win32_Tpm).SpecVersion
}
catch {}

if ($Tpm -match '2.0') {
    $formMainWindowControlTpmVersionLabel.Content = "TPM: 2.0"
    $formMainWindowControlTpmVersionLabel.Background = "Green"
}
elseif ($Tpm -match '1.2') {
    $formMainWindowControlTpmVersionLabel.Content = "TPM: 1.2"
    $formMainWindowControlTpmVersionLabel.Background = "Red"
}
else {
    $formMainWindowControlTpmVersionLabel.Content = "TPM"
    $formMainWindowControlTpmVersionLabel.Background = "Red"
    #$formMainWindowControlTpmVersionLabel.Visibility = "Collapsed"
}

$formMainWindowControlCSManufacturerControl.Content = ((Get-CimInstance -ClassName CIM_ComputerSystem).Manufacturer).Trim()

if ($formMainWindowControlCSManufacturerControl.Content -match 'Lenovo') {
    $formMainWindowControlCSModelControl.Content = ((Get-CimInstance -ClassName Win32_ComputerSystemProduct).Version).Trim()
}
else {
    $formMainWindowControlCSModelControl.Content = ((Get-CimInstance -ClassName CIM_ComputerSystem).Model).Trim()
}

$SerialNumber = ((Get-CimInstance -ClassName Win32_BIOS).SerialNumber).Trim()
$formMainWindowControlSerialNumberLabel.Content = $SerialNumber

$BiosVersion = ((Get-CimInstance -ClassName Win32_BIOS).SMBIOSBIOSVersion).Trim()
$formMainWindowControlBiosVersionLabel.Content = "BIOS $BiosVersion"
#================================================
# Parameters
#================================================
$AutopilotOOBEParams = (Get-Command Start-AutopilotOOBE).Parameters
#================================================
# Heading
#================================================
$formMainWindowControlHeading.Content = $Global:AutopilotOOBE.Title
#================================================
# SubHeading
#================================================
$Global:GetRegCurrentVersion = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'

$SubTitleProductName = ($Global:GetRegCurrentVersion).ProductName

if ($Global:GetRegCurrentVersion.DisplayVersion -gt 0) {
    $SubTitleDisplayVersion = ($Global:GetRegCurrentVersion).DisplayVersion
}
else {
    $SubTitleDisplayVersion = ($Global:GetRegCurrentVersion).ReleaseId
}

$SubTitleBuildNumber = "$($Global:GetRegCurrentVersion.CurrentBuild).$($Global:GetRegCurrentVersion.UBR)"

$formMainWindowControlSubHeading.Content = "$SubTitleProductName $SubTitleDisplayVersion ($SubTitleBuildNumber)"
#================================================
# GroupTag Control
#================================================
# Disable the Control
if ($Disabled -contains 'GroupTag') {
    $formMainWindowControlGroupTagComboBox.IsEnabled = $false
}

# Hide the Control
if ($Hidden -contains 'GroupTag') {
    $formMainWindowControlGroupTagStackPanel.Visibility = 'Collapsed'
}

# Populate the ComboBox
$Global:AutopilotOOBE.GroupTagOptions | ForEach-Object {
    $formMainWindowControlGroupTagComboBox.Items.Add($_) | Out-Null
}

# Set the ComboBox Default
if ($Global:AutopilotOOBE.GroupTag) {
    $formMainWindowControlGroupTagComboBox.Text = $Global:AutopilotOOBE.GroupTag
}
#================================================
# AddToGroup Control
#================================================
# Disable the Control
if ($Disabled -contains 'AddToGroup') {
    $formMainWindowControlAddToGroupComboBox.IsEnabled = $false
}

# Hide the Control
if ($Hidden -contains 'AddToGroup') {
    $formMainWindowControlAddToGroupStackPanel.Visibility = 'Collapsed'
}

# Populate the Control
$Global:AutopilotOOBE.AddToGroupOptions | ForEach-Object {
    $formMainWindowControlAddToGroupComboBox.Items.Add($_) | Out-Null
}

# Set the Default
if ($Global:AutopilotOOBE.AddToGroup) {
    $formMainWindowControlAddToGroupComboBox.Text = $Global:AutopilotOOBE.AddToGroup
}
#================================================
# AssignedUser Control
#================================================
# Disable the Control
if ($Disabled -contains 'AssignedUser') {
    $formMainWindowControlAssignedUserTextBox.IsEnabled = $false
}

# Hide the Control
if ($Hidden -contains 'AssignedUser') {
    $formMainWindowControlAssignedUserStackPanel.Visibility = 'Collapsed'
}

# Populate the Control
$formMainWindowControlAssignedUserTextBox.Text = $Global:AutopilotOOBE.AssignedUserExample
if ($Global:AutopilotOOBE.AssignedUser -gt 0) {
    $formMainWindowControlAssignedUserTextBox.Text = $Global:AutopilotOOBE.AssignedUser
}
#================================================
# AssignedComputerName Control
#================================================
# Disable the Control
if ($Disabled -contains 'AssignedComputerName') {
    $formMainWindowControlAssignedComputerNameTextBox.IsEnabled = $false
}

# Hide the Control
if ($Hidden -contains 'AssignedComputerName') {
    $formMainWindowControlAssignedComputerNameStackPanel.Visibility = 'Collapsed'
}

# Populate the Control
$formMainWindowControlAssignedComputerNameTextBox.Text = $Global:AutopilotOOBE.AssignedComputerNameExample
if ($Global:AutopilotOOBE.AssignedComputerName -gt 0) {
    $formMainWindowControlAssignedComputerNameTextBox.Text = $Global:AutopilotOOBE.AssignedComputerName
}
#================================================
# PostAction Control
#================================================
# Disable the Control
if ($Disabled -contains 'PostAction') {$formMainWindowControlPostActionComboBox.IsEnabled = $false}

# Hide the Control
if ($Hidden -contains 'PostAction') {
    $formMainWindowControlPostActionStackPanel.Visibility = 'Collapsed'
}

# Values
$PostActionComboBoxValues = @(
    'Quit',
    'Restart Computer',
    'Shutdown Computer',
    'Sysprep /oobe /quit',
    'Sysprep /oobe /reboot',
    'Sysprep /oobe /shutdown',
    'Sysprep /generalize /oobe /reboot',
    'Sysprep /generalize /oobe /shutdown'
)

# Populate the ComboBox
$PostActionComboBoxValues | ForEach-Object {
    $formMainWindowControlPostActionComboBox.Items.Add($_) | Out-Null
}

# Set the Default
switch ($Global:AutopilotOOBE.PostAction) {
    'Quit'                  {$formMainWindowControlPostActionComboBox.SelectedValue = 'Quit'}
    'Restart'               {$formMainWindowControlPostActionComboBox.SelectedValue = 'Restart Computer'}
    'Shutdown'              {$formMainWindowControlPostActionComboBox.SelectedValue = 'Shutdown Computer'}
    'Sysprep'               {$formMainWindowControlPostActionComboBox.SelectedValue = 'Sysprep /oobe /quit'}
    'SysprepReboot'         {$formMainWindowControlPostActionComboBox.SelectedValue = 'Sysprep /oobe /reboot'}
    'SysprepShutdown'       {$formMainWindowControlPostActionComboBox.SelectedValue = 'Sysprep /oobe /shutdown'}
    'GeneralizeReboot'      {$formMainWindowControlPostActionComboBox.SelectedValue = 'Sysprep /generalize /oobe /reboot'}
    'GeneralizeShutdown'    {$formMainWindowControlPostActionComboBox.SelectedValue = 'Sysprep /generalize /oobe /shutdown'}
    Default                 {$formMainWindowControlPostActionComboBox.SelectedValue = 'Quit'}
}
#================================================
# Assign CheckBox
#================================================
# Disable the Control
if ($Disabled -contains 'Assign') {$formMainWindowControlAssignCheckBox.IsEnabled = $false}

# Hide the Control
if ($Hidden -contains 'Assign') {
    $formMainWindowControlAssignStackPanel.Visibility = 'Collapsed'
}

# Set the Default
if ($Global:AutopilotOOBE.Assign -eq $true) {
    $formMainWindowControlAssignCheckBox.IsChecked = $true
}
#================================================
# Register Control
#================================================
# Hide the Control
if ($Hidden -contains 'Register') {
    $formMainWindowControlRegisterStackPanel.Visibility = 'Collapsed'

    if ($Global:RegAutoPilot.CloudAssignedForcedEnrollment -eq 1) {
        $CloudAssignedForcedEnrollment = 'Yes'
        $formMainWindow.Title = "AutopilotOOBE $ModuleVersion : Quit to OOBE"
    }
    else {
        $CloudAssignedForcedEnrollment = 'No'
        #$formMainWindow.Title = "AutopilotOOBE $ModuleVersion Device Not Registered"
    }

    if ($Global:RegAutoPilot.IsDevicePersonalized -eq 1) {
        $IsDevicePersonalized = 'Yes'
    }
    else {
        $IsDevicePersonalized = 'No'
    }

    if ($Global:RegAutoPilot.CloudAssignedLanguage) {
        $CloudAssignedLanguage = $Global:RegAutoPilot.CloudAssignedLanguage
    }
    else {
        $CloudAssignedLanguage = 'Operating System Default'
    }
    
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 512) -gt 0) {$PatchDownload = 'Yes'} else {$PatchDownload = 'No'}
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 128) -gt 0) {$TPMRequired = 'Yes'} else {$TPMRequired = 'No'}
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 64) -gt 0) {$DeviceAuth = 'Yes'} else {$DeviceAuth = 'No'}
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 32) -gt 0) {$TPMAttestation = 'Yes'} else {$TPMAttestation = 'No'}
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 4) -gt 0) {$SkipExpress = 'Yes'} else {$SkipExpress = 'No'}
    if (($Global:RegAutoPilot.CloudAssignedOobeConfig -band 2) -gt 0) {$DisallowAdmin = 'Yes'} else {$DisallowAdmin = 'No'}

    $formMainWindowControlInformationLabel.Content = @"
    Azure AD Tenant: $($Global:RegAutoPilot.CloudAssignedTenantDomain)
    Azure AD Tenant ID: $($Global:RegAutoPilot.CloudAssignedTenantId)
    MDM ID: $($Global:RegAutoPilot.CloudAssignedMdmId)
    Autopilot Service Correlation ID: $($Global:RegAutoPilot.AutopilotServiceCorrelationId)
 
    AAD Device Auth: $DeviceAuth
    AAD TPM Required: $TPMRequired
    Disallow Admin: $DisallowAdmin
    Enable Patch Download: $PatchDownload
    Forced Enrollment: $CloudAssignedForcedEnrollment
    Is Device Personalized: $IsDevicePersonalized
    Language: $CloudAssignedLanguage
    Skip Express Settings: $SkipExpress
    Telemetry Level: $($Global:RegAutoPilot.CloudAssignedTelemetryLevel)
    TPM Attestation: $TPMAttestation
"@

}
else {
    $formMainWindow.Title = "AutopilotOOBE $ModuleVersion : Register Device"
}
#================================================
# Run Controls
#================================================
# Hide the Control
if ($Hidden -contains 'Run') {
    $formMainWindowControlRunStackPanel.Visibility = 'Collapsed'
}

# Values
$RunComboBoxValues = @(
    'Restart Computer',
    'Shutdown Computer',
    'Command Prompt',
    'PowerShell',
    'PowerShell ISE',
    'Open Event Viewer',
    'Open Windows Explorer',
    'Show Network and Wireless Settings',
    'Show Windows Security',
    'Show Windows Settings',
    'AutopilotDiagnostics',
    'AutopilotDiagnostics Online',
    'MDMDiagnosticsTool -out C:\Temp',
    'MDMDiagnosticsTool -area Autopilot -cab C:\Temp\Autopilot.cab',
    'MDMDiagnosticsTool -area Autopilot;TPM -cab C:\Temp\AutopilotTPM.cab',
    'TPM Get',
    'TPM Clear',
    'TPM Initialize',
    'Sysprep /oobe /quit',
    'Sysprep /oobe /reboot',
    'Sysprep /oobe /shutdown',
    'Sysprep /audit /reboot'
)

# Populate the ComboBox
$RunComboBoxValues | ForEach-Object {
    $formMainWindowControlRunComboBox.Items.Add($_) | Out-Null
}

# Set the ComboBox Default
switch ($Global:AutopilotOOBE.Run) {
    'Restart'                       {$formMainWindowControlRunComboBox.SelectedValue = 'Restart Computer'}
    'Shutdown'                      {$formMainWindowControlRunComboBox.SelectedValue = 'Shutdown Computer'}
    'CommandPrompt'                 {$formMainWindowControlRunComboBox.SelectedValue = 'Command Prompt'}
    'PowerShell'                    {$formMainWindowControlRunComboBox.SelectedValue = 'PowerShell'}
    'PowerShellISE'                 {$formMainWindowControlRunComboBox.SelectedValue = 'PowerShell ISE'}
    'EventViewer'                   {$formMainWindowControlRunComboBox.SelectedValue = 'Open Event Viewer'}
    'NetworkingWireless'            {$formMainWindowControlRunComboBox.SelectedValue = 'Show Network and Wireless Settings'}
    'WindowsExplorer'               {$formMainWindowControlRunComboBox.SelectedValue = 'Open Windows Explorer'}
    'WindowsSettings'               {$formMainWindowControlRunComboBox.SelectedValue = 'Show Windows Settings'}
    'AutopilotDiagnostics'          {$formMainWindowControlRunComboBox.SelectedValue = 'AutopilotDiagnostics'}
    'AutopilotDiagnosticsOnline'    {$formMainWindowControlRunComboBox.SelectedValue = 'AutopilotDiagnostics Online'}
    'MDMDiag'                       {$formMainWindowControlRunComboBox.SelectedValue = 'MDMDiagnosticsTool -out C:\Temp'}
    'MDMDiagAutopilot'              {$formMainWindowControlRunComboBox.SelectedValue = 'MDMDiagnosticsTool -area Autopilot -cab C:\Temp\Autopilot.cab'}
    'MDMDiagAutopilotTPM'           {$formMainWindowControlRunComboBox.SelectedValue = 'MDMDiagnosticsTool -area Autopilot;TPM -cab C:\Temp\AutopilotTPM.cab'}
    'Sysprep'                       {$formMainWindowControlRunComboBox.SelectedValue = 'Sysprep /oobe /quit'}
    'SysprepReboot'                 {$formMainWindowControlRunComboBox.SelectedValue = 'Sysprep /oobe /reboot'}
    'SysprepShutdown'               {$formMainWindowControlRunComboBox.SelectedValue = 'Sysprep /oobe /shutdown'}
    'SysprepAudit'                  {$formMainWindowControlRunComboBox.SelectedValue = 'Sysprep /audit /reboot'}
    Default                         {$formMainWindowControlRunComboBox.SelectedValue = 'PowerShell'}
}

# Add Click
$formMainWindowControlRunButton.add_Click( {
    switch ($formMainWindowControlRunComboBox.SelectedValue) {
        'Restart Computer'                  {Restart-Computer}
        'Shutdown Computer'                 {Stop-Computer}
        'Command Prompt'                    {Start-Process Cmd.exe}
        'PowerShell'                        {Start-Process PowerShell.exe -ArgumentList "-Nologo"}
        'PowerShell ISE'                    {Start-Process PowerShell_ISE.exe}
        'Open Event Viewer'                 {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -Window Minimized',"-Command Invoke-AutopilotOOBEcmd EventViewer"}
        'Open Windows Explorer'             {Start-Process Explorer.exe}
        'Show Network and Wireless Settings'{Start-Process ms-availablenetworks:}
        'Show Windows Security'             {Start-Process PowerShell.exe -ArgumentList "Add-AppxPackage -Register -DisableDevelopmentMode 'C:\Windows\SystemApps\Microsoft.Windows.SecHealthUI_cw5n1h2txyewy\AppXManifest.xml';start windowsdefender:"}
        'Show Windows Settings'             {Start-Process ms-settings:}
        'AutopilotDiagnostics'              {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -NoExit',"-Command Invoke-AutopilotOOBEcmd AutopilotDiagnostics"}
        'AutopilotDiagnostics Online'       {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -NoExit',"-Command Invoke-AutopilotOOBEcmd AutopilotDiagnosticsOnline"}
        'MDMDiagnosticsTool -out C:\Temp'                                       {Start-Process MDMDiagnosticsTool.exe -ArgumentList "-out C:\Temp"}
        'MDMDiagnosticsTool -area Autopilot -cab C:\Temp\Autopilot.cab'         {Start-Process MDMDiagnosticsTool.exe -ArgumentList "-area Autopilot","-cab C:\Temp\Autopilot.cab"}
        'MDMDiagnosticsTool -area Autopilot;TPM -cab C:\Temp\AutopilotTPM.cab'  {Start-Process MDMDiagnosticsTool.exe -ArgumentList "-area Autopilot;TPM","-cab C:\Temp\AutopilotTPM.cab"}
        'TPM Get'                           {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -NoExit',"-Command Invoke-AutopilotOOBEcmd GetTpm"}
        'TPM Clear'                         {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -NoExit',"-Command Invoke-AutopilotOOBEcmd ClearTpm"}
        'TPM Initialize'                    {Start-Process -FilePath PowerShell.exe -ArgumentList '-NoLogo -NoExit',"-Command Invoke-AutopilotOOBEcmd InitializeTpm"}
        'Sysprep /oobe /quit'               {Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/quit"}
        'Sysprep /oobe /reboot'             {Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/reboot"}
        'Sysprep /oobe /shutdown'           {Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/shutdown"}
        'Sysprep /audit /reboot'            {Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/audit", "/reboot"}
        Default {}
    }
})
#================================================
# Parameter Docs
#================================================
if ($Hidden -contains 'Docs') {
    $formMainWindowControlDocsStackPanel.Visibility = 'Collapsed'
}

$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Documentation') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Overview') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot User-Driven Mode') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot for Pre-Provisioned Deployment') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Deployment for Existing Devices') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Manually register devices with Windows Autopilot') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Troubleshooting Overview') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Troubleshoot Autopilot Device Import and Enrollment') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Troubleshoot Autopilot OOBE Issues') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Troubleshoot Azure Active Directory Join Issues') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Known Issues') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Windows Autopilot Resolved Issues') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Sysprep Overview') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Sysprep Audit Mode Overview') | Out-Null
$formMainWindowControlDocsComboBox.Items.Add('Sysprep Command-Line Options') | Out-Null

if ($Hidden -contains 'Register') {
    $formMainWindowControlDocsComboBox.SelectedValue = 'Troubleshoot Autopilot OOBE Issues'
}
else {
    $formMainWindowControlDocsComboBox.SelectedValue = 'Windows Autopilot Documentation'
}

if ($Global:AutopilotOOBE.Docs) {
    $formMainWindowControlDocsComboBox.Items.Add($Global:AutopilotOOBE.Docs) | Out-Null
    $formMainWindowControlDocsComboBox.SelectedValue = $Global:AutopilotOOBE.Docs
}

$formMainWindowControlDocsButton.add_Click( {
    Write-Host -ForegroundColor Cyan "Run: $($formMainWindowControlDocsComboBox.SelectedValue)"

    if ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Documentation') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Overview') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/windows-autopilot'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot User-Driven Mode') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/user-driven'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot for Pre-Provisioned Deployment') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/pre-provision'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Deployment for Existing Devices') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/existing-devices'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Manually register devices with Windows Autopilot') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/add-devices'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Troubleshooting Overview') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/troubleshooting'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Troubleshoot Autopilot Device Import and Enrollment') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/troubleshoot-device-enrollment'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Troubleshoot Autopilot OOBE Issues') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/troubleshoot-oobe'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Troubleshoot Azure Active Directory Join Issues') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/troubleshoot-aad-join'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Known Issues') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/known-issues'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Windows Autopilot Resolved Issues') {Start-Process 'https://docs.microsoft.com/en-us/mem/autopilot/resolved-issues'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Sysprep Overview') {Start-Process 'https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--system-preparation--overview'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Sysprep Audit Mode Overview') {Start-Process 'https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/audit-mode-overview'}
    elseif ($formMainWindowControlDocsComboBox.SelectedValue -eq 'Sysprep Command-Line Options') {Start-Process 'https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep-command-line-options'}
    else {
        try {
            Start-Process $formMainWindowControlDocsComboBox.SelectedValue
        }
        catch {
            Write-Warning "Could not execute $($formMainWindowControlDocsComboBox.SelectedValue)"
        }
    }
})
#================================================
# RegisterButton
#================================================
if ($env:UserName -ne 'defaultuser0') {
    $formMainWindowControlRegisterButton.IsEnabled = $false
}

$formMainWindowControlRegisterButton.add_Click( {
    $formMainWindow.Close()
    Show-PowershellWindow

    $Params = @{
        Online = $true
    }

    if ($formMainWindowControlAssignCheckbox.IsChecked) {
        $Params.Assign = $true
    }

    if ($formMainWindowControlAddToGroupComboBox.Text -gt 0) {
        $Params.AddToGroup = $formMainWindowControlAddToGroupComboBox.Text
    }

    if ($formMainWindowControlGroupTagComboBox.Text -gt 0) {
        $Params.GroupTag = $formMainWindowControlGroupTagComboBox.Text
    }

    if (($formMainWindowControlAssignedUserTextBox.Text -gt 0) -and ($formMainWindowControlAssignedUserTextBox.Text -notmatch $Global:AutopilotOOBE.AssignedUserExample)) {
        $Params.AssignedUser = $formMainWindowControlAssignedUserTextBox.Text
    }

    if (($formMainWindowControlAssignedComputerNameTextBox.Text -gt 0) -and ($formMainWindowControlAssignedComputerNameTextBox.Text -notmatch $Global:AutopilotOOBE.AssignedComputerNameExample)) {
        $Params.AssignedComputerName = $formMainWindowControlAssignedComputerNameTextBox.Text
    }

    $Transcript = "$((Get-Date).ToString('yyyy-MM-dd-HHmmss'))-AutopilotOOBE.log"
    Start-Transcript -Path (Join-Path "$env:SystemRoot\Temp" $Transcript) -ErrorAction Ignore

    Write-Host -ForegroundColor Cyan "Install-Script Get-WindowsAutoPilotInfo"
    Start-Sleep -Seconds 3
    Install-Script Get-WindowsAutoPilotInfo -Force -Verbose

    Write-Host ($Params | Out-String)
    Write-Host -ForegroundColor Cyan "Get-WindowsAutoPilotInfo @Params"

    Start-Sleep -Seconds 3
    $formMainWindow.Title = "AutopilotOOBE $ModuleVersion : Registering Device"
    Get-WindowsAutoPilotInfo @Params
    $formMainWindow.Title = "AutopilotOOBE $ModuleVersion : Restart Device"

    if ((Get-Process -Name powershell).MainWindowTitle -match 'Running') {
        Write-Warning "Waiting for Start-OOBEDeploy to finish"
    }

    while ((Get-Process -Name powershell).MainWindowTitle -match 'Running') {
        Start-Sleep -Seconds 10
    }

    if ($formMainWindowControlPostActionComboBox.SelectedValue -eq 'Restart Computer') {Restart-Computer}
    if ($formMainWindowControlPostActionComboBox.SelectedValue -eq 'Shutdown Computer') {Stop-Computer}

    if ($formMainWindowControlPostActionComboBox.SelectedValue -match 'Sysprep') {
        Write-Host -ForegroundColor Cyan "Executing Sysprep"

        if ($formMainWindowControlPostActionComboBox.SelectedValue -match 'quit') {
            Start-Sleep -Seconds 3
            Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/quit" -Wait
        }
        
        elseif (($formMainWindowControlPostActionComboBox.SelectedValue -match 'reboot') -and ($formMainWindowControlPostActionComboBox.SelectedValue -match 'generalize')) {
            Start-Sleep -Seconds 3
            Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "generalize", "/oobe", "/reboot" -Wait
        }
        elseif (($formMainWindowControlPostActionComboBox.SelectedValue -match 'shutdown') -and ($formMainWindowControlPostActionComboBox.SelectedValue -match 'generalize')) {
            Start-Sleep -Seconds 3
            Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "generalize", "/oobe", "/reboot" -Wait
        }

        elseif ($formMainWindowControlPostActionComboBox.SelectedValue -match 'reboot') {
            Start-Sleep -Seconds 3
            Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/reboot" -Wait
        }
        elseif ($formMainWindowControlPostActionComboBox.SelectedValue -match 'shutdown') {
            Start-Sleep -Seconds 3
            Start-Process "$env:SystemRoot\System32\Sysprep\Sysprep.exe" -ArgumentList "/oobe", "/shutdown" -Wait
        }
    }
})
#================================================
# Hide Windows
#================================================
Hide-CmdWindow
Hide-PowershellWindow
########################
## WIRE UP YOUR CONTROLS
########################
# simple example: $formMainWindowControlButton.Add_Click({ your code })
#
# example with BackgroundScriptBlock and UpdateElement
# $formmainControlButton.Add_Click({
# $sb = {
# $SyncClass.UpdateElement("formmainControlProgress","Value",25)
# }
# Start-BackgroundScriptBlock $sb
# })

############################
###### DISPLAY DIALOG ######
############################
[void]$formMainWindow.ShowDialog()

##########################
##### SCRIPT CLEANUP #####
##########################
$jobCleanup.Flag = $false #Stop Cleaning Jobs
$jobCleanup.PowerShell.Runspace.Close() #Close the runspace
$jobCleanup.PowerShell.Dispose() #Remove the runspace from memory