Projects/ApplyFFU.ps1
#======================================================================= # Clear Screen #======================================================================= #Clear-Host #======================================================================= # PowershellWindow Functions # Hide the PowerShell Window # https://community.spiceworks.com/topic/1710213-hide-a-powershell-console-window-when-running-a-script #======================================================================= $Script:showWindowAsync = Add-Type -MemberDefinition @" [DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); "@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru function Show-Powershell() { $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 10) } function Hide-Powershell() { $null = $showWindowAsync::ShowWindowAsync((Get-Process -Id $pid).MainWindowHandle, 2) } #Hide-Powershell #======================================================================= # MahApps.Metro #======================================================================= # Assign current script directory to a global variable $Global:MyScriptDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition) # Load presentationframework and Dlls for the MahApps.Metro theme [System.Reflection.Assembly]::LoadWithPartialName("presentationframework") | Out-Null [System.Reflection.Assembly]::LoadFrom("$Global:MyScriptDir\assembly\System.Windows.Interactivity.dll") | Out-Null [System.Reflection.Assembly]::LoadFrom("$Global:MyScriptDir\assembly\MahApps.Metro.dll") | Out-Null #======================================================================= # Console Title #======================================================================= #$host.ui.RawUI.WindowTitle = "Start-ApplyFFU" #======================================================================= # Test-InWinPE #======================================================================= function Test-InWinPE { return Test-Path -Path Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlset\Control\MiniNT } #======================================================================= # LoadForm #======================================================================= function LoadForm { [CmdletBinding()] param( [Parameter(Mandatory = $True, Position = 1)] [string]$XamlPath ) # Import the XAML code [xml]$Global:xmlWPF = Get-Content -Path $XamlPath # Add WPF and Windows Forms assemblies try { Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms } catch { throw "Failed to load Windows Presentation Framework assemblies." } #Create the XAML reader using a new XML node reader $Global:xamGUI = [Windows.Markup.XamlReader]::Load((new-object System.Xml.XmlNodeReader $xmlWPF)) #Create hooks to each named object in the XAML $xmlWPF.SelectNodes("//*[@Name]") | ForEach { Set-Variable -Name ($_.Name) -Value $xamGUI.FindName($_.Name) -Scope Global } } #======================================================================= # LoadForm #======================================================================= LoadForm -XamlPath (Join-Path $Global:MyScriptDir 'ApplyFFU.xaml') #======================================================================= # Title #======================================================================= $TitleLabel.Content = 'Start-ApplyFFU' #======================================================================= # ApplyDrives #======================================================================= # Create empty array of hard disk numbers $Global:ArrayOfDiskNumbers = @() #Get all the ApplyDrives $Global:ApplyDrives = Get-LocalDisk | Where-Object {$_.IsBoot -eq $false} # Populate the ComboBox $Global:ApplyDrives | foreach { $ApplyDriveComboBox.Items.Add("Disk $($_.DiskNumber) $($_.BusType) $($_.MediaType) - $($_.FriendlyName)") | Out-Null $Global:ArrayOfDiskNumbers += $_.Number } $ApplyDriveDetails.Content = '' #Select the first item $ApplyDriveComboBox.SelectedIndex = 0 #======================================================================= # Set-ApplyDriveComboBox #======================================================================= function Set-ApplyDriveComboBox { $ApplyDrive = Get-LocalDisk | Where-Object { $_.Number -eq $Global:ArrayOfDiskNumbers[$ApplyDriveComboBox.SelectedIndex] } # Work out if the size should be in GB or TB if ([math]::Round(($ApplyDrive.Size/1TB),2) -lt 1) { $ApplyDriveSize = "$([math]::Round(($ApplyDrive.Size/1000000000),0))GB" } else { $ApplyDriveSize = "$([math]::Round(($ApplyDrive.Size/1000000000000),2))TB" } $Global:DiskNumber = $ApplyDrive.DiskNumber $Global:DismApplyDrive = "\\.\PhysicalDrive$($Global:DiskNumber)" Write-Host -ForegroundColor Cyan "ApplyDrive: $Global:DismApplyDrive" $Global:DismName = "disk$($Global:DiskNumber)" Write-Host -ForegroundColor Cyan "Name: $Global:DismName" $ApplyDriveDetails.Content = @" $ApplyDriveSize $($ApplyDrive.PartitionStyle) $($ApplyDrive.NumberOfPartitions) Partitions "@ } #======================================================================= # Set-ImageFileComboBox #======================================================================= function Set-ImageFileComboBox { $Global:DestinationDrives = @() $Global:DestinationDrives = Get-DataDisk | Where-Object {$_.DiskNumber -ne $Global:DiskNumber} $ImageFileComboBox.Items.Clear() $ImageFiles = @() if (-NOT ($Global:DestinationDrives)) { $ImageFileComboBox.IsEnabled = "False" } else { foreach ($DestinationDrive in $Global:DestinationDrives) { if (Test-Path "$($DestinationDrive.DriveLetter):\CaptureFFU") { $ImageFiles += Get-ChildItem "$($DestinationDrive.DriveLetter):\CaptureFFU" -Include *.ffu -File -Recurse -Force -ErrorAction Ignore | Select-Object -ExpandProperty FullName } } if ($ImageFiles) { foreach ($Item in $ImageFiles) { $ImageFileComboBox.Items.Add($Item) | Out-Null } $ImageFileComboBox.SelectedIndex = 0 } } } #======================================================================= # Set-DismCommandText #======================================================================= function Set-DismCommandText { #Write-Host "Text: $($ImageFileComboBox.Text)" $Global:DismImageFile = $ImageFileComboBox.Text if ($Global:DismImageFile -gt 0) { Write-Host -ForegroundColor Cyan "ImageFile: $Global:DismImageFile" } $DismCommand.Text = "Dism.exe /Apply-FFU /ImageFile=`"$Global:DismImageFile`" /ApplyDrive=$Global:DismApplyDrive" $ImageFileComboBox.IsEnabled = "True" } Set-ApplyDriveComboBox Set-ImageFileComboBox Set-DismCommandText <# $DestinationDetails.Content = @" DiskNumber: $($DestinationDrive.DiskNumber) FileSystemLabel: $($DestinationDrive.FileSystemLabel) FileSystem: $($DestinationDrive.FileSystem) Size: $($DestinationDrive.Size) SizeRemaining: $($DestinationDrive.SizeRemaining) "@ #> #======================================================================= # ApplyDriveComboBox Events #======================================================================= $ApplyDriveComboBox.add_SelectionChanged({ Set-ApplyDriveComboBox Set-ImageFileComboBox Set-DismCommandText }) $ApplyDriveComboBox.add_DropDownClosed({ Set-ApplyDriveComboBox Set-ImageFileComboBox Set-DismCommandText }) #======================================================================= # ImageFileComboBox Events #======================================================================= $ImageFileComboBox.add_SelectionChanged({ #Write-Host -ForegroundColor Magenta "add_SelectionChanged" Set-DismCommandText }) $ImageFileComboBox.add_DropDownClosed({ #Write-Host -ForegroundColor Magenta "add_DropDownClosed" Set-DismCommandText }) $ImageFileComboBox.add_IsKeyboardFocusedChanged({ #Write-Host -ForegroundColor Magenta "add_IsKeyboardFocusedChanged" Set-DismCommandText }) $ImageFileComboBox.add_IsKeyboardFocusWithinChanged({ #Write-Host -ForegroundColor Magenta "add_IsKeyboardFocusWithinChanged" Set-DismCommandText }) $ImageFileComboBox.add_KeyUp({ #Write-Host -ForegroundColor Magenta "add_KeyUp" Set-DismCommandText }) #======================================================================= # RunButton #======================================================================= $RunButton.add_Click({ if ($null -eq $Global:DismImageFile) { Write-Warning "DismImageFile value is null" } elseif ($Global:DismImageFile -eq '') { Write-Warning "DismImageFile value is nothing" } else { $ParentDirectory = Split-Path $Global:DismImageFile -Parent -ErrorAction Stop Write-Host "Dism.exe /Apply-FFU /ImageFile=`"$Global:DismImageFile`" /ApplyDrive=$Global:DismApplyDrive" $xamGUI.Close() Show-Powershell #======================================================================= # Checks #======================================================================= if (-NOT (Test-InWinPE)) { Write-Warning "ApplyFFU must be run in WinPE" Break } #======================================================================= # Create FFU #======================================================================= $CommandLine = "Dism.exe /Apply-FFU /ImageFile=`"$Global:DismImageFile`" /ApplyDrive=$Global:DismApplyDrive" Write-Host "CommandLine: $CommandLine" Get-OSDPower -Property High Start-Process PowerShell.exe -Wait -WorkingDirectory $ParentDirectory -ArgumentList '-NoExit','-NoLogo','Dism.exe','/Apply-FFU',"/ImageFile='$Global:DismImageFile'","/ApplyDrive='$Global:DismApplyDrive'" Get-OSDPower -Property Balanced if (Test-Path $Global:DismImageFile) { Get-WindowsImage -ImagePath $Global:DismImageFile } #======================================================================= } }) #======================================================================= # ShowDialog #======================================================================= $xamGUI.ShowDialog() | Out-Null #======================================================================= |