Powershell/Private/DisplayForms/ProgressForm.ps1
function New-ProgressForm { # syncHash the values [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null [System.Reflection.Assembly]::LoadWithPartialName('PresentationFramework') | Out-Null $syncHash = [hashtable]::Synchronized(@{ }) $newRunspace = [runspacefactory]::CreateRunspace() $syncHash.Runspace = $newRunspace $syncHash.PercentComplete = $PercentComplete $syncHash.StatusInput = '' $syncHash.LogText = @() $syncHash.logLevel = '' $syncHash.base64JCLogo = Get-ImageFromB64 -ImageBase64 $JCLogoBase64 $syncHash.closeWindow = $false # Migration Details $syncHash.UsernameInput = '' $syncHash.ProfileSizeInput = '' $syncHash.LocalPathInput = '' $syncHash.NewLocalUsernameInput = '' $syncHash.XAML = @" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="Window" Title="JumpCloud ADMU 2.7.11" WindowStyle="SingleBorderWindow" ResizeMode="NoResize" Background="White" Width="720" Height="550 "> <Window.Resources> <Style x:Key="NoHeaderGroupBoxStyle" TargetType="{x:Type GroupBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type GroupBox}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4"> <Grid> <ContentPresenter ContentSource="Header" RecognizesAccessKey="True" Margin="0" Visibility="Collapsed"/> <ContentPresenter Margin="3" /> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="TextBlock"> <Setter Property="FontFamily" Value="Segoe UI"/> <Setter Property="FontSize" Value="12"/> <Setter Property="FontWeight" Value="Normal"/> <Setter Property="LineHeight" Value="21"/> <Setter Property="Foreground" Value="#202D38"/> </Style> <Style TargetType="Label"> <Setter Property="FontFamily" Value="Segoe UI"/> <Setter Property="FontSize" Value="12"/> <Setter Property="FontWeight" Value="Normal"/> <Setter Property="Foreground" Value="#202D38"/> </Style> <Style TargetType="Button"> <Setter Property="FontFamily" Value="Segoe UI"/> <Setter Property="FontSize" Value="12"/> <Setter Property="Foreground" Value="#202D38"/> <Setter Property="FontWeight" Value="SemiBold"/> </Style> <Style TargetType="ProgressBar"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ProgressBar"> <Grid> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" CornerRadius="4"> <Grid x:Name="PART_Track" ClipToBounds="True" Background="Transparent"> <Border x:Name="PART_Indicator" Background="{TemplateBinding Foreground}" HorizontalAlignment="Left" CornerRadius="4"/> </Grid> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <Image Name="JCLogoImg" Source="C:\Users\kmara\Downloads\JC oceanblue tm.png" Margin="10,10,0,0" HorizontalAlignment="Left" Height="23" VerticalAlignment="Top"/> <Grid Margin="10,0,10,0" > <Grid.RowDefinitions> <RowDefinition Height="auto" MinHeight="216"/> <RowDefinition Height="auto" MinHeight="94"/> <RowDefinition Height="Auto" MinHeight="130"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <GroupBox Header="" Style="{StaticResource NoHeaderGroupBoxStyle}" FontWeight="Bold" Width="auto" MaxHeight="160" Margin="0,46,0,10" HorizontalAlignment="Left"> <Grid HorizontalAlignment="Left" Height="auto" Margin="10,0,0,0" VerticalAlignment="Center" Width="auto" MinWidth="245" MinHeight="100" Grid.Row="0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="118"/> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <TextBlock Text="Migration Details" FontWeight="SemiBold" Grid.Row="0" Margin="0,0,0,10" FontSize="12"/> <Label Content="Username: " HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Normal" Grid.Row="1" Height="25" Width="69" /> <Label Content="ProfileSize: " HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Normal" Grid.Row="2" Height="25" Width="71" /> <Label Content="LocalPath:" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Normal" Grid.Row="3" Height="25" Width="63" /> <Label Content="NewLocalUsername:" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Normal" Grid.Row="4" Height="25" Width="118" /> <Label Name="Username" Content="..." FontWeight="SemiBold" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="22,0,0,0" /> <Label Name="ProfileSize" Content="0.8GB" FontWeight="SemiBold" Grid.Row="2" Grid.Column="1" Margin="22,0,0,0" HorizontalAlignment="Right"/> <Label Name="LocalPath" Content="..." FontWeight="SemiBold" Grid.Row="3" Grid.Column="1" Margin="22,0,0,0" HorizontalAlignment="Right"/> <Label Name="NewLocalUsername" Content="..." FontWeight="SemiBold" Grid.Row="4" Grid.Column="1" Margin="22,0,0,0" HorizontalAlignment="Right"/> </Grid> </GroupBox> <GroupBox Header="" Style="{StaticResource NoHeaderGroupBoxStyle}" FontWeight="Bold" Height="94" Grid.Row="1"> <StackPanel Height="86" VerticalAlignment="Center"> <TextBlock Text="Migration Status" FontWeight="SemiBold" FontSize="12" Margin="5,10,0,0"/> <TextBlock Name="Status" TextWrapping="Wrap" Text="Status:" LineHeight="15" Width="auto" FontSize="12" Height="auto" Margin="5,0,5,5" HorizontalAlignment="Left" FontWeight="Normal"/> <TextBlock Name="ErrorBlock" Width="auto" FontSize="12" Height="auto" Margin="5,0,0,0" HorizontalAlignment="Left" FontWeight="Normal" Visibility="Collapsed"> <Hyperlink Name="ErrorLink" NavigateUri="https://github.com/TheJumpCloud/jumpcloud-ADMU/wiki/troubleshooting-errors"> https://github.com/TheJumpCloud/jumpcloud-ADMU/wiki/troubleshooting-errors </Hyperlink> </TextBlock> <ProgressBar Name="ProgressBar" Height="8" Foreground="#41C8c3" VerticalAlignment="Top" Width="645" Margin="5,0,0,20" Value="50" HorizontalAlignment="Left" Visibility="Visible" > </ProgressBar> </StackPanel> </GroupBox> <StackPanel VerticalAlignment="Center" Grid.Row="2" > <Expander Header="View Log" Background="White" Foreground="#4373C7" Height="142" Margin="0,10,0,0"> <Expander.Resources> <Style TargetType="{x:Type Border}"> <Setter Property="CornerRadius" Value="5"/> </Style> </Expander.Resources> <Border BorderBrush="#E3E8E9" BorderThickness="1" CornerRadius="5" > <ScrollViewer Name="ScrollLog" Foreground="Gray" HorizontalScrollBarVisibility="Disabled" VerticalAlignment="Center" Height="98" Width="650"> <TextBlock Name="LogTextBlock" TextWrapping="Wrap" FontWeight="Medium" FontSize="11">...</TextBlock> </ScrollViewer> </Border> </Expander> </StackPanel> <Grid Grid.Row="4" Margin="0,10,0,0" HorizontalAlignment="Right" VerticalAlignment="Top" Height="26" > <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="0"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="0"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Button Grid.Column="0" Name="ViewLogButton" Content="View Log" Height="26" Width="70" IsEnabled="False" Margin="0,0,10,0" HorizontalAlignment="Center"> <Button.Resources> <Style TargetType="{x:Type Border}"> <Setter Property="CornerRadius" Value="3"/> </Style> </Button.Resources> </Button> <Button Grid.Column="2" Name="StartJCADMUButton" Content="Rerun" Height="26" Width="70" IsEnabled="False" Margin="0,0,10,0"> <Button.Resources> <Style TargetType="{x:Type Border}"> <Setter Property="CornerRadius" Value="3"/> </Style> </Button.Resources> </Button> <Button Grid.Column="4" Name="ExitButton" Content="Exit" Height="26" Width="70" VerticalAlignment="Top" IsEnabled="False"> <Button.Resources> <Style TargetType="{x:Type Border}"> <Setter Property="CornerRadius" Value="3"/> </Style> </Button.Resources> </Button> </Grid> </Grid> </Grid> </Window> "@ # Colors # Foreground="#90b7fc" Darkblue # Foreground="#52C4C1" Teal # Create a runspace to run the form in $newRunspace.ApartmentState = "STA" $newRunspace.ThreadOptions = "ReuseThread" $data = $newRunspace.Open() | Out-Null $newRunspace.SessionStateProxy.SetVariable("syncHash", $syncHash) # Add the form code to the powershell instance $psCommand = [PowerShell]::Create().AddScript({ # Load an xaml form $syncHash.Window = [Windows.Markup.XamlReader]::parse( $SyncHash.XAML ) ([xml]$SyncHash.XAML).SelectNodes("//*[@Name]") | ForEach-Object { $SyncHash."$($_.Name)" = $SyncHash.Window.FindName($_.Name) } # Image $SyncHash.JCLogoImg.Source = $syncHash.base64JCLogo $syncHash.Username.Content = $syncHash.UsernameInput $syncHash.ProfileSize.Content = $syncHash.ProfileSizeInput $syncHash.LocalPath.Content = $syncHash.LocalPathInput $syncHash.NewLocalUsername.Content = $syncHash.NewLocalUsernameInput # Scroll to end of Log $syncHash.ScrollLog.ScrollToEnd() $updateForm = { # Migration Details if ($SyncHash.closeWindow -eq $True) { $syncHash.Window.Close() [System.Windows.Forms.Application]::Exit() Break } # IF close window button is clicked if ($SyncHash.Closing) { $SyncHash.Window.Close() [System.Windows.Forms.Application]::Exit() Break } if ($SyncHash.logLevel -eq "Error") { #$syncHash.Status.Foreground = "Red" # Hide Progress Bar $SyncHash.ProgressBar.Visibility = "Hidden" # Show Error Link and make clickable $syncHash.ErrorBlock.Visibility = "Visible" # Clickable link $SyncHash.ErrorLink.add_RequestNavigate({ #Sender is an event handler and used when the link is clicked https://learn.microsoft.com/en-us/dotnet/api/system.windows.navigation.requestnavigateeventargs.invokeeventhandler?view=windowsdesktop-8.0#system-windows-navigation-requestnavigateeventargs-invokeeventhandler(system-delegate-system-object # Suppress PSScriptAnalyzer rule that warns about 'Sender' being an automatic variable # <pragma>disable PSAvoidUsingAutomaticVariable param ($SenderParam, $e) if (-not $SenderParam) { Write-Error "SenderParam needs to be populated" } [System.Diagnostics.Process]::Start($e.Uri.AbsoluteUri) # Open the link in the default web browser $e.Handled = $true }) } if ($syncHash.PercentComplete -eq 100) { $SyncHash.ViewLogButton.IsEnabled = $true $SyncHash.StartJCADMUButton.IsEnabled = $true $SyncHash.ExitButton.IsEnabled = $true } # Update Log TextBlock $SyncHash.LogTextBlock.Text = $syncHash.LogText # Update Progress Bar $SyncHash.ProgressBar.Value = $SyncHash.PercentComplete # Update Status Text $SyncHash.Status.Text = $SyncHash.StatusInput } # View Log Button $SyncHash.ViewLogButton.Add_Click({ # Open log \Windows\Temp\jcAdmu.log $scriptPath = "$(Get-WindowsDrive)\Windows\Temp\jcAdmu.log" # Open the log Invoke-Item -Path:($scriptPath) }) # Start JCADMU Button $syncHash.StartJCADMUButton.Add_Click({ # Get the path of the exe then rerun $exeFilePath = [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName Start-Process -FilePath $exeFilePath # Close the current window $syncHash.CloseWindow = $true }) $syncHash.ExitButton.Add_Click({ $syncHash.CloseWindow = $true }) # Time to update the form $syncHash.Window.Add_SourceInitialized( { $timer = new-object System.Windows.Threading.DispatcherTimer $timer.Interval = [TimeSpan]"0:0:0.01" $timer.Add_Tick( $updateForm ) $timer.Start() if (!$timer.IsEnabled ) { $clock.Close() Write-Error "Timer didn't start" } } ) $syncHash.Window.Show() | Out-Null $appContext = [System.Windows.Forms.ApplicationContext]::new() [void][System.Windows.Forms.Application]::Run($appContext) }) # Invoke PS Command $psCommand.Runspace = $newRunspace $data = $psCommand.BeginInvoke() Register-ObjectEvent -InputObject $SyncHash.Runspace -EventName 'AvailabilityChanged' -Action { if ($Sender.RunspaceAvailability -eq "Available") { $Sender.Closeasync() $Sender.Dispose() } } | Out-Null return $syncHash } # Function to update the progress bar function Update-ProgressForm { param( [Parameter(Mandatory = $true)] $ProgressBar, [int]$PercentComplete, [string]$Status, [string]$logLevel, [string]$username, [string]$profileSize, [string]$localPath, [string]$newLocalUsername ) if ($username -or $profileSize -or $localPath -or $newLocalUsername) { #Write-toLog -message "Migration details updated: Username: $username, ProfileSize: $profileSize, LocalPath: $localPath, NewLocalUsername: $newLocalUsername" $ProgressBar.UsernameInput = $username $ProgressBar.ProfileSizeInput = "$($profileSize)GB" $ProgressBar.LocalPathInput = $localPath $ProgressBar.NewLocalUsernameInput = $newLocalUsername } if ($logLevel -eq "Error") { $ProgressBar.PercentComplete = 100 $ProgressBar.StatusInput = $Status $ProgressBar.logLevel = $logLevel } else { $ProgressBar.PercentComplete = $PercentComplete $ProgressBar.StatusInput = $Status } } function Update-LogTextBlock { param( [Parameter(Mandatory = $true)] $ProgressBar, [string]$LogText ) # Update the progress bar and add XAML linebreaks $ProgressBar.LogText += $LogText } |