From 18c2c4a96193f2f20d0105e01281afa8679a0455 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 20:47:02 -0800 Subject: [PATCH 01/85] 2015-11: Retroactive initial commit --- LICENSE.txt | 7 + README.md | 18 ++ System32/menu.cmd | 34 ++++ System32/startnet.cmd | 10 + WK/FastCopy.ini | 165 +++++++++++++++++ WK/Notepad2.ini | 131 ++++++++++++++ WK/Scripts/WK.ps1 | 413 ++++++++++++++++++++++++++++++++++++++++++ WK/Scripts/init.ps1 | 48 +++++ WK/hwmonitorw.ini | 7 + make-cd.cmd | 34 ++++ make.cmd | 100 ++++++++++ update.cmd | 100 ++++++++++ 12 files changed, 1067 insertions(+) create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 System32/menu.cmd create mode 100644 System32/startnet.cmd create mode 100644 WK/FastCopy.ini create mode 100644 WK/Notepad2.ini create mode 100644 WK/Scripts/WK.ps1 create mode 100644 WK/Scripts/init.ps1 create mode 100644 WK/hwmonitorw.ini create mode 100644 make-cd.cmd create mode 100644 make.cmd create mode 100644 update.cmd diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..a401a44d --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,7 @@ +Copyright (c) 2015 Alan Mason + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..ebd32070 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Wizard Kit PE # + +A collection of scripts to help technicians service Windows systems. + +# NOTICE: Currently under maintenance # + +*These scripts are being reviewed and updated at the moment.* +Things may or may not work until this is completed. This warning will be removed once the maintenance is finished. + +## Requirements ## + +* Windows Assessment and Deployment Kit for Windows 10 + +## Initial Setup ## + +* Install Windows ADK for Windows 10 +* Run "Deployment and Imaging Tools Environment" as admin +* Run `make.cmd` to build a new Windows 10 PE image \ No newline at end of file diff --git a/System32/menu.cmd b/System32/menu.cmd new file mode 100644 index 00000000..ca826073 --- /dev/null +++ b/System32/menu.cmd @@ -0,0 +1,34 @@ +@echo off + +:Init +setlocal EnableDelayedExpansion +title Menu Launcher +color 0a +pushd %~dp0 + +:Flags +for %%f in (%*) do ( + if /i "%%f" == "/DEBUG" (@echo on) +) + +:LaunchMenu +PowerShell -ExecutionPolicy Bypass %systemdrive%\WK\Scripts\WK.ps1 +goto Done + +:Abort +echo. +echo Aborted. +goto Exit + +:Done +echo. +echo Done. +goto Exit + +:Exit +echo. +rem echo Press any key to exit... +rem pause>nul +popd +color +endlocal \ No newline at end of file diff --git a/System32/startnet.cmd b/System32/startnet.cmd new file mode 100644 index 00000000..c97c37be --- /dev/null +++ b/System32/startnet.cmd @@ -0,0 +1,10 @@ +@echo off + +echo Initializing... +wpeinit +wpeutil updatebootinfo + +pushd %systemdrive%\WK +set "PATH=%PATH%;%systemdrive%\WK" + +powershell -executionpolicy bypass -file %systemdrive%\WK\Scripts\WK.ps1 diff --git a/WK/FastCopy.ini b/WK/FastCopy.ini new file mode 100644 index 00000000..62517176 --- /dev/null +++ b/WK/FastCopy.ini @@ -0,0 +1,165 @@ +[main] +bufsize="128" +max_transize="16" +nonbuf_minsize_ntfs2="64" +nonbuf_minsize_fat="128" +is_readosbuf="0" +max_history="10" +default_copy_mode="1" +skip_empty_dir="1" +ignore_error="1" +estimate_mode="0" +disk_mode="0" +is_toplevel="0" +is_errlog="1" +is_utf8log="1" +filelog_mode="0" +aclerr_log="0" +streamerr_log="0" +is_samedir_rename="1" +shext_autoclose="1" +shext_tasktray="0" +shext_dd_noconfirm="0" +shext_right_noconfirm="0" +exec_confirm="0" +force_start="0" +lcid="-1" +speed_level="11" +overwrite_del="0" +acl="0" +stream="0" +verify="0" +nsa_del="0" +deldir_with_filter="0" +move_attr="0" +serial_move="0" +serial_verify_move="0" +reparse2="1" +extend_filter="0" +taskbarMode="0" +infoSpan="2" +win_pos="-10000,-10000,-10000,-10000" +driveMap="" +[src_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[dst_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[del_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[include_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[exclude_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[fromdate_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[todate_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[minsize_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[maxsize_history] +0="" +1="" +2="" +3="" +4="" +5="" +6="" +7="" +8="" +9="" +[finaction_0] +title="Normal" +sound="" +cmd="" +shutdown_time="-1" +flags="1" +[finaction_1] +title="Standby" +sound="" +cmd="" +shutdown_time="60" +flags="65" +[finaction_2] +title="Hibernate" +sound="" +cmd="" +shutdown_time="60" +flags="129" +[finaction_3] +title="Shutdown" +sound="" +cmd="" +shutdown_time="60" +flags="257" diff --git a/WK/Notepad2.ini b/WK/Notepad2.ini new file mode 100644 index 00000000..6bba42de --- /dev/null +++ b/WK/Notepad2.ini @@ -0,0 +1,131 @@ +[Settings] +SaveSettings=1 +SaveRecentFiles=1 +SaveFindReplace=1 +CloseFind=0 +CloseReplace=0 +NoFindWrap=0 +OpenWithDir=%SystemDrive%\ +Favorites=%SystemDrive%\ +PathNameFormat=1 +WordWrap=0 +WordWrapMode=0 +WordWrapIndent=0 +WordWrapSymbols=22 +ShowWordWrapSymbols=0 +MatchBraces=1 +AutoCloseTags=0 +HighlightCurrentLine=1 +AutoIndent=1 +AutoCompleteWords=0 +ShowIndentGuides=0 +TabsAsSpaces=1 +TabIndents=1 +BackspaceUnindents=0 +TabWidth=4 +IndentWidth=0 +MarkLongLines=1 +LongLinesLimit=80 +LongLineMode=1 +ShowSelectionMargin=0 +ShowLineNumbers=1 +ShowCodeFolding=1 +MarkOccurrences=2 +MarkOccurrencesMatchCase=0 +MarkOccurrencesMatchWholeWords=0 +ViewWhiteSpace=0 +ViewEOLs=0 +DefaultEncoding=3 +SkipUnicodeDetection=0 +LoadASCIIasUTF8=0 +LoadNFOasOEM=1 +NoEncodingTags=0 +DefaultEOLMode=0 +FixLineEndings=0 +FixTrailingBlanks=0 +PrintHeader=1 +PrintFooter=0 +PrintColorMode=3 +PrintZoom=10 +PrintMarginLeft=1000 +PrintMarginTop=1000 +PrintMarginRight=1000 +PrintMarginBottom=1000 +SaveBeforeRunningTools=1 +FileWatchingMode=1 +ResetFileWatching=0 +EscFunction=2 +AlwaysOnTop=0 +MinimizeToTray=0 +TransparentMode=0 +ToolbarButtons=1 2 4 0 5 6 0 7 8 9 0 10 11 0 12 0 24 0 13 14 0 15 0 17 +ShowToolbar=1 +ShowStatusbar=1 +EncodingDlgSizeX=256 +EncodingDlgSizeY=262 +RecodeDlgSizeX=256 +RecodeDlgSizeY=262 +FileMRUDlgSizeX=412 +FileMRUDlgSizeY=376 +OpenWithDlgSizeX=384 +OpenWithDlgSizeY=386 +FavoritesDlgSizeX=334 +FavoritesDlgSizeY=316 +FindReplaceDlgPosX=0 +FindReplaceDlgPosY=0 +[Settings2] +SingleFileInstance=1 +ShellAppUserModelID=Notepad2 +ShellUseSystemMRU=1 +[Custom Colors] +01=#000000 +02=#0A246A +03=#3A6EA5 +04=#003CE6 +05=#006633 +06=#608020 +07=#648000 +08=#A46000 +09=#FFFFFF +10=#FFFFE2 +11=#FFF1A8 +12=#FFC000 +13=#FF4000 +14=#C80000 +15=#B000B0 +16=#B28B40 +[Styles] +Use2ndDefaultStyle=1 +DefaultScheme=0 +AutoSelect=1 +SelectDlgSizeX=304 +SelectDlgSizeY=324 +[Default Text] +2nd Default Style=font:Lucida Console; size:10; fore:#C0C0C0; back:#000000 +2nd Margins and Line Numbers=font:Tahoma; size:-3; fore:#808080; back:#000000 +2nd Matching Braces=bold; fore:#00FF00 +2nd Matching Braces Error=bold; fore:#FF0000 +2nd Control Characters (Font)=size:-1 +2nd Indentation Guide (Color)=fore:#808080 +2nd Selected Text (Colors)=fore:#008000; back:#404040; alpha:50; eolfilled +2nd Whitespace (Colors, Size 0-5)=fore:#FF0000 +2nd Current Line Background (Color)=back:#808080; alpha:50 +2nd Caret (Color, Size 1-3)=fore:#C0C0C0 +2nd Long Line Marker (Colors)=fore:#404040 +2nd Extra Line Spacing (Size)= +[Window] +1440x900 PosX=600 +1440x900 PosY=16 +1440x900 SizeX=824 +1440x900 SizeY=824 +1440x900 Maximized=1 +1600x900 PosX=756 +1600x900 PosY=16 +1600x900 SizeX=828 +1600x900 SizeY=828 +1600x900 Maximized=1 +800x600 PosX=216 +800x600 PosY=16 +800x600 SizeX=568 +800x600 SizeY=568 +800x600 Maximized=0 \ No newline at end of file diff --git a/WK/Scripts/WK.ps1 b/WK/Scripts/WK.ps1 new file mode 100644 index 00000000..ccfcd28b --- /dev/null +++ b/WK/Scripts/WK.ps1 @@ -0,0 +1,413 @@ +# WK-Checklist + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 +clear +$host.UI.RawUI.WindowTitle = "WK PE Tool" +$logpath = "$WKPath\Info\$date" +md "$logpath" 2>&1 | out-null +$log = "$logpath\winpe.log" +$source_server = "10.0.0.10" +$backup_servers = @( + @{ "ip"="10.0.0.10"; + "letter"="Z"; + "name"="ServerOne"; + "path"="Backups"}, + @{ "ip"="10.0.0.11"; + "name"="ServerTwo"; + "letter"="Y"; + "path"="Backups"} + ) +$backup_user = "WORKGROUP\backup" +$backup_pass = "Abracadabra" + +# Functions +function apply-image { + param([string]$image, [int]$index) + $path = "" + $split_image = $false + $split_image_pattern = "" + + # Check for local source + $volumes = get-volume | where {$_.Size -ne 0 -and $_.DriveLetter -match '^[C-Z]$'} + foreach ($v in $volumes) { + $letter = $v.DriveLetter + ":" + if (test-path "$letter\sources\$image.wim") { + $path = "$letter\sources\$image.wim" + } elseif (test-path "$letter\sources\$image.swm") { + $path = "$letter\sources\$image.swm" + $split_image = $true + $split_image_pattern = "$letter\sources\$image*.swm" + } + } + + # Check for remote source (if necessary) + if ($path -match '^$') { + net use z: "\\$source_server\Windows" /user:guest notarealpassword + if (test-path "Z:\$image.wim") { + $path = "Z:\$image.wim" + } elseif (test-path "Z:\$image.swm") { + $path = "Z:\$image.swm" + } + } + + # Expand Image + if ($path -match '\.wim$') { + Expand-WindowsImage -ImagePath "$path" -Index $index -ApplyPath 'W:\' + } elseif ($path -match '\.swm$') { + Expand-WindowsImage -ImagePath "$path" -Index $index -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" + } else { + net use z: /delete + throw "Source image not found." + } + net use z: /delete +} +function format-gpt { + param($dest_disk) + wk-write "Drive will use a GPT (UEFI) layout." + + # Double-check we have the right drive + ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets + $_sel_uid = $dest_disk.Guid + if ($dest_disk.PartitionStyle -imatch "MBR") { + # MBR disks don't have GUIDs and use the signature in hex instead + $_sel_uid = "{0:x}" -f $dest_disk.Signature + } + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "uniqueid disk" + out-file -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + start "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | out-null + if (!(Get-Content "$wd\drive_uid" | where {$_ -imatch $_sel_uid})) { + # GUIDs do not match + wk-error "Diskpart failed to select the same disk for formatting, aborting setup." + wk-warn "This system requires manual formatting & setup" + wk-write "" + throw "Failed to format disk" + } else { + wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) + } + + # Generate Diskpart script and execute + ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: + ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d + ## + ## NOTE 2: This overwrites existing diskpart.script file without confirmation. + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "clean`r`n" + $diskpart_script += "convert gpt`r`n" + + # 1. Windows RE tools partition (Windows 8+) + if ($dest_windows_version.Name -match '^Windows (8|10)') { + $diskpart_script += "create partition primary size=300`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" + $diskpart_script += "assign letter='T'`r`n" + $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" + $diskpart_script += "gpt attributes=0x8000000000000001`r`n" + } + + # 2. System partition + $diskpart_script += "create partition efi size=260`r`n" + ## NOTE: Allows for Advanced Format 4Kn drives + $diskpart_script += "format quick fs=fat32 label='System'`r`n" + $diskpart_script += "assign letter='S'`r`n" + + # 3. Microsoft Reserved (MSR) partition + $diskpart_script += "create partition msr size=128`r`n" + + # 4. Windows partition + $diskpart_script += "create partition primary`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" + $diskpart_script += "assign letter='W'`r`n" + + # Run script + out-file -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + start "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow +} +function format-mbr { + param($dest_disk) + wk-write "Drive will use a MBR (legacy) layout." + + if ($dest_disk.PartitionStyle -notmatch '^RAW$') { + # Only clean if necessary + clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false + } + Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' + New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true + New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false + Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' + Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' +} +function wk-exit { + popd + if ($answer -match 'R') { + #pause "Press Enter to Reboot... " + wpeutil reboot + } elseif ($answer -match 'S') { + #pause "Press Enter to Shutdown... " + wpeutil shutdown + } + exit 0 +} +function mount-servers { + # Mount servers + wk-write "Connecting to backup server(s)" + foreach ($_server in $backup_servers) { + if (test-connection $_server.ip -count 1 -quiet) { + try { + $_path = "\\{0}\{1}" -f $_server.ip, $_server.path + $_drive = "{0}:" -f $_server.letter + net use $_drive "$_path" /user:$backup_user $backup_pass | out-null + wk-write ("`t{0} server: mounted" -f $_server.name) + + # Add friendly description + $_regex = "^{0}$" -f $_server.letter + (gdr | where {$_.Name -imatch $_regex}).Description = $_server.name + } catch { + wk-warn ("`t{0} server: failed" -f $_server.name) + } + } else { + wk-warn ("`t{0} server: unreachable" -f $_server.name) + } + } +} +function unmount-servers { + # Unmount servers + wk-write "Disconnecting from backup server(s)" + $mounted_servers = @(gdr | where {$_.DisplayRoot -imatch '\\\\'}) + foreach ($_server in $mounted_servers) { + try { + $_drive = "{0}:" -f $_server.Name + net use $_drive /delete | out-null + wk-warn ("`t{0} server: unmounted" -f $_server.name) + } catch { + wk-warn ("`t{0} server: failed" -f $_server.name) + } + } +} +function menu-imaging { + wk-write "Drive Imaging" + wk-write "" + + ## WARNING + wk-warn "WARNING: This section is experimental" + pause + ## WARNING + + # Mount server(s) + mount-servers + + # Select destination + $avail_servers = @(gdr | where {$_.DisplayRoot -imatch '\\\\'}) + $menu_disc_imaging = "Which drive are we imaging?`r`n`r`n" + $valid_answers = @("M", "m") + for ($i=0; $i -lt $avail_servers.length; $i++) { + $valid_answers += ($i + 1) + $menu_disc_imaging += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) + } + $menu_disc_imaging += "`r`n" + $menu_disc_imaging += "M: Main Menu`r`n" + $menu_disc_imaging += "`r`n" + $menu_disc_imaging += "Please make a selection`r`n" + do { + clear + $answer = read-host -prompt $menu_disc_imaging + } until ($valid_answers -contains $answer) + if ($answer -imatch '^M$') { + # Exit if requested + unmount-servers + popd + return + } else { + $answer -= 1 + $dest_backup_server = $avail_servers[$answer] + } + + # Service Order + $menu_service_order += "Please enter the service order`r`n" + do { + clear + $service_order = read-host -prompt $menu_service_order + } until ($service_order -imatch '^\d[\w\-]+$') + + # Backup partitions + wk-write ("Saving partition backups to: {0}" -f $dest_backup_server.Description) + wk-write ("`t{0}{1}" -f $dest_backup_server.Root, $service_order) + + # Unmount server(s) + unmount-servers + pause "Press Enter to return to main menu... " +} +function menu-setup { + wk-write "Windows Setup" + wk-write "" + pushd $WKPath\Setup + + # Build windows menu + $windows_versions = @( + @{Name="Windows 7 Home Premium"; ImageFile="Win7"; Index=1}, + @{Name="Windows 7 Professional"; ImageFile="Win7"; Index=2}, + @{Name="Windows 7 Ultimate"; ImageFile="Win7"; Index=3}, + @{Name="Windows 8.1"; ImageFile="Win8"; Index=1}, + @{Name="Windows 8.1 Pro"; ImageFile="Win8"; Index=2}, + @{Name="Windows 10 Home"; ImageFile="Win10"; Index=1}, + @{Name="Windows 10 Pro"; ImageFile="Win10"; Index=2} + ) + $menu_setup_windows = "Which version of Windows are we installing?`r`n`r`n" + $valid_answers = @("M", "m") + for ($i=0; $i -lt $windows_versions.length; $i++) { + $valid_answers += ($i + 1) + $menu_setup_windows += "{0}: {1}`r`n" -f ($i + 1), $windows_versions[$i].Name + } + $menu_setup_windows += "`r`n" + $menu_setup_windows += "M: Main Menu`r`n" + $menu_setup_windows += "`r`n" + $menu_setup_windows += "Please make a selection`r`n" + + # Select Windows version + do { + clear + $answer = read-host -prompt $menu_setup_windows + } until ($valid_answers -contains $answer) + + if ($answer -imatch '^M$') { + # Exit if requested + popd + return + } else { + $answer -= 1 + $dest_windows_version = $windows_versions[$answer] + } + + # Build disk menu + $menu_setup_disk = "To which drive are we installing {0}?`r`n`r`n" -f $dest_windows_version.Name + $valid_answers = @("M", "m") + $disks = get-disk | where {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} + foreach ($_ in $disks) { + $valid_answers += $_.DiskNumber + $menu_setup_disk += "{0}: {1:N0} Gb`t({2}) {3}`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.PartitionStyle, $_.FriendlyName + } + $menu_setup_disk += "`r`n" + $menu_setup_disk += "M: Main Menu`r`n" + $menu_setup_disk += "`r`n" + $menu_setup_disk += "Please make a selection`r`n" + + # Select disk + do { + clear + $answer = read-host -prompt $menu_setup_disk + } until ($valid_answers -contains $answer) + + if ($answer -imatch '^M$') { + # Exit if requested + popd + return + } else { + # Double check before deleting data + $dest_disk = $disks | where {$_.DiskNumber -eq $answer} + wk-warn "All data will be deleted from the following drive:" + wk-warn ("`t{0:N0} Gb`t({1}) {2}`r`n" -f ($dest_disk.Size / 1GB), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (ask ("Proceed and install {0}?" -f $dest_windows_version.Name)) { + wk-warn "SAFTEY CHECK:" + wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) + wk-error (" And ERASING:`tDisk {0} - {1:N0} Gb`t({2}) {3}`r`n" -f $dest_disk.DiskNumber, ($dest_disk.Size / 1GB), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (ask "Is this correct?") { + ## WARNING + wk-warn "WARNING: This section is experimental" + ## WARNING + ## Here be dragons + + try { + # Select UEFI or BIOS + if ($dest_windows_version.Name -match '^Windows 7') { + if (ask "Setup drive using MBR (legacy) layout?") { + format-mbr $dest_disk + } else { + format-gpt $dest_disk + } + } elseif ($dest_windows_version.Name -match '^Windows (8|10)') { + if (ask "Setup drive using GPT (UEFI) layout?") { + format-gpt $dest_disk + } else { + format-mbr $dest_disk + } + } + + # Apply image + apply-image $dest_windows_version.ImageFile $dest_windows_version.Index + + # Create boot files (copies files for both Legacy and UEFI) + bcdboot W:\Windows /s S: /f ALL + if ($dest_windows_version.Name -match '^Windows (8|10)') { + W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows + } + + # Reboot + wk-write "Windows Setup complete." + wk-write "" + return 0 + } catch { + wk-error "$Error" + wk-error "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " + return 1 + } + } else { + wk-error "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " + } + } else { + wk-error "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " + } + } + popd +} +function menu-tools { + wk-write "Misc Tools" + wk-write "" + wk-warn "Be careful." + start "explorer" -argumentlist @("$WKPath\Programs") + wk-exit +} +function menu-main { + $answered = $false + $menu_main = @" +WK WinPE Tools + +1: Drive Imaging +2: Windows Setup +3: Misc Tools + +Q: Quit +R: Reboot +S: Shutdown + +Please make a selection +"@ + + do { + clear + $answer = read-host -prompt $menu_main + } until ($answer -imatch '^[123QRS]$') + clear + + if ($answer.GetType().Name -match "String") { + $answer = $answer.ToUpper() + } + switch ($answer) { + 1 {menu-imaging; break} + 2 {menu-setup; break} + 3 {menu-tools; break} + default {wk-exit} + } +} + +# Main Loop +do { + menu-main +} while ($true) diff --git a/WK/Scripts/init.ps1 b/WK/Scripts/init.ps1 new file mode 100644 index 00000000..6fbb9bcd --- /dev/null +++ b/WK/Scripts/init.ps1 @@ -0,0 +1,48 @@ +# WK-Init +# +# Some common settings and functions + +$host.UI.RawUI.BackgroundColor = "black" +$host.UI.RawUI.ForegroundColor = "green" +$systemdrive = (gci env:systemdrive).value +$WKPath = "$systemdrive\WK" +$date = get-date -uformat "%Y-%m-%d" + +function ask { + param([string]$text = "Kotaero", [string]$log = "WK.log") + $answered = $false + $text += " [Y/N]" + while (!$answered) { + $answer = read-host $text + if ($answer -imatch '^(y|yes)$') { + $answer = $true + $answered = $true + } elseif ($answer -imatch '^(n|no)$') { + $answer = $false + $answered = $true + } + } + $text += ": $answer" + out-file -filepath $log -inputobject $text -append + return $answer +} +function wk-error { + param([string]$text = "ERROR", [string]$log = "WK.log") + write-host ($text) -foreground "red" + out-file -filepath $log -inputobject $text -append +} +function wk-warn { + param([string]$text = "WARNING", [string]$log = "WK.log") + write-host ($text) -foreground "yellow" + out-file -filepath $log -inputobject $text -append +} +function wk-write { + param([string]$text = "", [string]$log = "WK.log") + write-host ($text) + out-file -filepath $log -inputobject $text -append +} +function pause { + param([string]$message = "Press Enter to continue... ") + write-host $message + $x = read-host +} diff --git a/WK/hwmonitorw.ini b/WK/hwmonitorw.ini new file mode 100644 index 00000000..0bfb23e7 --- /dev/null +++ b/WK/hwmonitorw.ini @@ -0,0 +1,7 @@ +[HWMonitor] +VERSION=1.2.8.0 +USE_ACPI=1 +USE_SMBUS=1 +USE_SMART=1 +USE_DISPLAY=1 +UPDATES=0 diff --git a/make-cd.cmd b/make-cd.cmd new file mode 100644 index 00000000..500141fc --- /dev/null +++ b/make-cd.cmd @@ -0,0 +1,34 @@ +@echo off + +:Init +setlocal EnableDelayedExpansion +title WinPE 10 creation tool +color 1b +pushd %~dp0 + +:Flags +for %%f in (%*) do ( + if /i "%%f" == "/DEBUG" (@echo on) +) + +:CreateISO +del winpe10-test.iso +makewinpemedia.cmd /iso wd winpe10-test.iso + +:Abort +echo. +echo Aborted. +goto Exit + +:Done +echo. +echo Done. +goto Exit + +:Exit +echo. +echo Press any key to exit... +pause>nul +popd +color +endlocal \ No newline at end of file diff --git a/make.cmd b/make.cmd new file mode 100644 index 00000000..91af52ab --- /dev/null +++ b/make.cmd @@ -0,0 +1,100 @@ +@echo off + +:Init +setlocal EnableDelayedExpansion +title WinPE 10 creation tool +color 1b +pushd %~dp0 +set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" + + +:Flags +for %%f in (%*) do ( + if /i "%%f" == "/DEBUG" (@echo on) +) + +:CopyPEFiles +call copype.cmd amd64 "%cd%\wd" + +:Mount +rem echo Press any key to configure the WinPE image... +rem pause>nul +mkdir "%cd%\mount" +dism /mount-image /imagefile:"%cd%\wd\media\sources\boot.wim" /index:1 /mountdir:"%cd%\mount" + +:AddPackages +:: More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382(v=vs.85).aspx +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" + +:: Install WinPE-WMI before you install WinPE-NetFX. +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" + +:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting before you install WinPE-PowerShell. +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" + +:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-DismCmdlets. +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" + +:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. +dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" + +:Robocopy +del "%cd%\WK\Scripts\WK.log" +mkdir "%cd%\mount\WK" +robocopy /e "%cd%\WK" "%cd%\mount\WK" + +:MenuLauncher +copy /y "%cd%\System32\menu.cmd" "%cd%\mount\Windows\System32\menu.cmd" + +:ReplaceStartnet +copy /y "%cd%\System32\startnet.cmd" "%cd%\mount\Windows\System32\startnet.cmd" + +:ReplaceNotepad +reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE +reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2.exe /z" /f +reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe" /v Debugger /t REG_SZ /d "X:\WK\Explorer++.exe /z" /f +reg unload HKLM\WinPE-SW + +:Background +takeown /f "%cd%\mount\Windows\System32\winpe.jpg" /a +icacls "%cd%\mount\Windows\System32\winpe.jpg" /grant administrators:F +copy /y "%cd%\System32\winpe.jpg" "%cd%\mount\Windows\System32\winpe.jpg" + +:ManualStuff +echo Now is the time to add stuff (optional). +echo. +echo Press any key to commit changes... +pause>nul + +:Unmount +dism /unmount-image /mountdir:"%cd%\mount" /commit + +:CreateISO +del winpe10-test.iso +makewinpemedia.cmd /iso wd winpe10-test.iso +goto Done + +:Abort +echo. +echo Aborted. +goto Exit + +:Done +echo. +echo Done. +goto Exit + +:Exit +echo. +echo Press any key to exit... +pause>nul +popd +color +endlocal \ No newline at end of file diff --git a/update.cmd b/update.cmd new file mode 100644 index 00000000..03545b77 --- /dev/null +++ b/update.cmd @@ -0,0 +1,100 @@ +@echo off + +:Init +setlocal EnableDelayedExpansion +title WinPE 10 update tool +color 1b +pushd %~dp0 +set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" + + +:Flags +for %%f in (%*) do ( + if /i "%%f" == "/DEBUG" (@echo on) +) + +:CopyPEFiles +rem call copype.cmd amd64 "%cd%\wd" + +:Mount +rem echo Press any key to configure the WinPE image... +rem pause>nul +mkdir "%cd%\mount" +dism /mount-image /imagefile:"%cd%\wd\media\sources\boot.wim" /index:1 /mountdir:"%cd%\mount" + +:AddPackages +rem :: More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382(v=vs.85).aspx +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" + +rem :: Install WinPE-WMI before you install WinPE-NetFX. +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" + +rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting before you install WinPE-PowerShell. +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" + +rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-DismCmdlets. +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" + +rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. +rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" + +:Robocopy +del "%cd%\WK\Scripts\WK.log" +rem mkdir "%cd%\mount\WK" +robocopy /e "%cd%\WK" "%cd%\mount\WK" + +:MenuLauncher +copy /y "%cd%\System32\menu.cmd" "%cd%\mount\Windows\System32\menu.cmd" + +:ReplaceStartnet +copy /y "%cd%\System32\startnet.cmd" "%cd%\mount\Windows\System32\startnet.cmd" + +:ReplaceNotepad +reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE +reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2.exe /z" /f +reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe" /v Debugger /t REG_SZ /d "X:\WK\Explorer++.exe /z" /f +reg unload HKLM\WinPE-SW + +:Background +takeown /f "%cd%\mount\Windows\System32\winpe.jpg" /a +icacls "%cd%\mount\Windows\System32\winpe.jpg" /grant administrators:F +copy /y "%cd%\System32\winpe.jpg" "%cd%\mount\Windows\System32\winpe.jpg" + +:ManualStuff +echo Now is the time to add stuff (optional). +echo. +echo Press any key to commit changes... +pause>nul + +:Unmount +dism /unmount-image /mountdir:"%cd%\mount" /commit + +:CreateISO +del winpe10-test.iso +makewinpemedia.cmd /iso wd winpe10-test.iso +goto Done + +:Abort +echo. +echo Aborted. +goto Exit + +:Done +echo. +echo Done. +goto Exit + +:Exit +echo. +echo Press any key to exit... +pause>nul +popd +color +endlocal \ No newline at end of file From c7b5abb0bcfab1f0c17783d9e5a32a37ff2f906b Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 20:48:55 -0800 Subject: [PATCH 02/85] 2015-12: Retroactive Updates --- WK/Notepad2.ini | 27 ++++------- WK/Scripts/WK.ps1 | 87 +++++++++++++++++++++++++--------- WK/Scripts/init.ps1 | 10 ++-- WK/config.xml | 112 ++++++++++++++++++++++++++++++++++++++++++++ WK/hwmonitorw.ini | 1 + make-cd.cmd | 2 +- make.cmd | 57 ++++++++++++---------- update.cmd | 100 --------------------------------------- 8 files changed, 227 insertions(+), 169 deletions(-) create mode 100644 WK/config.xml delete mode 100644 update.cmd diff --git a/WK/Notepad2.ini b/WK/Notepad2.ini index 6bba42de..4522220d 100644 --- a/WK/Notepad2.ini +++ b/WK/Notepad2.ini @@ -95,7 +95,7 @@ ShellUseSystemMRU=1 15=#B000B0 16=#B28B40 [Styles] -Use2ndDefaultStyle=1 +Use2ndDefaultStyle=0 DefaultScheme=0 AutoSelect=1 SelectDlgSizeX=304 @@ -113,19 +113,12 @@ SelectDlgSizeY=324 2nd Caret (Color, Size 1-3)=fore:#C0C0C0 2nd Long Line Marker (Colors)=fore:#404040 2nd Extra Line Spacing (Size)= -[Window] -1440x900 PosX=600 -1440x900 PosY=16 -1440x900 SizeX=824 -1440x900 SizeY=824 -1440x900 Maximized=1 -1600x900 PosX=756 -1600x900 PosY=16 -1600x900 SizeX=828 -1600x900 SizeY=828 -1600x900 Maximized=1 -800x600 PosX=216 -800x600 PosY=16 -800x600 SizeX=568 -800x600 SizeY=568 -800x600 Maximized=0 \ No newline at end of file +[Recent Files] +01= +02= +[Recent Find] +01= +02= +[Recent Replace] +01= +02= diff --git a/WK/Scripts/WK.ps1 b/WK/Scripts/WK.ps1 index ccfcd28b..9fc55b6b 100644 --- a/WK/Scripts/WK.ps1 +++ b/WK/Scripts/WK.ps1 @@ -154,7 +154,7 @@ function mount-servers { # Mount servers wk-write "Connecting to backup server(s)" foreach ($_server in $backup_servers) { - if (test-connection $_server.ip -count 1 -quiet) { + if (test-connection $_server.ip -count 1 -quiet 2>&1 | out-null) { try { $_path = "\\{0}\{1}" -f $_server.ip, $_server.path $_drive = "{0}:" -f $_server.letter @@ -195,39 +195,79 @@ function menu-imaging { pause ## WARNING + # Check if any source drives were detected + $disks = get-disk | where {$_.Size -ne 0} +# if ($disks.count -eq 0) { +# wk-error "No suitable source drives were detected." +# pause "Press Enter to return to main menu... " $True +# return 1 +# } + # Mount server(s) mount-servers - # Select destination + # Build server menu $avail_servers = @(gdr | where {$_.DisplayRoot -imatch '\\\\'}) - $menu_disc_imaging = "Which drive are we imaging?`r`n`r`n" +# if ($avail_servers.count -eq 0) { +# wk-error "No suitable backup servers were detected." +# pause "Press Enter to return to main menu... " $True +# return 1 +# } + $menu_imaging_server = "Where are we saving the backup image(s)?`r`n`r`n" $valid_answers = @("M", "m") for ($i=0; $i -lt $avail_servers.length; $i++) { $valid_answers += ($i + 1) - $menu_disc_imaging += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) + $menu_imaging_server += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) } - $menu_disc_imaging += "`r`n" - $menu_disc_imaging += "M: Main Menu`r`n" - $menu_disc_imaging += "`r`n" - $menu_disc_imaging += "Please make a selection`r`n" + $menu_imaging_server += "`r`n" + $menu_imaging_server += "M: Main Menu`r`n" + $menu_imaging_server += "`r`n" + $menu_imaging_server += "Please make a selection`r`n" + + # Select server do { - clear - $answer = read-host -prompt $menu_disc_imaging +##testing## clear + $answer = read-host -prompt $menu_imaging_server } until ($valid_answers -contains $answer) if ($answer -imatch '^M$') { # Exit if requested unmount-servers - popd return } else { $answer -= 1 $dest_backup_server = $avail_servers[$answer] } + # Build source menu + $menu_imaging_source = "For which drive are we creating backup image(s)?`r`n`r`n" + $valid_answers = @("M", "m") + foreach ($_ in $disks) { + $valid_answers += $_.DiskNumber + $menu_imaging_source += "{0}: {1:N0} Gb`t({2}) {3} ({4})`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.BusType, $_.FriendlyName, $_.PartitionStyle + } + $menu_imaging_source += "`r`n" + $menu_imaging_source += "M: Main Menu`r`n" + $menu_imaging_source += "`r`n" + $menu_imaging_source += "Please make a selection`r`n" + + # Select source + do { +##testing## clear + $answer = read-host -prompt $menu_imaging_source + } until ($valid_answers -contains $answer) + + if ($answer -imatch '^M$') { + # Exit if requested + return + } else { + ##TODO## + get-volume + } + # Service Order $menu_service_order += "Please enter the service order`r`n" do { - clear +##testing## clear $service_order = read-host -prompt $menu_service_order } until ($service_order -imatch '^\d[\w\-]+$') @@ -242,7 +282,14 @@ function menu-imaging { function menu-setup { wk-write "Windows Setup" wk-write "" - pushd $WKPath\Setup + + # Check if any destination drives were detected + $disks = get-disk | where {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} + if ($disks.count -eq 0) { + wk-error "No suitable destination drives were detected." + pause "Press Enter to return to main menu... " $True + return 1 + } # Build windows menu $windows_versions = @( @@ -267,13 +314,12 @@ function menu-setup { # Select Windows version do { - clear +##testing## clear $answer = read-host -prompt $menu_setup_windows } until ($valid_answers -contains $answer) if ($answer -imatch '^M$') { # Exit if requested - popd return } else { $answer -= 1 @@ -283,7 +329,6 @@ function menu-setup { # Build disk menu $menu_setup_disk = "To which drive are we installing {0}?`r`n`r`n" -f $dest_windows_version.Name $valid_answers = @("M", "m") - $disks = get-disk | where {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} foreach ($_ in $disks) { $valid_answers += $_.DiskNumber $menu_setup_disk += "{0}: {1:N0} Gb`t({2}) {3}`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.PartitionStyle, $_.FriendlyName @@ -295,13 +340,12 @@ function menu-setup { # Select disk do { - clear +##testing## clear $answer = read-host -prompt $menu_setup_disk } until ($valid_answers -contains $answer) if ($answer -imatch '^M$') { # Exit if requested - popd return } else { # Double check before deleting data @@ -365,13 +409,12 @@ function menu-setup { pause "Press Enter to return to main menu... " } } - popd } function menu-tools { wk-write "Misc Tools" wk-write "" wk-warn "Be careful." - start "explorer" -argumentlist @("$WKPath\Programs") + start "$WKPath\explorer++" -argumentlist @("$WKPath") wk-exit } function menu-main { @@ -391,10 +434,10 @@ Please make a selection "@ do { - clear +##testing## clear $answer = read-host -prompt $menu_main } until ($answer -imatch '^[123QRS]$') - clear +##testing## clear if ($answer.GetType().Name -match "String") { $answer = $answer.ToUpper() diff --git a/WK/Scripts/init.ps1 b/WK/Scripts/init.ps1 index 6fbb9bcd..e0065430 100644 --- a/WK/Scripts/init.ps1 +++ b/WK/Scripts/init.ps1 @@ -3,7 +3,7 @@ # Some common settings and functions $host.UI.RawUI.BackgroundColor = "black" -$host.UI.RawUI.ForegroundColor = "green" +$host.UI.RawUI.ForegroundColor = "cyan" $systemdrive = (gci env:systemdrive).value $WKPath = "$systemdrive\WK" $date = get-date -uformat "%Y-%m-%d" @@ -42,7 +42,11 @@ function wk-write { out-file -filepath $log -inputobject $text -append } function pause { - param([string]$message = "Press Enter to continue... ") - write-host $message + param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) + if ($warning) { + write-host ($message) -foreground "yellow" + } else { + write-host ($message) + } $x = read-host } diff --git a/WK/config.xml b/WK/config.xml new file mode 100644 index 00000000..90a19145 --- /dev/null +++ b/WK/config.xml @@ -0,0 +1,112 @@ + + + + + yes + no + yes + yes + no + yes + no + no + + + + + 90 + yes + no + no + no + no + no + no + 0 + yes + 9 + no + 0 + yes + no + ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} + no + 500 + yes + yes + 1 + yes + no + no + no + yes + yes + yes + yes + no + yes + no + yes + yes + yes + no + yes + yes + no + yes + yes + yes + 1 + yes + 1 + yes + no + no + + no + 208 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/hwmonitorw.ini b/WK/hwmonitorw.ini index 0bfb23e7..e3978b4e 100644 --- a/WK/hwmonitorw.ini +++ b/WK/hwmonitorw.ini @@ -4,4 +4,5 @@ USE_ACPI=1 USE_SMBUS=1 USE_SMART=1 USE_DISPLAY=1 +CPU_0_TJMAX=100.0 UPDATES=0 diff --git a/make-cd.cmd b/make-cd.cmd index 500141fc..885ba639 100644 --- a/make-cd.cmd +++ b/make-cd.cmd @@ -13,7 +13,7 @@ for %%f in (%*) do ( :CreateISO del winpe10-test.iso -makewinpemedia.cmd /iso wd winpe10-test.iso +makewinpemedia.cmd /iso pe_files winpe10-test.iso :Abort echo. diff --git a/make.cmd b/make.cmd index 91af52ab..29afdf3a 100644 --- a/make.cmd +++ b/make.cmd @@ -5,6 +5,7 @@ setlocal EnableDelayedExpansion title WinPE 10 creation tool color 1b pushd %~dp0 +set "wd=%cd%" set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" @@ -14,58 +15,62 @@ for %%f in (%*) do ( ) :CopyPEFiles -call copype.cmd amd64 "%cd%\wd" +call copype.cmd amd64 "%wd%\pe_files" :Mount rem echo Press any key to configure the WinPE image... rem pause>nul -mkdir "%cd%\mount" -dism /mount-image /imagefile:"%cd%\wd\media\sources\boot.wim" /index:1 /mountdir:"%cd%\mount" +mkdir "%wd%\mount" +dism /mount-image /imagefile:"%wd%\pe_files\media\sources\boot.wim" /index:1 /mountdir:"%wd%\mount" :AddPackages +mkdir "%wd%\log" + :: More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382(v=vs.85).aspx -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" /logpath:"dism.log" :: Install WinPE-WMI before you install WinPE-NetFX. -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" + +:: Install WinPE-WMI > WinPE-NetFX before you install WinPE-Scripting. +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting before you install WinPE-PowerShell. -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-DismCmdlets. -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. -dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" :Robocopy -del "%cd%\WK\Scripts\WK.log" -mkdir "%cd%\mount\WK" -robocopy /e "%cd%\WK" "%cd%\mount\WK" +del "%wd%\WK\Scripts\WK.log" +mkdir "%wd%\mount\WK" +robocopy /e "%wd%\WK" "%wd%\mount\WK" +mklink "%wd%\mount\System32\explorer.exe" "%wd%\mount\WK\Explorer++.exe" :MenuLauncher -copy /y "%cd%\System32\menu.cmd" "%cd%\mount\Windows\System32\menu.cmd" +copy /y "%wd%\System32\menu.cmd" "%wd%\mount\Windows\System32\menu.cmd" :ReplaceStartnet -copy /y "%cd%\System32\startnet.cmd" "%cd%\mount\Windows\System32\startnet.cmd" +copy /y "%wd%\System32\startnet.cmd" "%wd%\mount\Windows\System32\startnet.cmd" :ReplaceNotepad reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2.exe /z" /f -reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe" /v Debugger /t REG_SZ /d "X:\WK\Explorer++.exe /z" /f reg unload HKLM\WinPE-SW :Background -takeown /f "%cd%\mount\Windows\System32\winpe.jpg" /a -icacls "%cd%\mount\Windows\System32\winpe.jpg" /grant administrators:F -copy /y "%cd%\System32\winpe.jpg" "%cd%\mount\Windows\System32\winpe.jpg" +takeown /f "%wd%\mount\Windows\System32\winpe.jpg" /a +icacls "%wd%\mount\Windows\System32\winpe.jpg" /grant administrators:F +copy /y "%wd%\System32\winpe.jpg" "%wd%\mount\Windows\System32\winpe.jpg" :ManualStuff echo Now is the time to add stuff (optional). @@ -74,11 +79,11 @@ echo Press any key to commit changes... pause>nul :Unmount -dism /unmount-image /mountdir:"%cd%\mount" /commit +dism /unmount-image /mountdir:"%wd%\mount" /commit :CreateISO del winpe10-test.iso -makewinpemedia.cmd /iso wd winpe10-test.iso +makewinpemedia.cmd /iso "%wd%\pe_files" winpe10-test.iso goto Done :Abort diff --git a/update.cmd b/update.cmd deleted file mode 100644 index 03545b77..00000000 --- a/update.cmd +++ /dev/null @@ -1,100 +0,0 @@ -@echo off - -:Init -setlocal EnableDelayedExpansion -title WinPE 10 update tool -color 1b -pushd %~dp0 -set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" - - -:Flags -for %%f in (%*) do ( - if /i "%%f" == "/DEBUG" (@echo on) -) - -:CopyPEFiles -rem call copype.cmd amd64 "%cd%\wd" - -:Mount -rem echo Press any key to configure the WinPE image... -rem pause>nul -mkdir "%cd%\mount" -dism /mount-image /imagefile:"%cd%\wd\media\sources\boot.wim" /index:1 /mountdir:"%cd%\mount" - -:AddPackages -rem :: More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382(v=vs.85).aspx -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" - -rem :: Install WinPE-WMI before you install WinPE-NetFX. -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" - -rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting before you install WinPE-PowerShell. -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" - -rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-DismCmdlets. -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" - -rem :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. -rem dism /add-package /image:"%cd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" - -:Robocopy -del "%cd%\WK\Scripts\WK.log" -rem mkdir "%cd%\mount\WK" -robocopy /e "%cd%\WK" "%cd%\mount\WK" - -:MenuLauncher -copy /y "%cd%\System32\menu.cmd" "%cd%\mount\Windows\System32\menu.cmd" - -:ReplaceStartnet -copy /y "%cd%\System32\startnet.cmd" "%cd%\mount\Windows\System32\startnet.cmd" - -:ReplaceNotepad -reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE -reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2.exe /z" /f -reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe" /v Debugger /t REG_SZ /d "X:\WK\Explorer++.exe /z" /f -reg unload HKLM\WinPE-SW - -:Background -takeown /f "%cd%\mount\Windows\System32\winpe.jpg" /a -icacls "%cd%\mount\Windows\System32\winpe.jpg" /grant administrators:F -copy /y "%cd%\System32\winpe.jpg" "%cd%\mount\Windows\System32\winpe.jpg" - -:ManualStuff -echo Now is the time to add stuff (optional). -echo. -echo Press any key to commit changes... -pause>nul - -:Unmount -dism /unmount-image /mountdir:"%cd%\mount" /commit - -:CreateISO -del winpe10-test.iso -makewinpemedia.cmd /iso wd winpe10-test.iso -goto Done - -:Abort -echo. -echo Aborted. -goto Exit - -:Done -echo. -echo Done. -goto Exit - -:Exit -echo. -echo Press any key to exit... -pause>nul -popd -color -endlocal \ No newline at end of file From 41272c03ab7487f565793946c26c94d6f1b8f15a Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 20:50:41 -0800 Subject: [PATCH 03/85] 2016-01: Retroactive Updates --- LICENSE.txt | 2 +- System32/menu.cmd | 8 +- System32/startnet.cmd | 1 + WK/Scripts/WK.ps1 | 332 +++++++++++++++++++++++++++++------------- WK/Scripts/init.ps1 | 15 ++ make.cmd | 16 +- 6 files changed, 263 insertions(+), 111 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index a401a44d..3d52e4c5 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2015 Alan Mason +Copyright (c) 2016 Alan Mason Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/System32/menu.cmd b/System32/menu.cmd index ca826073..2de98847 100644 --- a/System32/menu.cmd +++ b/System32/menu.cmd @@ -3,7 +3,7 @@ :Init setlocal EnableDelayedExpansion title Menu Launcher -color 0a +color 0b pushd %~dp0 :Flags @@ -30,5 +30,7 @@ echo. rem echo Press any key to exit... rem pause>nul popd -color -endlocal \ No newline at end of file +endlocal +cls +echo Careful now... +echo. \ No newline at end of file diff --git a/System32/startnet.cmd b/System32/startnet.cmd index c97c37be..45186f05 100644 --- a/System32/startnet.cmd +++ b/System32/startnet.cmd @@ -1,5 +1,6 @@ @echo off +color 0b echo Initializing... wpeinit wpeutil updatebootinfo diff --git a/WK/Scripts/WK.ps1 b/WK/Scripts/WK.ps1 index 9fc55b6b..e0633612 100644 --- a/WK/Scripts/WK.ps1 +++ b/WK/Scripts/WK.ps1 @@ -7,7 +7,7 @@ pushd "$wd" clear $host.UI.RawUI.WindowTitle = "WK PE Tool" $logpath = "$WKPath\Info\$date" -md "$logpath" 2>&1 | out-null +md "$logpath" 2>&1 | Out-Null $log = "$logpath\winpe.log" $source_server = "10.0.0.10" $backup_servers = @( @@ -20,23 +20,23 @@ $backup_servers = @( "letter"="Y"; "path"="Backups"} ) -$backup_user = "WORKGROUP\backup" +$backup_user = "backup" $backup_pass = "Abracadabra" # Functions function apply-image { - param([string]$image, [int]$index) + Param([string]$image, [int]$index) $path = "" $split_image = $false $split_image_pattern = "" # Check for local source - $volumes = get-volume | where {$_.Size -ne 0 -and $_.DriveLetter -match '^[C-Z]$'} + $volumes = Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -match '^[C-Z]$'} foreach ($v in $volumes) { $letter = $v.DriveLetter + ":" - if (test-path "$letter\sources\$image.wim") { + if (Test-Path "$letter\sources\$image.wim") { $path = "$letter\sources\$image.wim" - } elseif (test-path "$letter\sources\$image.swm") { + } elseif (Test-Path "$letter\sources\$image.swm") { $path = "$letter\sources\$image.swm" $split_image = $true $split_image_pattern = "$letter\sources\$image*.swm" @@ -46,9 +46,9 @@ function apply-image { # Check for remote source (if necessary) if ($path -match '^$') { net use z: "\\$source_server\Windows" /user:guest notarealpassword - if (test-path "Z:\$image.wim") { + if (Test-Path "Z:\$image.wim") { $path = "Z:\$image.wim" - } elseif (test-path "Z:\$image.swm") { + } elseif (Test-Path "Z:\$image.swm") { $path = "Z:\$image.swm" } } @@ -65,7 +65,7 @@ function apply-image { net use z: /delete } function format-gpt { - param($dest_disk) + Param($dest_disk) wk-write "Drive will use a GPT (UEFI) layout." # Double-check we have the right drive @@ -77,9 +77,9 @@ function format-gpt { } $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber $diskpart_script += "uniqueid disk" - out-file -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - start "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | out-null - if (!(Get-Content "$wd\drive_uid" | where {$_ -imatch $_sel_uid})) { + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null + if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { # GUIDs do not match wk-error "Diskpart failed to select the same disk for formatting, aborting setup." wk-warn "This system requires manual formatting & setup" @@ -122,16 +122,16 @@ function format-gpt { $diskpart_script += "assign letter='W'`r`n" # Run script - out-file -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - start "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow } function format-mbr { - param($dest_disk) + Param($dest_disk) wk-write "Drive will use a MBR (legacy) layout." if ($dest_disk.PartitionStyle -notmatch '^RAW$') { # Only clean if necessary - clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false + Clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false } Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true @@ -139,6 +139,120 @@ function format-mbr { Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' } +function select-disk { + $_skipped_parts = 0 + # Check if any source drives were detected + $disks = Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number" + if ($disks.count -eq 0) { + wk-error "No suitable source drives were detected." + return $false + } elseif ($disks.count -eq $null) { + # Assuming only one disk is available + $answer = $disks.DiskNumber + } else { + # Build source menu + $menu_imaging_source = "For which drive are we creating backup image(s)?`r`n`r`n" + $valid_answers = @("M", "m") + foreach ($_ in $disks) { + $valid_answers += $_.DiskNumber + $menu_imaging_source += "{0}: {1,4:N0} Gb`t[{2}] ({3}) {4}`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.PartitionStyle, $_.BusType, $_.FriendlyName + } + $menu_imaging_source += "`r`n" + $menu_imaging_source += "M: Main Menu`r`n" + $menu_imaging_source += "`r`n" + $menu_imaging_source += "Please make a selection`r`n" + + # Select source + do { + clear + $answer = read-host -prompt $menu_imaging_source + } until ($valid_answers -contains $answer) + } + + if ($answer -imatch '^\d+$') { + # Valid disk selected + clear + $_d = Get-Disk -number $answer + $_disk_details = "Disk:`t{0,4:N0} Gb`t[{1}] ({2}) {3}" -f ($_d.Size / 1GB), $_d.PartitionStyle, $_d.BusType, $_d.FriendlyName + wk-write "$_disk_details" + wk-write "Partition(s):" + + # Print partition info + $partitions = Get-Partition -DiskNumber $_d.DiskNumber + foreach ($_p in $partitions) { + # Assign letter + Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null + + # Update partition info + $_p = Get-Partition -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber + $_v = Get-Volume -Partition $_p + + # Set size label + $_size = (human-size $_p.size 0) + if ($_v -ne $null) { + $_used = (human-size ($_v.Size - $_v.SizeRemaining) 0) + } + + # Print partition info + if ($_p.AccessPaths -eq $null) { + # No drive letter + $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type + wk-error "$_msg" + $_skipped_parts += 1 + } else { + # Has drive letter + $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + $_label = " {0}" -f $_p.Type + if ($_v -and $_v.FileSystemLabel -ne "") { + $_label = '"{0}"' -f $_v.FileSystemLabel + } + $_msg = " {0:N0}:`t{1} ({2,6}) {3} ({4} used)" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used + wk-write "$_msg" + } + } + if ($_skipped_parts -gt 0) { + wk-warn " *`tUnable to backup these partition(s)" + } + wk-write "" + if (ask " Backup these partition(s)?") { + return $_d + } else { + return $false + } + } + + return $answer +} +function select-server { + # Build server menu + $avail_servers = @(gdr | Where-Object {$_.DisplayRoot -imatch '\\\\'}) + if ($avail_servers.count -eq 0) { + wk-error "No suitable backup servers were detected." + return $false + } + $menu_imaging_server = "Where are we saving the backup image(s)?`r`n`r`n" + $valid_answers = @("M", "m") + for ($i=0; $i -lt $avail_servers.length; $i++) { + $valid_answers += ($i + 1) + $menu_imaging_server += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) + } + $menu_imaging_server += "`r`n" + $menu_imaging_server += "M: Main Menu`r`n" + $menu_imaging_server += "`r`n" + $menu_imaging_server += "Please make a selection`r`n" + + # Select server + do { +# clear + $answer = read-host -prompt $menu_imaging_server + } until ($valid_answers -contains $answer) + + if ($answer -imatch '^\d+$') { + $answer -= 1 + return $avail_servers[$answer] + } + return $answer +} function wk-exit { popd if ($answer -match 'R') { @@ -154,35 +268,37 @@ function mount-servers { # Mount servers wk-write "Connecting to backup server(s)" foreach ($_server in $backup_servers) { - if (test-connection $_server.ip -count 1 -quiet 2>&1 | out-null) { + if (test-connection $_server.ip -count 3 -quiet) { try { $_path = "\\{0}\{1}" -f $_server.ip, $_server.path $_drive = "{0}:" -f $_server.letter - net use $_drive "$_path" /user:$backup_user $backup_pass | out-null + net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null wk-write ("`t{0} server: mounted" -f $_server.name) # Add friendly description $_regex = "^{0}$" -f $_server.letter - (gdr | where {$_.Name -imatch $_regex}).Description = $_server.name + (gdr | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name } catch { wk-warn ("`t{0} server: failed" -f $_server.name) } } else { - wk-warn ("`t{0} server: unreachable" -f $_server.name) + wk-warn ("`t{0} server: timed-out" -f $_server.name) } } } function unmount-servers { # Unmount servers wk-write "Disconnecting from backup server(s)" - $mounted_servers = @(gdr | where {$_.DisplayRoot -imatch '\\\\'}) + $mounted_servers = @(gdr | Where-Object {$_.DisplayRoot -imatch '\\\\'}) foreach ($_server in $mounted_servers) { try { $_drive = "{0}:" -f $_server.Name - net use $_drive /delete | out-null - wk-warn ("`t{0} server: unmounted" -f $_server.name) + net use $_drive /delete | Out-Null + #wk-warn ("`t{0} server: unmounted" -f $_server.name) + wk-warn "`tServer: unmounted" } catch { - wk-warn ("`t{0} server: failed" -f $_server.name) + #wk-warn ("`t{0} server: failed" -f $_server.name) + wk-warn "`tServer: failed" } } } @@ -194,86 +310,92 @@ function menu-imaging { wk-warn "WARNING: This section is experimental" pause ## WARNING - - # Check if any source drives were detected - $disks = get-disk | where {$_.Size -ne 0} -# if ($disks.count -eq 0) { -# wk-error "No suitable source drives were detected." -# pause "Press Enter to return to main menu... " $True -# return 1 -# } + + # Service Order + $menu_service_order += "Please enter the service order`r`n" + do { + clear + $service_order = read-host -prompt $menu_service_order + } until ($service_order -imatch '^\d[\w\-]+$') + + # Select Disk + $disk = select-disk + if (!($disk)) { + # No drives detected or user aborted + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " + return $false + } elseif ($disk -imatch '^M$') { + # User selected to return to the menu + return + } + wk-write "" # Mount server(s) mount-servers - # Build server menu - $avail_servers = @(gdr | where {$_.DisplayRoot -imatch '\\\\'}) -# if ($avail_servers.count -eq 0) { -# wk-error "No suitable backup servers were detected." -# pause "Press Enter to return to main menu... " $True -# return 1 -# } - $menu_imaging_server = "Where are we saving the backup image(s)?`r`n`r`n" - $valid_answers = @("M", "m") - for ($i=0; $i -lt $avail_servers.length; $i++) { - $valid_answers += ($i + 1) - $menu_imaging_server += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) - } - $menu_imaging_server += "`r`n" - $menu_imaging_server += "M: Main Menu`r`n" - $menu_imaging_server += "`r`n" - $menu_imaging_server += "Please make a selection`r`n" - - # Select server - do { -##testing## clear - $answer = read-host -prompt $menu_imaging_server - } until ($valid_answers -contains $answer) - if ($answer -imatch '^M$') { - # Exit if requested - unmount-servers + # Select Server + $server = select-server + if (!($server)) { + # No servers detected + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " + return $false + } elseif ($server -imatch '^M$') { + # User selected to return to the menu return - } else { - $answer -= 1 - $dest_backup_server = $avail_servers[$answer] } - - # Build source menu - $menu_imaging_source = "For which drive are we creating backup image(s)?`r`n`r`n" - $valid_answers = @("M", "m") - foreach ($_ in $disks) { - $valid_answers += $_.DiskNumber - $menu_imaging_source += "{0}: {1:N0} Gb`t({2}) {3} ({4})`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.BusType, $_.FriendlyName, $_.PartitionStyle - } - $menu_imaging_source += "`r`n" - $menu_imaging_source += "M: Main Menu`r`n" - $menu_imaging_source += "`r`n" - $menu_imaging_source += "Please make a selection`r`n" - - # Select source - do { -##testing## clear - $answer = read-host -prompt $menu_imaging_source - } until ($valid_answers -contains $answer) - - if ($answer -imatch '^M$') { - # Exit if requested - return - } else { - ##TODO## - get-volume - } - - # Service Order - $menu_service_order += "Please enter the service order`r`n" - do { -##testing## clear - $service_order = read-host -prompt $menu_service_order - } until ($service_order -imatch '^\d[\w\-]+$') + wk-write "" + wk-write ("Saving partition backups to: {0}" -f $server.Description) + wk-write "" # Backup partitions - wk-write ("Saving partition backups to: {0}" -f $dest_backup_server.Description) - wk-write ("`t{0}{1}" -f $dest_backup_server.Root, $service_order) + $partitions = Get-Partition -DiskNumber $disk.DiskNumber + foreach ($_p in $partitions) { + $_v = Get-Volume -Partition $_p + + $_name = "{0}" -f $_p.PartitionNumber + if ($_v -and $_v.FileSystemLabel -ne "") { + $_name += "_{0}" -f $_v.FileSystemLabel + } else { + $_name += "_{0}" -f $_p.Type + } + + $_imagepath = "{0}{1}" -f $server.Root, $service_order + $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name + + if ($_p.AccessPaths -ne $null) { + $_capturepath = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + + # Take image + wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) + if (!(Test-Path "$_imagepath")) { + mkdir "$_imagepath" | out-null + } + New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturepath" -Name "$_name" -CompressionType "fast" | out-null + + # Verify image + ## Code borrowed from: https://stackoverflow/a/10262275 + $pinfo = New-Object System.Diagnostics.ProcessStartInfo + $pinfo.FileName = "$WKPath\7z.exe" + $pinfo.RedirectStandardError = $true + $pinfo.RedirectStandardOutput = $true + $pinfo.UseShellExecute = $false + $pinfo.Arguments = 't "{0}"' -f $_imagefile + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $pinfo + $p.Start() | Out-Null + write-host " Verifying . . . " -NoNewline + $p.WaitForExit() + if ($p.ExitCode -eq 0) { + write-host "Complete." -foreground "green" + } else { + write-host "Failed." -foreground "red" + } + } + } # Unmount server(s) unmount-servers @@ -284,11 +406,11 @@ function menu-setup { wk-write "" # Check if any destination drives were detected - $disks = get-disk | where {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} + $disks = Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} if ($disks.count -eq 0) { wk-error "No suitable destination drives were detected." pause "Press Enter to return to main menu... " $True - return 1 + return $false } # Build windows menu @@ -314,7 +436,7 @@ function menu-setup { # Select Windows version do { -##testing## clear + clear $answer = read-host -prompt $menu_setup_windows } until ($valid_answers -contains $answer) @@ -340,7 +462,7 @@ function menu-setup { # Select disk do { -##testing## clear + clear $answer = read-host -prompt $menu_setup_disk } until ($valid_answers -contains $answer) @@ -349,7 +471,7 @@ function menu-setup { return } else { # Double check before deleting data - $dest_disk = $disks | where {$_.DiskNumber -eq $answer} + $dest_disk = $disks | Where-Object {$_.DiskNumber -eq $answer} wk-warn "All data will be deleted from the following drive:" wk-warn ("`t{0:N0} Gb`t({1}) {2}`r`n" -f ($dest_disk.Size / 1GB), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) if (ask ("Proceed and install {0}?" -f $dest_windows_version.Name)) { @@ -396,7 +518,7 @@ function menu-setup { wk-error "Windows Setup aborted." wk-write "" pause "Press Enter to return to main menu... " - return 1 + return $false } } else { wk-error "Windows Setup aborted." @@ -414,7 +536,7 @@ function menu-tools { wk-write "Misc Tools" wk-write "" wk-warn "Be careful." - start "$WKPath\explorer++" -argumentlist @("$WKPath") + Start-Process "$WKPath\explorer++" -argumentlist @("$WKPath") wk-exit } function menu-main { @@ -434,10 +556,10 @@ Please make a selection "@ do { -##testing## clear + clear $answer = read-host -prompt $menu_main } until ($answer -imatch '^[123QRS]$') -##testing## clear + clear if ($answer.GetType().Name -match "String") { $answer = $answer.ToUpper() diff --git a/WK/Scripts/init.ps1 b/WK/Scripts/init.ps1 index e0065430..009b756b 100644 --- a/WK/Scripts/init.ps1 +++ b/WK/Scripts/init.ps1 @@ -41,6 +41,21 @@ function wk-write { write-host ($text) out-file -filepath $log -inputobject $text -append } +function human-size { + param($bytes, [int]$decimals = 2) + if ($bytes -gt 1Tb) { + $size = "{0:N$decimals} Tb" -f ($bytes / 1Tb) + } elseif ($bytes -gt 1Gb) { + $size = "{0:N$decimals} Gb" -f ($bytes / 1Gb) + } elseif ($bytes -gt 1Mb) { + $size = "{0:N$decimals} Mb" -f ($bytes / 1Mb) + } elseif ($bytes -gt 1Kb) { + $size = "{0:N$decimals} Kb" -f ($bytes / 1Kb) + } else { + $size = "{0:N$decimals} b" -f $bytes + } + return $size +} function pause { param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) if ($warning) { diff --git a/make.cmd b/make.cmd index 29afdf3a..01dc5421 100644 --- a/make.cmd +++ b/make.cmd @@ -50,6 +50,14 @@ dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Dism :: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" +:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-StorageWMI. +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-StorageWMI.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" + +:: Install ?? before you install WinPE-EnhancedStorage. +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-EnhancedStorage.cab" /logpath:"dism.log" +dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-EnhancedStorage_en-us.cab" /logpath:"dism.log" + :Robocopy del "%wd%\WK\Scripts\WK.log" mkdir "%wd%\mount\WK" @@ -78,12 +86,16 @@ echo. echo Press any key to commit changes... pause>nul +:Set-ScratchSpace +rem Force RamDisk size to try and avoid capture-image errors +dism /image:"%wd%\mount" /set-scratchspace:512 + :Unmount dism /unmount-image /mountdir:"%wd%\mount" /commit :CreateISO -del winpe10-test.iso -makewinpemedia.cmd /iso "%wd%\pe_files" winpe10-test.iso +del winpe10-2016.iso +makewinpemedia.cmd /iso "%wd%\pe_files" winpe10-2016.iso goto Done :Abort From 4ed08ebb9b617a3a21e418e418941d10a03ebf85 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 20:54:40 -0800 Subject: [PATCH 04/85] 2016-02: Retroactive Updates --- System32/Winpeshl.ini | 5 + System32/menu.cmd | 9 +- WK/ConEmu/ConEmu.xml | 643 ++++++++++++++++++++++++++++++ WK/{ => Explorer++}/config.xml | 3 +- WK/FastCopy.ini | 165 -------- WK/{ => HWMonitor}/hwmonitorw.ini | 0 WK/{ => Notepad2}/Notepad2.ini | 0 WK/Scripts/WK.ps1 | 631 ++++------------------------- WK/Scripts/imaging.ps1 | 463 +++++++++++++++++++++ WK/Scripts/init.ps1 | 91 +++++ WK/Scripts/servers.ps1 | 85 ++++ make-cd.cmd | 7 +- make.cmd | 37 +- 13 files changed, 1399 insertions(+), 740 deletions(-) create mode 100644 System32/Winpeshl.ini create mode 100644 WK/ConEmu/ConEmu.xml rename WK/{ => Explorer++}/config.xml (95%) delete mode 100644 WK/FastCopy.ini rename WK/{ => HWMonitor}/hwmonitorw.ini (100%) rename WK/{ => Notepad2}/Notepad2.ini (100%) create mode 100644 WK/Scripts/imaging.ps1 create mode 100644 WK/Scripts/servers.ps1 diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini new file mode 100644 index 00000000..313d0a7b --- /dev/null +++ b/System32/Winpeshl.ini @@ -0,0 +1,5 @@ +[LaunchApp] +[LaunchApps] +wpeinit +wpeutil updatebootinfo +"%SystemDrive%\WK\ConEmu\ConEmu64.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n \ No newline at end of file diff --git a/System32/menu.cmd b/System32/menu.cmd index 2de98847..eb9c80be 100644 --- a/System32/menu.cmd +++ b/System32/menu.cmd @@ -12,7 +12,7 @@ for %%f in (%*) do ( ) :LaunchMenu -PowerShell -ExecutionPolicy Bypass %systemdrive%\WK\Scripts\WK.ps1 +"%SystemDrive%\WK\ConEmu\ConEmu64.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n goto Done :Abort @@ -27,10 +27,5 @@ goto Exit :Exit echo. -rem echo Press any key to exit... -rem pause>nul popd -endlocal -cls -echo Careful now... -echo. \ No newline at end of file +endlocal \ No newline at end of file diff --git a/WK/ConEmu/ConEmu.xml b/WK/ConEmu/ConEmu.xml new file mode 100644 index 00000000..26a3611c --- /dev/null +++ b/WK/ConEmu/ConEmu.xml @@ -0,0 +1,643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/config.xml b/WK/Explorer++/config.xml similarity index 95% rename from WK/config.xml rename to WK/Explorer++/config.xml index 90a19145..342f0de4 100644 --- a/WK/config.xml +++ b/WK/Explorer++/config.xml @@ -68,7 +68,7 @@ 4 - + @@ -108,5 +108,6 @@ + diff --git a/WK/FastCopy.ini b/WK/FastCopy.ini deleted file mode 100644 index 62517176..00000000 --- a/WK/FastCopy.ini +++ /dev/null @@ -1,165 +0,0 @@ -[main] -bufsize="128" -max_transize="16" -nonbuf_minsize_ntfs2="64" -nonbuf_minsize_fat="128" -is_readosbuf="0" -max_history="10" -default_copy_mode="1" -skip_empty_dir="1" -ignore_error="1" -estimate_mode="0" -disk_mode="0" -is_toplevel="0" -is_errlog="1" -is_utf8log="1" -filelog_mode="0" -aclerr_log="0" -streamerr_log="0" -is_samedir_rename="1" -shext_autoclose="1" -shext_tasktray="0" -shext_dd_noconfirm="0" -shext_right_noconfirm="0" -exec_confirm="0" -force_start="0" -lcid="-1" -speed_level="11" -overwrite_del="0" -acl="0" -stream="0" -verify="0" -nsa_del="0" -deldir_with_filter="0" -move_attr="0" -serial_move="0" -serial_verify_move="0" -reparse2="1" -extend_filter="0" -taskbarMode="0" -infoSpan="2" -win_pos="-10000,-10000,-10000,-10000" -driveMap="" -[src_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[dst_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[del_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[include_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[exclude_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[fromdate_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[todate_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[minsize_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[maxsize_history] -0="" -1="" -2="" -3="" -4="" -5="" -6="" -7="" -8="" -9="" -[finaction_0] -title="Normal" -sound="" -cmd="" -shutdown_time="-1" -flags="1" -[finaction_1] -title="Standby" -sound="" -cmd="" -shutdown_time="60" -flags="65" -[finaction_2] -title="Hibernate" -sound="" -cmd="" -shutdown_time="60" -flags="129" -[finaction_3] -title="Shutdown" -sound="" -cmd="" -shutdown_time="60" -flags="257" diff --git a/WK/hwmonitorw.ini b/WK/HWMonitor/hwmonitorw.ini similarity index 100% rename from WK/hwmonitorw.ini rename to WK/HWMonitor/hwmonitorw.ini diff --git a/WK/Notepad2.ini b/WK/Notepad2/Notepad2.ini similarity index 100% rename from WK/Notepad2.ini rename to WK/Notepad2/Notepad2.ini diff --git a/WK/Scripts/WK.ps1 b/WK/Scripts/WK.ps1 index e0633612..f39f397c 100644 --- a/WK/Scripts/WK.ps1 +++ b/WK/Scripts/WK.ps1 @@ -4,571 +4,100 @@ $wd = $(Split-Path $MyInvocation.MyCommand.Path) pushd "$wd" . .\init.ps1 +. .\servers.ps1 +. .\imaging.ps1 clear $host.UI.RawUI.WindowTitle = "WK PE Tool" $logpath = "$WKPath\Info\$date" md "$logpath" 2>&1 | Out-Null $log = "$logpath\winpe.log" -$source_server = "10.0.0.10" -$backup_servers = @( - @{ "ip"="10.0.0.10"; - "letter"="Z"; - "name"="ServerOne"; - "path"="Backups"}, - @{ "ip"="10.0.0.11"; - "name"="ServerTwo"; - "letter"="Y"; - "path"="Backups"} - ) -$backup_user = "backup" -$backup_pass = "Abracadabra" # Functions -function apply-image { - Param([string]$image, [int]$index) - $path = "" - $split_image = $false - $split_image_pattern = "" - - # Check for local source - $volumes = Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -match '^[C-Z]$'} - foreach ($v in $volumes) { - $letter = $v.DriveLetter + ":" - if (Test-Path "$letter\sources\$image.wim") { - $path = "$letter\sources\$image.wim" - } elseif (Test-Path "$letter\sources\$image.swm") { - $path = "$letter\sources\$image.swm" - $split_image = $true - $split_image_pattern = "$letter\sources\$image*.swm" - } - } - - # Check for remote source (if necessary) - if ($path -match '^$') { - net use z: "\\$source_server\Windows" /user:guest notarealpassword - if (Test-Path "Z:\$image.wim") { - $path = "Z:\$image.wim" - } elseif (Test-Path "Z:\$image.swm") { - $path = "Z:\$image.swm" - } - } - - # Expand Image - if ($path -match '\.wim$') { - Expand-WindowsImage -ImagePath "$path" -Index $index -ApplyPath 'W:\' - } elseif ($path -match '\.swm$') { - Expand-WindowsImage -ImagePath "$path" -Index $index -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" - } else { - net use z: /delete - throw "Source image not found." - } - net use z: /delete -} -function format-gpt { - Param($dest_disk) - wk-write "Drive will use a GPT (UEFI) layout." - - # Double-check we have the right drive - ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets - $_sel_uid = $dest_disk.Guid - if ($dest_disk.PartitionStyle -imatch "MBR") { - # MBR disks don't have GUIDs and use the signature in hex instead - $_sel_uid = "{0:x}" -f $dest_disk.Signature - } - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "uniqueid disk" - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null - if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { - # GUIDs do not match - wk-error "Diskpart failed to select the same disk for formatting, aborting setup." - wk-warn "This system requires manual formatting & setup" - wk-write "" - throw "Failed to format disk" - } else { - wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) - } - - # Generate Diskpart script and execute - ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: - ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d - ## - ## NOTE 2: This overwrites existing diskpart.script file without confirmation. - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "clean`r`n" - $diskpart_script += "convert gpt`r`n" - - # 1. Windows RE tools partition (Windows 8+) - if ($dest_windows_version.Name -match '^Windows (8|10)') { - $diskpart_script += "create partition primary size=300`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" - $diskpart_script += "assign letter='T'`r`n" - $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" - $diskpart_script += "gpt attributes=0x8000000000000001`r`n" - } - - # 2. System partition - $diskpart_script += "create partition efi size=260`r`n" - ## NOTE: Allows for Advanced Format 4Kn drives - $diskpart_script += "format quick fs=fat32 label='System'`r`n" - $diskpart_script += "assign letter='S'`r`n" - - # 3. Microsoft Reserved (MSR) partition - $diskpart_script += "create partition msr size=128`r`n" - - # 4. Windows partition - $diskpart_script += "create partition primary`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" - $diskpart_script += "assign letter='W'`r`n" - - # Run script - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -} -function format-mbr { - Param($dest_disk) - wk-write "Drive will use a MBR (legacy) layout." - - if ($dest_disk.PartitionStyle -notmatch '^RAW$') { - # Only clean if necessary - Clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false - } - Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' - New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true - New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false - Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' - Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' -} -function select-disk { - $_skipped_parts = 0 - # Check if any source drives were detected - $disks = Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number" - if ($disks.count -eq 0) { - wk-error "No suitable source drives were detected." - return $false - } elseif ($disks.count -eq $null) { - # Assuming only one disk is available - $answer = $disks.DiskNumber - } else { - # Build source menu - $menu_imaging_source = "For which drive are we creating backup image(s)?`r`n`r`n" - $valid_answers = @("M", "m") - foreach ($_ in $disks) { - $valid_answers += $_.DiskNumber - $menu_imaging_source += "{0}: {1,4:N0} Gb`t[{2}] ({3}) {4}`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.PartitionStyle, $_.BusType, $_.FriendlyName - } - $menu_imaging_source += "`r`n" - $menu_imaging_source += "M: Main Menu`r`n" - $menu_imaging_source += "`r`n" - $menu_imaging_source += "Please make a selection`r`n" - - # Select source - do { - clear - $answer = read-host -prompt $menu_imaging_source - } until ($valid_answers -contains $answer) - } - - if ($answer -imatch '^\d+$') { - # Valid disk selected - clear - $_d = Get-Disk -number $answer - $_disk_details = "Disk:`t{0,4:N0} Gb`t[{1}] ({2}) {3}" -f ($_d.Size / 1GB), $_d.PartitionStyle, $_d.BusType, $_d.FriendlyName - wk-write "$_disk_details" - wk-write "Partition(s):" - - # Print partition info - $partitions = Get-Partition -DiskNumber $_d.DiskNumber - foreach ($_p in $partitions) { - # Assign letter - Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null - - # Update partition info - $_p = Get-Partition -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber - $_v = Get-Volume -Partition $_p - - # Set size label - $_size = (human-size $_p.size 0) - if ($_v -ne $null) { - $_used = (human-size ($_v.Size - $_v.SizeRemaining) 0) - } - - # Print partition info - if ($_p.AccessPaths -eq $null) { - # No drive letter - $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type - wk-error "$_msg" - $_skipped_parts += 1 - } else { - # Has drive letter - $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - $_label = " {0}" -f $_p.Type - if ($_v -and $_v.FileSystemLabel -ne "") { - $_label = '"{0}"' -f $_v.FileSystemLabel - } - $_msg = " {0:N0}:`t{1} ({2,6}) {3} ({4} used)" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used - wk-write "$_msg" - } - } - if ($_skipped_parts -gt 0) { - wk-warn " *`tUnable to backup these partition(s)" - } - wk-write "" - if (ask " Backup these partition(s)?") { - return $_d - } else { - return $false - } - } - - return $answer -} -function select-server { - # Build server menu - $avail_servers = @(gdr | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - if ($avail_servers.count -eq 0) { - wk-error "No suitable backup servers were detected." - return $false - } - $menu_imaging_server = "Where are we saving the backup image(s)?`r`n`r`n" - $valid_answers = @("M", "m") - for ($i=0; $i -lt $avail_servers.length; $i++) { - $valid_answers += ($i + 1) - $menu_imaging_server += ("{0}: {1} ({2:N2} Gb free)`r`n" -f ($i + 1), $avail_servers[$i].Description, ($avail_servers[$i].Free / 1Gb)) - } - $menu_imaging_server += "`r`n" - $menu_imaging_server += "M: Main Menu`r`n" - $menu_imaging_server += "`r`n" - $menu_imaging_server += "Please make a selection`r`n" - - # Select server - do { -# clear - $answer = read-host -prompt $menu_imaging_server - } until ($valid_answers -contains $answer) - - if ($answer -imatch '^\d+$') { - $answer -= 1 - return $avail_servers[$answer] - } - return $answer -} function wk-exit { - popd - if ($answer -match 'R') { - #pause "Press Enter to Reboot... " - wpeutil reboot - } elseif ($answer -match 'S') { - #pause "Press Enter to Shutdown... " - wpeutil shutdown + param([string]$action) + switch ($action) { + 'Q' {PowerShell -ExecutionPolicy Bypass; break} + 'R' {wpeutil reboot; break} + 'S' {wpeutil shutdown; break} + default {throw} } exit 0 } -function mount-servers { - # Mount servers - wk-write "Connecting to backup server(s)" - foreach ($_server in $backup_servers) { - if (test-connection $_server.ip -count 3 -quiet) { - try { - $_path = "\\{0}\{1}" -f $_server.ip, $_server.path - $_drive = "{0}:" -f $_server.letter - net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null - wk-write ("`t{0} server: mounted" -f $_server.name) - - # Add friendly description - $_regex = "^{0}$" -f $_server.letter - (gdr | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name - } catch { - wk-warn ("`t{0} server: failed" -f $_server.name) - } - } else { - wk-warn ("`t{0} server: timed-out" -f $_server.name) - } - } -} -function unmount-servers { - # Unmount servers - wk-write "Disconnecting from backup server(s)" - $mounted_servers = @(gdr | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - foreach ($_server in $mounted_servers) { - try { - $_drive = "{0}:" -f $_server.Name - net use $_drive /delete | Out-Null - #wk-warn ("`t{0} server: unmounted" -f $_server.name) - wk-warn "`tServer: unmounted" - } catch { - #wk-warn ("`t{0} server: failed" -f $_server.name) - wk-warn "`tServer: failed" - } - } -} -function menu-imaging { - wk-write "Drive Imaging" - wk-write "" - - ## WARNING - wk-warn "WARNING: This section is experimental" - pause - ## WARNING - - # Service Order - $menu_service_order += "Please enter the service order`r`n" - do { - clear - $service_order = read-host -prompt $menu_service_order - } until ($service_order -imatch '^\d[\w\-]+$') - - # Select Disk - $disk = select-disk - if (!($disk)) { - # No drives detected or user aborted - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " - return $false - } elseif ($disk -imatch '^M$') { - # User selected to return to the menu - return - } - wk-write "" - - # Mount server(s) - mount-servers - - # Select Server - $server = select-server - if (!($server)) { - # No servers detected - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " - return $false - } elseif ($server -imatch '^M$') { - # User selected to return to the menu - return - } - wk-write "" - wk-write ("Saving partition backups to: {0}" -f $server.Description) - wk-write "" - - # Backup partitions - $partitions = Get-Partition -DiskNumber $disk.DiskNumber - foreach ($_p in $partitions) { - $_v = Get-Volume -Partition $_p - - $_name = "{0}" -f $_p.PartitionNumber - if ($_v -and $_v.FileSystemLabel -ne "") { - $_name += "_{0}" -f $_v.FileSystemLabel - } else { - $_name += "_{0}" -f $_p.Type - } - - $_imagepath = "{0}{1}" -f $server.Root, $service_order - $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name - - if ($_p.AccessPaths -ne $null) { - $_capturepath = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - - # Take image - wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) - if (!(Test-Path "$_imagepath")) { - mkdir "$_imagepath" | out-null - } - New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturepath" -Name "$_name" -CompressionType "fast" | out-null - - # Verify image - ## Code borrowed from: https://stackoverflow/a/10262275 - $pinfo = New-Object System.Diagnostics.ProcessStartInfo - $pinfo.FileName = "$WKPath\7z.exe" - $pinfo.RedirectStandardError = $true - $pinfo.RedirectStandardOutput = $true - $pinfo.UseShellExecute = $false - $pinfo.Arguments = 't "{0}"' -f $_imagefile - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $pinfo - $p.Start() | Out-Null - write-host " Verifying . . . " -NoNewline - $p.WaitForExit() - if ($p.ExitCode -eq 0) { - write-host "Complete." -foreground "green" - } else { - write-host "Failed." -foreground "red" - } - } - } - - # Unmount server(s) - unmount-servers - pause "Press Enter to return to main menu... " -} -function menu-setup { - wk-write "Windows Setup" - wk-write "" - - # Check if any destination drives were detected - $disks = Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} - if ($disks.count -eq 0) { - wk-error "No suitable destination drives were detected." - pause "Press Enter to return to main menu... " $True - return $false - } - - # Build windows menu - $windows_versions = @( - @{Name="Windows 7 Home Premium"; ImageFile="Win7"; Index=1}, - @{Name="Windows 7 Professional"; ImageFile="Win7"; Index=2}, - @{Name="Windows 7 Ultimate"; ImageFile="Win7"; Index=3}, - @{Name="Windows 8.1"; ImageFile="Win8"; Index=1}, - @{Name="Windows 8.1 Pro"; ImageFile="Win8"; Index=2}, - @{Name="Windows 10 Home"; ImageFile="Win10"; Index=1}, - @{Name="Windows 10 Pro"; ImageFile="Win10"; Index=2} - ) - $menu_setup_windows = "Which version of Windows are we installing?`r`n`r`n" - $valid_answers = @("M", "m") - for ($i=0; $i -lt $windows_versions.length; $i++) { - $valid_answers += ($i + 1) - $menu_setup_windows += "{0}: {1}`r`n" -f ($i + 1), $windows_versions[$i].Name - } - $menu_setup_windows += "`r`n" - $menu_setup_windows += "M: Main Menu`r`n" - $menu_setup_windows += "`r`n" - $menu_setup_windows += "Please make a selection`r`n" - - # Select Windows version - do { - clear - $answer = read-host -prompt $menu_setup_windows - } until ($valid_answers -contains $answer) - - if ($answer -imatch '^M$') { - # Exit if requested - return - } else { - $answer -= 1 - $dest_windows_version = $windows_versions[$answer] - } - - # Build disk menu - $menu_setup_disk = "To which drive are we installing {0}?`r`n`r`n" -f $dest_windows_version.Name - $valid_answers = @("M", "m") - foreach ($_ in $disks) { - $valid_answers += $_.DiskNumber - $menu_setup_disk += "{0}: {1:N0} Gb`t({2}) {3}`r`n" -f $_.DiskNumber, ($_.Size / 1GB), $_.PartitionStyle, $_.FriendlyName - } - $menu_setup_disk += "`r`n" - $menu_setup_disk += "M: Main Menu`r`n" - $menu_setup_disk += "`r`n" - $menu_setup_disk += "Please make a selection`r`n" - - # Select disk - do { - clear - $answer = read-host -prompt $menu_setup_disk - } until ($valid_answers -contains $answer) - - if ($answer -imatch '^M$') { - # Exit if requested - return - } else { - # Double check before deleting data - $dest_disk = $disks | Where-Object {$_.DiskNumber -eq $answer} - wk-warn "All data will be deleted from the following drive:" - wk-warn ("`t{0:N0} Gb`t({1}) {2}`r`n" -f ($dest_disk.Size / 1GB), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (ask ("Proceed and install {0}?" -f $dest_windows_version.Name)) { - wk-warn "SAFTEY CHECK:" - wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) - wk-error (" And ERASING:`tDisk {0} - {1:N0} Gb`t({2}) {3}`r`n" -f $dest_disk.DiskNumber, ($dest_disk.Size / 1GB), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (ask "Is this correct?") { - ## WARNING - wk-warn "WARNING: This section is experimental" - ## WARNING - ## Here be dragons - - try { - # Select UEFI or BIOS - if ($dest_windows_version.Name -match '^Windows 7') { - if (ask "Setup drive using MBR (legacy) layout?") { - format-mbr $dest_disk - } else { - format-gpt $dest_disk - } - } elseif ($dest_windows_version.Name -match '^Windows (8|10)') { - if (ask "Setup drive using GPT (UEFI) layout?") { - format-gpt $dest_disk - } else { - format-mbr $dest_disk - } - } - - # Apply image - apply-image $dest_windows_version.ImageFile $dest_windows_version.Index - - # Create boot files (copies files for both Legacy and UEFI) - bcdboot W:\Windows /s S: /f ALL - if ($dest_windows_version.Name -match '^Windows (8|10)') { - W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows - } - - # Reboot - wk-write "Windows Setup complete." - wk-write "" - return 0 - } catch { - wk-error "$Error" - wk-error "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " - return $false - } - } else { - wk-error "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " - } - } else { - wk-error "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " - } - } -} function menu-tools { - wk-write "Misc Tools" - wk-write "" - wk-warn "Be careful." - Start-Process "$WKPath\explorer++" -argumentlist @("$WKPath") - wk-exit + # Avail tools + $tools = @( + @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView64.exe"}, + @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++64.exe"}, + @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy64.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, + @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor64.exe"}, + @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit64.exe"}, + @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod64.exe"}, + @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, + @{Name="PhotoRec (GUI)"; Folder="TestDisk"; File="qphotorec_win.exe"}, + @{Name="PhotoRec (CLI)"; Folder="TestDisk"; File="photorec_win.exe"}, + @{Name="TestDisk (CLI)"; Folder="TestDisk"; File="testdisk_win.exe"} + ) + + # Build menu + $selection = $null + $actions = @(@{Name="Main Menu"; Letter="M"}) + + # Run Loop + $_done = $false + do { + $selection = (menu-select "Tools Menu" $tools $actions) + + if ($selection -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + $selection -= 1 + $path = "{0}\{1}" -f $WKPath, $tools[$selection].Folder + if ($tools[$selection].ContainsKey("Args")) { + Start-Process $tools[$selection].File -ArgumentList $tools[$selection].Args -WorkingDirectory $path + } else { + Start-Process $tools[$selection].File -WorkingDirectory $path + } + } + } until ($_done) } function menu-main { - $answered = $false - $menu_main = @" -WK WinPE Tools - -1: Drive Imaging -2: Windows Setup -3: Misc Tools - -Q: Quit -R: Reboot -S: Shutdown - -Please make a selection -"@ - - do { - clear - $answer = read-host -prompt $menu_main - } until ($answer -imatch '^[123QRS]$') - clear - - if ($answer.GetType().Name -match "String") { - $answer = $answer.ToUpper() - } - switch ($answer) { - 1 {menu-imaging; break} - 2 {menu-setup; break} - 3 {menu-tools; break} - default {wk-exit} + # Build menu + $selection = $null + $menus = @( + @{Name="Drive Imaging"; Menu="menu-imaging"} + @{Name="Windows Setup"; Menu="menu-setup"} + @{Name="Misc Tools"; Menu="menu-tools"} + ) + $actions = @( + @{Name="Command Prompt"; Letter="C"} + @{Name="PowerShell"; Letter="P"} + @{Name="Reboot"; Letter="R"} + @{Name="Shutdown"; Letter="S"} + ) + + # Show Menu + $selection = (menu-select "Main Menu" $menus $actions -SecretExit $true) + + if ($selection -imatch '^C$') { + Start-Process "$windir\System32\cmd.exe" -argumentlist @("-new_console:n") -WorkingDirectory "$WKPath" + return + } elseif ($selection -imatch '^P$') { + Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-new_console:n") -WorkingDirectory "$WKPath" + return + } elseif ($selection -imatch '^[QRS]$') { + wk-exit $selection + return + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + # Launch sub-menu + $selection -= 1 + & $menus[$selection].Menu } } diff --git a/WK/Scripts/imaging.ps1 b/WK/Scripts/imaging.ps1 new file mode 100644 index 00000000..a1033dc5 --- /dev/null +++ b/WK/Scripts/imaging.ps1 @@ -0,0 +1,463 @@ +# WK imaging functions + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 + +# Functions +function apply-image { + # Apply a Windows image to W:\ + Param([string]$image, [string]$name) + $path = "" + $split_image = $false + $split_image_pattern = "" + + # Check for local source + $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) + foreach ($v in $volumes) { + $letter = $v.DriveLetter + ":" + if (Test-Path "$letter\sources\$image.wim") { + $path = "$letter\sources\$image.wim" + } elseif (Test-Path "$letter\sources\$image.esd") { + $path = "$letter\sources\$image.wim" + } elseif (Test-Path "$letter\sources\$image.swm") { + $path = "$letter\sources\$image.swm" + $split_image = $true + $split_image_pattern = "$letter\sources\$image*.swm" + } + } + + # Check for remote source (if necessary) + if ($path -imatch '^$') { + # Temporarily set path to network source + $path = "\\$source_server\Windows\$image" + wk-warn "Searching for network source" + if (Test-Path "$path.wim") { + $path = "$path.wim" + } elseif (Test-Path "$path.esd") { + $path = "$path.swm" + } elseif (Test-Path "$path.swm") { + $path = "$path.swm" + $split_image = $true + $split_image_pattern = "$path*.swm" + } else { + # Revert to empty path if nothing found. + $path = "" + } + } + + # Expand Image + if ($path -imatch 'Win\d+\.(esd|wim)$') { + wk-write " Applying image..." + Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' | out-null + } elseif ($path -imatch 'Win\d+\.swm$') { + wk-write " Applying split-image..." + Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" | out-null + } else { + wk-error "Image not found." + throw + } +} +function format-gpt { + Param($dest_disk) + wk-write "Drive will use a GPT (UEFI) layout." + + # Double-check we have the right drive + ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets + $_sel_uid = $dest_disk.Guid + if ($dest_disk.PartitionStyle -imatch "MBR") { + # MBR disks don't have GUIDs and use the signature in hex instead + $_sel_uid = "{0:x}" -f $dest_disk.Signature + } + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "uniqueid disk" + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null + if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { + # GUIDs do not match + wk-error "Diskpart failed to select the same disk for formatting, aborting setup." + wk-warn "This system requires manual formatting & setup" + wk-write "" + throw "Failed to format disk" + } else { + wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) + } + + # Generate Diskpart script and execute + ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: + ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d + ## + ## NOTE 2: This overwrites existing diskpart.script file without confirmation. + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "clean`r`n" + $diskpart_script += "convert gpt`r`n" + + # 1. Windows RE tools partition (Windows 8+) + if ($dest_windows_version.Name -imatch '^Windows (8|10)') { + $diskpart_script += "create partition primary size=300`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" + $diskpart_script += "assign letter='T'`r`n" + $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" + $diskpart_script += "gpt attributes=0x8000000000000001`r`n" + } + + # 2. System partition + $diskpart_script += "create partition efi size=260`r`n" + ## NOTE: Allows for Advanced Format 4Kn drives + $diskpart_script += "format quick fs=fat32 label='System'`r`n" + $diskpart_script += "assign letter='S'`r`n" + + # 3. Microsoft Reserved (MSR) partition + $diskpart_script += "create partition msr size=128`r`n" + + # 4. Windows partition + $diskpart_script += "create partition primary`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" + $diskpart_script += "assign letter='W'`r`n" + + # Run script + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow | out-null +} +function format-mbr { + Param($dest_disk) + wk-write "Drive will use a MBR (legacy) layout." + + if ($dest_disk.PartitionStyle -inotmatch '^RAW$') { + # Only clean if necessary + clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false | out-null + } + Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' | out-null + New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true | out-null + New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false | out-null + Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' | out-null + Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' | out-null +} +function select-disk { + param([string]$title, [bool]$skip_usb=$false) + $_skipped_parts = 0 + + # Get Disk(s) + if ($skip_usb) { + $disks = @(Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} | Sort-Object -Property "Number") + } else { + $disks = @(Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number") + } + + # Check if any drives were detected + if ($disks.count -eq 0) { + wk-error "No suitable drives were detected." + return $false + } + + # Get selection + $selection = $null + $main_set = @() + if ($disks.count -eq 1) { + # Only one disk is available + $selection = $disks[0] + } else { + # Multiple options. Build and use menu + foreach ($_ in $disks) { + $_entry = "{0}`t[{1}] ({2}) {3}" -f (human-size $_.Size 0), $_.PartitionStyle, $_.BusType, $_.FriendlyName + $main_set += @{Name=$_entry} + } + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select $title $main_set $actions) + } + + if ($selection -imatch '^\d+$') { + $selection -= 1 + return $disks[$selection] + } else { + return $selection + } +} +function menu-imaging { + wk-write "Drive Imaging" + wk-write "" + + ## WARNING + wk-warn "WARNING: This section is experimental" + pause + ## WARNING + + # Service Order + $menu_service_order += "Please enter the service order`r`n" + do { + clear + $service_order = read-host -prompt $menu_service_order + } until ($service_order -imatch '^\d[\w\-]+$') + + # Select Disk + $disk = (select-disk "For which drive are we creating backup image(s)?") + + if (!($disk)) { + # No drives detected or user aborted + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($disk -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($disk.DiskNumber -imatch '^\d+$') { + # Valid disk selected + clear + wk-write ("Disk:`t{0}`t[{1}] ({2}) {3}" -f (human-size $disk.Size 0), $disk.PartitionStyle, $disk.BusType, $disk.FriendlyName) + wk-write "Partition(s):" + + # Print partition info + $partitions = Get-Partition -DiskNumber $disk.DiskNumber + $_skipped_parts = 0 + foreach ($_p in $partitions) { + # Assign letter + Add-PartitionAccessPath -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null + + # Update partition info + $_p = Get-Partition -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber + $_v = Get-Volume -Partition $_p + + # Set size label + $_size = (human-size $_p.size 0) + $_used = "" + if ($_v) { + $_used = "({0} used)" -f (human-size ($_v.Size - $_v.SizeRemaining) 0) + } + + # Print partition info + if ($_p.AccessPaths) { + # Has drive letter + $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + $_label = " {0}" -f $_p.Type + if ($_v -and $_v.FileSystemLabel -ne "") { + $_label = '"{0}"' -f $_v.FileSystemLabel + } + $_msg = " {0:N0}:`t{1} ({2,6}) {3} {4}" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used + wk-write "$_msg" + } else { + # No drive letter + $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type + wk-error "$_msg" + $_skipped_parts += 1 + } + } + if ($_skipped_parts -gt 0) { + wk-warn " *`tUnable to backup these partition(s)" + } + wk-write "" + if (!(ask " Backup these partition(s)?")) { + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + wk-write "" + + # Mount server(s) + mount-servers + + # Select Server + $server = (select-server) + if (!($server)) { + # No servers detected + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($server -imatch '^M$') { + # User selected to return to the menu + return + } + wk-write "" + wk-write ("Saving partition backups to: {0}" -f $server.Description) + wk-write "" + + # Backup partitions + $partitions = Get-Partition -DiskNumber $disk.DiskNumber + foreach ($_p in $partitions) { + $_v = Get-Volume -Partition $_p + + $_name = "{0}" -f $_p.PartitionNumber + if ($_v -and $_v.FileSystemLabel -ne "") { + $_name += "_{0}" -f $_v.FileSystemLabel + } else { + $_name += "_{0}" -f $_p.Type + } + # Sanitize the name + $_name = $_name -replace '\s', '_' + + $_imagepath = "{0}{1}" -f $server.Root, $service_order + $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name + + if ($_p.AccessPaths -ne $null) { + # Avoid unwanted clobbering + if (Test-Path "$_imagefile") { + if (!(ask ("Overwrite backup image: {0}" -f $_imagefile))) { + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + $_capturedir = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + + # Take image + wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) + if (!(Test-Path "$_imagepath")) { + mkdir "$_imagepath" | out-null + } + $_dism_args = @( + '/Capture-Image', + '/ImageFile:$_imagefile', + '/CaptureDir:$_capturedir', + '/Name:$_name', + '/Compress:fast', + '/Quiet') + Start-Process "$windir\System32\Dism.exe" -ArgumentList $_dism_args -NoNewWindow -Wait | out-null + + ## The following command fails to capture OS partitions consitantly. Until this is fixed I will use DISM directly (as above). + #New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturedir" -Name "$_name" -CompressionType "fast" | out-null + + # Verify image + ## Code borrowed from: https://stackoverflow/a/10262275 + $pinfo = New-Object System.Diagnostics.ProcessStartInfo + $pinfo.FileName = "$WKPath\7-Zip\7z.exe" + $pinfo.RedirectStandardError = $true + $pinfo.RedirectStandardOutput = $true + $pinfo.UseShellExecute = $false + $pinfo.Arguments = 't "{0}"' -f $_imagefile + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $pinfo + $p.Start() | Out-Null + write-host " Verifying . . . " -NoNewline + $p.WaitForExit() + if ($p.ExitCode -eq 0) { + write-host "Complete." -foreground "green" + } else { + write-host "Failed." -foreground "red" + } + } + } + + # Unmount server(s) + unmount-servers + pause "Press Enter to return to main menu... " +} +function menu-setup { + # Select Disk + $dest_disk = (select-disk "To which drive are we installing Windows?" -skip_usb=$true) + + if (!($dest_disk)) { + # No drives detected or user aborted + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($dest_disk -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($dest_disk.DiskNumber -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + wk-warn "All data will be deleted from the following drive:" + wk-warn ("`t{0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (!(ask "Proceed and install Windows?")) { + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + + # Set available Windows versions + $windows_versions = @( + @{Name="Windows 7 Home Basic"; ImageFile="Win7"; ImageName="Windows 7 HOMEBASIC"} + @{Name="Windows 7 Home Premium"; ImageFile="Win7"; ImageName="Windows 7 HOMEPREMIUM"} + @{Name="Windows 7 Professional"; ImageFile="Win7"; ImageName="Windows 7 PROFESSIONAL"} + @{Name="Windows 7 Ultimate"; ImageFile="Win7"; ImageName="Windows 7 ULTIMATE"} + + @{Name="Windows 8.1"; ImageFile="Win8"; ImageName="Windows 8.1"; CRLF=$true} + @{Name="Windows 8.1 Pro"; ImageFile="Win8"; ImageName="Windows 8.1 Pro"} + + # The ISOs from the MediaCreationTool are apparently Technical Previews + @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Technical Preview"; CRLF=$true} + @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro Technical Preview"} + ) + + # Build menu and get selection + $dest_windows_version = $null + $selection = $null + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select "Which version of Windows are we installing?" $windows_versions $actions) + + if ($selection -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + $selection -= 1 + $dest_windows_version = $windows_versions[$selection] + } + + # Double check before deleting data + wk-warn "SAFTEY CHECK:" + wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) + wk-error (" And ERASING:`tDisk: {0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (!(ask "Is this correct?")) { + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + + ## WARNING + wk-warn "WARNING: This section is experimental" + ## WARNING + + ## Here be dragons + try { + # Select UEFI or BIOS partition layout + if ($UEFI) { + # System booted via UEFI so assume new layout should be GPT + if (ask "Setup drive using GPT (UEFI) layout?") { + format-gpt $dest_disk + } else { + format-mbr $dest_disk + } + } else{ + if (ask "Setup drive using MBR (legacy) layout?") { + format-mbr $dest_disk + } else { + format-gpt $dest_disk + } + } + + # Apply image + apply-image $dest_windows_version.ImageFile $dest_windows_version.ImageName + + # Create boot files (copies files for both Legacy and UEFI) + wk-write " Copying boot files..." + bcdboot W:\Windows /s S: /f ALL 2>&1 | out-null + if ($dest_windows_version.Name -imatch '^Windows (8|10)') { + W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows 2>&1 | out-null + } + + # Done + wk-write "Windows Setup complete." + wk-write "" + pause "Press Enter to return to main menu... " + } catch { + # Error(s) + wk-error "$Error" + wk-error "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } +} diff --git a/WK/Scripts/init.ps1 b/WK/Scripts/init.ps1 index 009b756b..b198fdd8 100644 --- a/WK/Scripts/init.ps1 +++ b/WK/Scripts/init.ps1 @@ -4,9 +4,26 @@ $host.UI.RawUI.BackgroundColor = "black" $host.UI.RawUI.ForegroundColor = "cyan" +#$appdata = (gci env:appdata).value +#$localappdata = (gci env:localappdata).value +#$username = (gci env:username).value +#$userprofile = (gci env:userprofile).value $systemdrive = (gci env:systemdrive).value +$windir = (gci env:windir).value +#$programfiles = (gci env:programfiles).value +#$programfiles86 = $programfiles +#if (test-path env:"programfiles(x86)") { +# $programfiles86 = (gci env:"programfiles(x86)").value +#} $WKPath = "$systemdrive\WK" $date = get-date -uformat "%Y-%m-%d" +#$logpath = "$WKPath\Info\$date" + +# Check if booted via UEFI +$UEFI = $false +if ((Get-ItemProperty -path "HKLM:\System\CurrentControlSet\Control").PEFirmwareType -eq 2) { + $UEFI = $true +} function ask { param([string]$text = "Kotaero", [string]$log = "WK.log") @@ -56,6 +73,80 @@ function human-size { } return $size } +function menu-select { + ## $MainEntries should be an "AoH" object (with at least the key "Name" for each item) + ## NOTE: if the CRLF=$true; then a spacer is added before that entry. + ## Example: + ## $MainEntries = @( + ## @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"} + ## @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} + ##) + + ## $ActionEntries should be an "AoH" object (with at least the keys "Name" and "Letter" for each item) + ## NOTE: if the CRLF=$true; then a spacer is added before that entry. + ## Example: + ## $ActionEntries = @( + ## @{Name="Reboot"; Letter="R"} + ## @{Name="Shutdown"; Letter="S"} + ##) + + param( + [string]$Title = "## Untitled Menu ##", + $MainEntries = @(), + $ActionEntries = @(), + [string]$Prompt = "Please make a selection", + [bool]$SecretExit = $false + ) + + # Bail early if no items given + if ($MainEntries.length -eq 0 -and $ActionEntries.length -eq 0) { + throw "MenuError: No items given." + } + + # Build menu + $menu_splash = "{0}`r`n`r`n" -f $title + $valid_answers = @() + if ($SecretExit) { + $valid_answers += "Q" + } + + # Add main items to splash + if ($MainEntries.length -gt 0) { + for ($i=0; $i -lt $MainEntries.length; $i++) { + if ($MainEntries[$i].CRLF) { + # Add spacer + $menu_splash += "`r`n" + } + $valid_answers += ($i + 1) + $menu_splash += "{0,2:N0}: {1}`r`n" -f ($i + 1), $MainEntries[$i].Name + } + $menu_splash += "`r`n" + } + + # Add action items to splash + if ($ActionEntries.length -gt 0) { + foreach ($_item in $ActionEntries) { + if ($_item.CRLF) { + # Add spacer + $menu_splash += "`r`n" + } + $menu_splash += " {0}: {1}`r`n" -f $_item.Letter.ToUpper(), $_item.Name + $valid_answers += $_item.Letter.ToLower(), $_item.Letter.ToUpper() + } + $menu_splash += "`r`n" + } + + # Add prompt to splash + $menu_splash += "{0}`r`n" -f $prompt + + # Select Windows version + do { + clear + $answer = read-host -prompt $menu_splash + } until ($valid_answers -contains $answer) + + return $answer.ToUpper() +} function pause { param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) if ($warning) { diff --git a/WK/Scripts/servers.ps1 b/WK/Scripts/servers.ps1 new file mode 100644 index 00000000..2d47e19f --- /dev/null +++ b/WK/Scripts/servers.ps1 @@ -0,0 +1,85 @@ +# WK server functions + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 + +# Variables +$source_server = "10.0.0.10" +$backup_servers = @( + @{ "ip"="10.0.0.10"; + "letter"="Z"; + "name"="ServerOne"; + "path"="Backups"}, + @{ "ip"="10.0.0.11"; + "name"="ServerTwo"; + "letter"="Y"; + "path"="Backups"} + ) +$backup_user = "backup" +$backup_pass = "Abracadabra" + +# Functions +function select-server { + # Check for available servers + $avail_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) + if ($avail_servers.count -eq 0) { + wk-error "No suitable backup servers were detected." + return $false + } + + # Build menu and get selection + $selection = $null + $main_set = @() + foreach ($server in $avail_servers) { + $_entry = "{0} ({1} free)" -f $server.Description, (human-size $server.Free) + $main_set += @{Name=$_entry} + } + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select "Where are we saving the backup image(s)?" $main_set $actions) + + if ($selection -imatch '^\d+$') { + $selection -= 1 + return $avail_servers[$selection] + } + return $selection +} +function mount-servers { + # Mount servers + wk-write "Connecting to backup server(s)" + foreach ($_server in $backup_servers) { + if (test-connection $_server.ip -count 3 -quiet) { + try { + $_path = "\\{0}\{1}" -f $_server.ip, $_server.path + $_drive = "{0}:" -f $_server.letter + net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null + wk-write ("`t{0} server: mounted" -f $_server.name) + + # Add friendly description + $_regex = "^{0}$" -f $_server.letter + (Get-PSDrive | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name + } catch { + wk-warn ("`t{0} server: failed" -f $_server.name) + } + } else { + wk-warn ("`t{0} server: timed-out" -f $_server.name) + } + } +} +function unmount-servers { + # Unmount servers + wk-write "Disconnecting from backup server(s)" + $mounted_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) + foreach ($_server in $mounted_servers) { + try { + $_drive = "{0}:" -f $_server.Name + net use $_drive /delete | Out-Null + #wk-warn ("`t{0} server: unmounted" -f $_server.name) + wk-warn "`tServer: unmounted" + } catch { + #wk-warn ("`t{0} server: failed" -f $_server.name) + wk-warn "`tServer: failed" + } + } +} diff --git a/make-cd.cmd b/make-cd.cmd index 885ba639..2f7bf210 100644 --- a/make-cd.cmd +++ b/make-cd.cmd @@ -5,6 +5,8 @@ setlocal EnableDelayedExpansion title WinPE 10 creation tool color 1b pushd %~dp0 +set "wd=%cd%" +set "pe_iso=WinPE-2016-02d.iso" :Flags for %%f in (%*) do ( @@ -12,8 +14,9 @@ for %%f in (%*) do ( ) :CreateISO -del winpe10-test.iso -makewinpemedia.cmd /iso pe_files winpe10-test.iso +del "!pe_iso!" +makewinpemedia.cmd /iso "%wd%\pe_files" "!pe_iso!" +goto Done :Abort echo. diff --git a/make.cmd b/make.cmd index 01dc5421..5868691b 100644 --- a/make.cmd +++ b/make.cmd @@ -7,7 +7,7 @@ color 1b pushd %~dp0 set "wd=%cd%" set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" - +set "pe_iso=WinPE-2016-02d.iso" :Flags for %%f in (%*) do ( @@ -62,29 +62,38 @@ dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Enha del "%wd%\WK\Scripts\WK.log" mkdir "%wd%\mount\WK" robocopy /e "%wd%\WK" "%wd%\mount\WK" -mklink "%wd%\mount\System32\explorer.exe" "%wd%\mount\WK\Explorer++.exe" +del "%wd%\mount\Windows\explorer.exe" +mklink /h "%wd%\mount\Windows\explorer.exe" "%wd%\mount\WK\Explorer++\Explorer++64.exe" -:MenuLauncher +:System32Stuff copy /y "%wd%\System32\menu.cmd" "%wd%\mount\Windows\System32\menu.cmd" +copy /y "%wd%\System32\Winpeshl.ini" "%wd%\mount\Windows\System32\Winpeshl.ini" -:ReplaceStartnet -copy /y "%wd%\System32\startnet.cmd" "%wd%\mount\Windows\System32\startnet.cmd" - -:ReplaceNotepad +:RegistryEdits reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE -reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2.exe /z" /f +reg load HKLM\WinPE-SYS mount\Windows\System32\config\SYSTEM + +rem Add 7-Zip to path +reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip" /f + +rem Replace Notepad +reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod64.exe /z" /f + +rem Unload registry hives reg unload HKLM\WinPE-SW +reg unload HKLM\WinPE-SYS :Background takeown /f "%wd%\mount\Windows\System32\winpe.jpg" /a icacls "%wd%\mount\Windows\System32\winpe.jpg" /grant administrators:F copy /y "%wd%\System32\winpe.jpg" "%wd%\mount\Windows\System32\winpe.jpg" +copy /y "%wd%\System32\winpe.jpg" "%wd%\mount\WK\ConEmu\winpe.jpg" :ManualStuff -echo Now is the time to add stuff (optional). -echo. -echo Press any key to commit changes... -pause>nul +REM echo Now is the time to add stuff (optional). +REM echo. +REM echo Press any key to commit changes... +REM pause>nul :Set-ScratchSpace rem Force RamDisk size to try and avoid capture-image errors @@ -94,8 +103,8 @@ dism /image:"%wd%\mount" /set-scratchspace:512 dism /unmount-image /mountdir:"%wd%\mount" /commit :CreateISO -del winpe10-2016.iso -makewinpemedia.cmd /iso "%wd%\pe_files" winpe10-2016.iso +del "!pe_iso!" +makewinpemedia.cmd /iso "%wd%\pe_files" "!pe_iso!" goto Done :Abort From 6818922ba8de6b60b81f952491791e52e718ea54 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 20:59:32 -0800 Subject: [PATCH 05/85] 2016-03: Retroactive Updates * Started work on building 32-bit and 64-bit images --- System32/startnet.cmd | 11 - WK_32/CPU-Z/cpuz.ini | 20 + {WK => WK_32}/ConEmu/ConEmu.xml | 0 {WK => WK_32}/Explorer++/config.xml | 4 +- {WK => WK_32}/HWMonitor/hwmonitorw.ini | 0 {WK => WK_32}/Notepad2/Notepad2.ini | 42 +- {WK => WK_32}/Scripts/WK.ps1 | 21 +- {WK => WK_32}/Scripts/imaging.ps1 | 36 +- {WK => WK_32}/Scripts/init.ps1 | 0 {WK => WK_32}/Scripts/servers.ps1 | 0 WK_64/CPU-Z/cpuz.ini | 20 + WK_64/ConEmu/ConEmu.xml | 643 +++++++++++++++++++++++++ WK_64/Explorer++/config.xml | 113 +++++ WK_64/HWMonitor/hwmonitorw.ini | 8 + WK_64/Notepad2/Notepad2.ini | 106 ++++ WK_64/Scripts/WK.ps1 | 116 +++++ WK_64/Scripts/imaging.ps1 | 467 ++++++++++++++++++ WK_64/Scripts/init.ps1 | 158 ++++++ WK_64/Scripts/servers.ps1 | 85 ++++ 19 files changed, 1785 insertions(+), 65 deletions(-) delete mode 100644 System32/startnet.cmd create mode 100644 WK_32/CPU-Z/cpuz.ini rename {WK => WK_32}/ConEmu/ConEmu.xml (100%) rename {WK => WK_32}/Explorer++/config.xml (97%) rename {WK => WK_32}/HWMonitor/hwmonitorw.ini (100%) rename {WK => WK_32}/Notepad2/Notepad2.ini (64%) rename {WK => WK_32}/Scripts/WK.ps1 (82%) rename {WK => WK_32}/Scripts/imaging.ps1 (93%) rename {WK => WK_32}/Scripts/init.ps1 (100%) rename {WK => WK_32}/Scripts/servers.ps1 (100%) create mode 100644 WK_64/CPU-Z/cpuz.ini create mode 100644 WK_64/ConEmu/ConEmu.xml create mode 100644 WK_64/Explorer++/config.xml create mode 100644 WK_64/HWMonitor/hwmonitorw.ini create mode 100644 WK_64/Notepad2/Notepad2.ini create mode 100644 WK_64/Scripts/WK.ps1 create mode 100644 WK_64/Scripts/imaging.ps1 create mode 100644 WK_64/Scripts/init.ps1 create mode 100644 WK_64/Scripts/servers.ps1 diff --git a/System32/startnet.cmd b/System32/startnet.cmd deleted file mode 100644 index 45186f05..00000000 --- a/System32/startnet.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -color 0b -echo Initializing... -wpeinit -wpeutil updatebootinfo - -pushd %systemdrive%\WK -set "PATH=%PATH%;%systemdrive%\WK" - -powershell -executionpolicy bypass -file %systemdrive%\WK\Scripts\WK.ps1 diff --git a/WK_32/CPU-Z/cpuz.ini b/WK_32/CPU-Z/cpuz.ini new file mode 100644 index 00000000..fa6114f0 --- /dev/null +++ b/WK_32/CPU-Z/cpuz.ini @@ -0,0 +1,20 @@ +[CPU-Z] +VERSION=1.7.5.0 +TextFontName= +TextFontSize=14 +TextFontColor=000080 +LabelFontName= +LabelFontSize=14 +ACPI=1 +PCI=1 +MaxPCIBus=256 +DMI=1 +Sensor=1 +SMBus=1 +Display=1 +UseDisplayAPI=1 +BusClock=1 +Chipset=1 +SPD=1 +XOC=0 +CheckUpdates=0 diff --git a/WK/ConEmu/ConEmu.xml b/WK_32/ConEmu/ConEmu.xml similarity index 100% rename from WK/ConEmu/ConEmu.xml rename to WK_32/ConEmu/ConEmu.xml diff --git a/WK/Explorer++/config.xml b/WK_32/Explorer++/config.xml similarity index 97% rename from WK/Explorer++/config.xml rename to WK_32/Explorer++/config.xml index 342f0de4..add6848f 100644 --- a/WK/Explorer++/config.xml +++ b/WK_32/Explorer++/config.xml @@ -71,9 +71,9 @@ - + - + diff --git a/WK/HWMonitor/hwmonitorw.ini b/WK_32/HWMonitor/hwmonitorw.ini similarity index 100% rename from WK/HWMonitor/hwmonitorw.ini rename to WK_32/HWMonitor/hwmonitorw.ini diff --git a/WK/Notepad2/Notepad2.ini b/WK_32/Notepad2/Notepad2.ini similarity index 64% rename from WK/Notepad2/Notepad2.ini rename to WK_32/Notepad2/Notepad2.ini index 4522220d..b5c75f87 100644 --- a/WK/Notepad2/Notepad2.ini +++ b/WK_32/Notepad2/Notepad2.ini @@ -1,14 +1,15 @@ -[Settings] +[Notepad2] +[Settings] SaveSettings=1 -SaveRecentFiles=1 -SaveFindReplace=1 +SaveRecentFiles=0 +SaveFindReplace=0 CloseFind=0 CloseReplace=0 NoFindWrap=0 -OpenWithDir=%SystemDrive%\ -Favorites=%SystemDrive%\ -PathNameFormat=1 -WordWrap=0 +OpenWithDir=%SystemDrive%\WK\Tools\.bin\Notepad2 +Favorites=%SystemDrive%\WK\Tools\.bin\Notepad2 +PathNameFormat=2 +WordWrap=1 WordWrapMode=0 WordWrapIndent=0 WordWrapSymbols=22 @@ -21,7 +22,7 @@ AutoCompleteWords=0 ShowIndentGuides=0 TabsAsSpaces=1 TabIndents=1 -BackspaceUnindents=0 +BackspaceUnindents=1 TabWidth=4 IndentWidth=0 MarkLongLines=1 @@ -77,6 +78,9 @@ FindReplaceDlgPosY=0 SingleFileInstance=1 ShellAppUserModelID=Notepad2 ShellUseSystemMRU=1 +[Recent Files] +[Recent Find] +[Recent Replace] [Custom Colors] 01=#000000 02=#0A246A @@ -100,25 +104,3 @@ DefaultScheme=0 AutoSelect=1 SelectDlgSizeX=304 SelectDlgSizeY=324 -[Default Text] -2nd Default Style=font:Lucida Console; size:10; fore:#C0C0C0; back:#000000 -2nd Margins and Line Numbers=font:Tahoma; size:-3; fore:#808080; back:#000000 -2nd Matching Braces=bold; fore:#00FF00 -2nd Matching Braces Error=bold; fore:#FF0000 -2nd Control Characters (Font)=size:-1 -2nd Indentation Guide (Color)=fore:#808080 -2nd Selected Text (Colors)=fore:#008000; back:#404040; alpha:50; eolfilled -2nd Whitespace (Colors, Size 0-5)=fore:#FF0000 -2nd Current Line Background (Color)=back:#808080; alpha:50 -2nd Caret (Color, Size 1-3)=fore:#C0C0C0 -2nd Long Line Marker (Colors)=fore:#404040 -2nd Extra Line Spacing (Size)= -[Recent Files] -01= -02= -[Recent Find] -01= -02= -[Recent Replace] -01= -02= diff --git a/WK/Scripts/WK.ps1 b/WK_32/Scripts/WK.ps1 similarity index 82% rename from WK/Scripts/WK.ps1 rename to WK_32/Scripts/WK.ps1 index f39f397c..bf346b17 100644 --- a/WK/Scripts/WK.ps1 +++ b/WK_32/Scripts/WK.ps1 @@ -26,13 +26,14 @@ function wk-exit { function menu-tools { # Avail tools $tools = @( - @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView64.exe"}, - @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++64.exe"}, - @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy64.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, - @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor64.exe"}, - @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit64.exe"}, - @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod64.exe"}, + @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView.exe"}, + @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++.exe"}, + @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, + @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor.exe"}, + @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit.exe"}, + @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod.exe"}, @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, + @{Name="ProduKey"; Folder="ProduKey"; File="ProduKey.exe"}, @{Name="PhotoRec (GUI)"; Folder="TestDisk"; File="qphotorec_win.exe"}, @{Name="PhotoRec (CLI)"; Folder="TestDisk"; File="photorec_win.exe"}, @{Name="TestDisk (CLI)"; Folder="TestDisk"; File="testdisk_win.exe"} @@ -101,6 +102,14 @@ function menu-main { } } +# Mount all partitions +foreach ($_d in @(Get-Disk)) { + foreach ($_p in @(Get-Partition -DiskNumber $_d.DiskNumber)) { + # Assign letter + Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null + } +} + # Main Loop do { menu-main diff --git a/WK/Scripts/imaging.ps1 b/WK_32/Scripts/imaging.ps1 similarity index 93% rename from WK/Scripts/imaging.ps1 rename to WK_32/Scripts/imaging.ps1 index a1033dc5..38b48b4c 100644 --- a/WK/Scripts/imaging.ps1 +++ b/WK_32/Scripts/imaging.ps1 @@ -13,14 +13,16 @@ function apply-image { $split_image = $false $split_image_pattern = "" - # Check for local source + # Check for source image + ## This checks all drive letters for the source image. + ## It starts with local sources and then tries the server(s) (usually Y: and Z:) $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) foreach ($v in $volumes) { $letter = $v.DriveLetter + ":" if (Test-Path "$letter\sources\$image.wim") { $path = "$letter\sources\$image.wim" } elseif (Test-Path "$letter\sources\$image.esd") { - $path = "$letter\sources\$image.wim" + $path = "$letter\sources\$image.esd" } elseif (Test-Path "$letter\sources\$image.swm") { $path = "$letter\sources\$image.swm" $split_image = $true @@ -28,7 +30,7 @@ function apply-image { } } - # Check for remote source (if necessary) + # Check for FQDN remote source (if necessary) if ($path -imatch '^$') { # Temporarily set path to network source $path = "\\$source_server\Windows\$image" @@ -36,7 +38,7 @@ function apply-image { if (Test-Path "$path.wim") { $path = "$path.wim" } elseif (Test-Path "$path.esd") { - $path = "$path.swm" + $path = "$path.esd" } elseif (Test-Path "$path.swm") { $path = "$path.swm" $split_image = $true @@ -177,6 +179,10 @@ function select-disk { function menu-imaging { wk-write "Drive Imaging" wk-write "" + + # Pre-emptively mount Server(s) + ## Helps ensure a successfull backup and/or setup + mount-servers ## WARNING wk-warn "WARNING: This section is experimental" @@ -256,9 +262,6 @@ function menu-imaging { } wk-write "" - # Mount server(s) - mount-servers - # Select Server $server = (select-server) if (!($server)) { @@ -310,12 +313,12 @@ function menu-imaging { mkdir "$_imagepath" | out-null } $_dism_args = @( - '/Capture-Image', - '/ImageFile:$_imagefile', - '/CaptureDir:$_capturedir', - '/Name:$_name', - '/Compress:fast', - '/Quiet') + "/Capture-Image", + "/ImageFile:$_imagefile", + "/CaptureDir:$_capturedir", + "/Name:$_name", + "/Compress:fast", + "/Quiet") Start-Process "$windir\System32\Dism.exe" -ArgumentList $_dism_args -NoNewWindow -Wait | out-null ## The following command fails to capture OS partitions consitantly. Until this is fixed I will use DISM directly (as above). @@ -341,12 +344,13 @@ function menu-imaging { } } } - - # Unmount server(s) - unmount-servers pause "Press Enter to return to main menu... " } function menu-setup { + # Pre-emptively mount Server(s) + ## Helps ensure a successfull backup and/or setup + mount-servers + # Select Disk $dest_disk = (select-disk "To which drive are we installing Windows?" -skip_usb=$true) diff --git a/WK/Scripts/init.ps1 b/WK_32/Scripts/init.ps1 similarity index 100% rename from WK/Scripts/init.ps1 rename to WK_32/Scripts/init.ps1 diff --git a/WK/Scripts/servers.ps1 b/WK_32/Scripts/servers.ps1 similarity index 100% rename from WK/Scripts/servers.ps1 rename to WK_32/Scripts/servers.ps1 diff --git a/WK_64/CPU-Z/cpuz.ini b/WK_64/CPU-Z/cpuz.ini new file mode 100644 index 00000000..fa6114f0 --- /dev/null +++ b/WK_64/CPU-Z/cpuz.ini @@ -0,0 +1,20 @@ +[CPU-Z] +VERSION=1.7.5.0 +TextFontName= +TextFontSize=14 +TextFontColor=000080 +LabelFontName= +LabelFontSize=14 +ACPI=1 +PCI=1 +MaxPCIBus=256 +DMI=1 +Sensor=1 +SMBus=1 +Display=1 +UseDisplayAPI=1 +BusClock=1 +Chipset=1 +SPD=1 +XOC=0 +CheckUpdates=0 diff --git a/WK_64/ConEmu/ConEmu.xml b/WK_64/ConEmu/ConEmu.xml new file mode 100644 index 00000000..26a3611c --- /dev/null +++ b/WK_64/ConEmu/ConEmu.xml @@ -0,0 +1,643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK_64/Explorer++/config.xml b/WK_64/Explorer++/config.xml new file mode 100644 index 00000000..add6848f --- /dev/null +++ b/WK_64/Explorer++/config.xml @@ -0,0 +1,113 @@ + + + + + yes + no + yes + yes + no + yes + no + no + + + + + 90 + yes + no + no + no + no + no + no + 0 + yes + 9 + no + 0 + yes + no + ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} + no + 500 + yes + yes + 1 + yes + no + no + no + yes + yes + yes + yes + no + yes + no + yes + yes + yes + no + yes + yes + no + yes + yes + yes + 1 + yes + 1 + yes + no + no + + no + 208 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK_64/HWMonitor/hwmonitorw.ini b/WK_64/HWMonitor/hwmonitorw.ini new file mode 100644 index 00000000..e3978b4e --- /dev/null +++ b/WK_64/HWMonitor/hwmonitorw.ini @@ -0,0 +1,8 @@ +[HWMonitor] +VERSION=1.2.8.0 +USE_ACPI=1 +USE_SMBUS=1 +USE_SMART=1 +USE_DISPLAY=1 +CPU_0_TJMAX=100.0 +UPDATES=0 diff --git a/WK_64/Notepad2/Notepad2.ini b/WK_64/Notepad2/Notepad2.ini new file mode 100644 index 00000000..b5c75f87 --- /dev/null +++ b/WK_64/Notepad2/Notepad2.ini @@ -0,0 +1,106 @@ +[Notepad2] +[Settings] +SaveSettings=1 +SaveRecentFiles=0 +SaveFindReplace=0 +CloseFind=0 +CloseReplace=0 +NoFindWrap=0 +OpenWithDir=%SystemDrive%\WK\Tools\.bin\Notepad2 +Favorites=%SystemDrive%\WK\Tools\.bin\Notepad2 +PathNameFormat=2 +WordWrap=1 +WordWrapMode=0 +WordWrapIndent=0 +WordWrapSymbols=22 +ShowWordWrapSymbols=0 +MatchBraces=1 +AutoCloseTags=0 +HighlightCurrentLine=1 +AutoIndent=1 +AutoCompleteWords=0 +ShowIndentGuides=0 +TabsAsSpaces=1 +TabIndents=1 +BackspaceUnindents=1 +TabWidth=4 +IndentWidth=0 +MarkLongLines=1 +LongLinesLimit=80 +LongLineMode=1 +ShowSelectionMargin=0 +ShowLineNumbers=1 +ShowCodeFolding=1 +MarkOccurrences=2 +MarkOccurrencesMatchCase=0 +MarkOccurrencesMatchWholeWords=0 +ViewWhiteSpace=0 +ViewEOLs=0 +DefaultEncoding=3 +SkipUnicodeDetection=0 +LoadASCIIasUTF8=0 +LoadNFOasOEM=1 +NoEncodingTags=0 +DefaultEOLMode=0 +FixLineEndings=0 +FixTrailingBlanks=0 +PrintHeader=1 +PrintFooter=0 +PrintColorMode=3 +PrintZoom=10 +PrintMarginLeft=1000 +PrintMarginTop=1000 +PrintMarginRight=1000 +PrintMarginBottom=1000 +SaveBeforeRunningTools=1 +FileWatchingMode=1 +ResetFileWatching=0 +EscFunction=2 +AlwaysOnTop=0 +MinimizeToTray=0 +TransparentMode=0 +ToolbarButtons=1 2 4 0 5 6 0 7 8 9 0 10 11 0 12 0 24 0 13 14 0 15 0 17 +ShowToolbar=1 +ShowStatusbar=1 +EncodingDlgSizeX=256 +EncodingDlgSizeY=262 +RecodeDlgSizeX=256 +RecodeDlgSizeY=262 +FileMRUDlgSizeX=412 +FileMRUDlgSizeY=376 +OpenWithDlgSizeX=384 +OpenWithDlgSizeY=386 +FavoritesDlgSizeX=334 +FavoritesDlgSizeY=316 +FindReplaceDlgPosX=0 +FindReplaceDlgPosY=0 +[Settings2] +SingleFileInstance=1 +ShellAppUserModelID=Notepad2 +ShellUseSystemMRU=1 +[Recent Files] +[Recent Find] +[Recent Replace] +[Custom Colors] +01=#000000 +02=#0A246A +03=#3A6EA5 +04=#003CE6 +05=#006633 +06=#608020 +07=#648000 +08=#A46000 +09=#FFFFFF +10=#FFFFE2 +11=#FFF1A8 +12=#FFC000 +13=#FF4000 +14=#C80000 +15=#B000B0 +16=#B28B40 +[Styles] +Use2ndDefaultStyle=0 +DefaultScheme=0 +AutoSelect=1 +SelectDlgSizeX=304 +SelectDlgSizeY=324 diff --git a/WK_64/Scripts/WK.ps1 b/WK_64/Scripts/WK.ps1 new file mode 100644 index 00000000..bf346b17 --- /dev/null +++ b/WK_64/Scripts/WK.ps1 @@ -0,0 +1,116 @@ +# WK-Checklist + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 +. .\servers.ps1 +. .\imaging.ps1 +clear +$host.UI.RawUI.WindowTitle = "WK PE Tool" +$logpath = "$WKPath\Info\$date" +md "$logpath" 2>&1 | Out-Null +$log = "$logpath\winpe.log" + +# Functions +function wk-exit { + param([string]$action) + switch ($action) { + 'Q' {PowerShell -ExecutionPolicy Bypass; break} + 'R' {wpeutil reboot; break} + 'S' {wpeutil shutdown; break} + default {throw} + } + exit 0 +} +function menu-tools { + # Avail tools + $tools = @( + @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView.exe"}, + @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++.exe"}, + @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, + @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor.exe"}, + @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit.exe"}, + @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod.exe"}, + @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, + @{Name="ProduKey"; Folder="ProduKey"; File="ProduKey.exe"}, + @{Name="PhotoRec (GUI)"; Folder="TestDisk"; File="qphotorec_win.exe"}, + @{Name="PhotoRec (CLI)"; Folder="TestDisk"; File="photorec_win.exe"}, + @{Name="TestDisk (CLI)"; Folder="TestDisk"; File="testdisk_win.exe"} + ) + + # Build menu + $selection = $null + $actions = @(@{Name="Main Menu"; Letter="M"}) + + # Run Loop + $_done = $false + do { + $selection = (menu-select "Tools Menu" $tools $actions) + + if ($selection -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + $selection -= 1 + $path = "{0}\{1}" -f $WKPath, $tools[$selection].Folder + if ($tools[$selection].ContainsKey("Args")) { + Start-Process $tools[$selection].File -ArgumentList $tools[$selection].Args -WorkingDirectory $path + } else { + Start-Process $tools[$selection].File -WorkingDirectory $path + } + } + } until ($_done) +} +function menu-main { + # Build menu + $selection = $null + $menus = @( + @{Name="Drive Imaging"; Menu="menu-imaging"} + @{Name="Windows Setup"; Menu="menu-setup"} + @{Name="Misc Tools"; Menu="menu-tools"} + ) + $actions = @( + @{Name="Command Prompt"; Letter="C"} + @{Name="PowerShell"; Letter="P"} + @{Name="Reboot"; Letter="R"} + @{Name="Shutdown"; Letter="S"} + ) + + # Show Menu + $selection = (menu-select "Main Menu" $menus $actions -SecretExit $true) + + if ($selection -imatch '^C$') { + Start-Process "$windir\System32\cmd.exe" -argumentlist @("-new_console:n") -WorkingDirectory "$WKPath" + return + } elseif ($selection -imatch '^P$') { + Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-new_console:n") -WorkingDirectory "$WKPath" + return + } elseif ($selection -imatch '^[QRS]$') { + wk-exit $selection + return + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + # Launch sub-menu + $selection -= 1 + & $menus[$selection].Menu + } +} + +# Mount all partitions +foreach ($_d in @(Get-Disk)) { + foreach ($_p in @(Get-Partition -DiskNumber $_d.DiskNumber)) { + # Assign letter + Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null + } +} + +# Main Loop +do { + menu-main +} while ($true) diff --git a/WK_64/Scripts/imaging.ps1 b/WK_64/Scripts/imaging.ps1 new file mode 100644 index 00000000..38b48b4c --- /dev/null +++ b/WK_64/Scripts/imaging.ps1 @@ -0,0 +1,467 @@ +# WK imaging functions + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 + +# Functions +function apply-image { + # Apply a Windows image to W:\ + Param([string]$image, [string]$name) + $path = "" + $split_image = $false + $split_image_pattern = "" + + # Check for source image + ## This checks all drive letters for the source image. + ## It starts with local sources and then tries the server(s) (usually Y: and Z:) + $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) + foreach ($v in $volumes) { + $letter = $v.DriveLetter + ":" + if (Test-Path "$letter\sources\$image.wim") { + $path = "$letter\sources\$image.wim" + } elseif (Test-Path "$letter\sources\$image.esd") { + $path = "$letter\sources\$image.esd" + } elseif (Test-Path "$letter\sources\$image.swm") { + $path = "$letter\sources\$image.swm" + $split_image = $true + $split_image_pattern = "$letter\sources\$image*.swm" + } + } + + # Check for FQDN remote source (if necessary) + if ($path -imatch '^$') { + # Temporarily set path to network source + $path = "\\$source_server\Windows\$image" + wk-warn "Searching for network source" + if (Test-Path "$path.wim") { + $path = "$path.wim" + } elseif (Test-Path "$path.esd") { + $path = "$path.esd" + } elseif (Test-Path "$path.swm") { + $path = "$path.swm" + $split_image = $true + $split_image_pattern = "$path*.swm" + } else { + # Revert to empty path if nothing found. + $path = "" + } + } + + # Expand Image + if ($path -imatch 'Win\d+\.(esd|wim)$') { + wk-write " Applying image..." + Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' | out-null + } elseif ($path -imatch 'Win\d+\.swm$') { + wk-write " Applying split-image..." + Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" | out-null + } else { + wk-error "Image not found." + throw + } +} +function format-gpt { + Param($dest_disk) + wk-write "Drive will use a GPT (UEFI) layout." + + # Double-check we have the right drive + ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets + $_sel_uid = $dest_disk.Guid + if ($dest_disk.PartitionStyle -imatch "MBR") { + # MBR disks don't have GUIDs and use the signature in hex instead + $_sel_uid = "{0:x}" -f $dest_disk.Signature + } + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "uniqueid disk" + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null + if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { + # GUIDs do not match + wk-error "Diskpart failed to select the same disk for formatting, aborting setup." + wk-warn "This system requires manual formatting & setup" + wk-write "" + throw "Failed to format disk" + } else { + wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) + } + + # Generate Diskpart script and execute + ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: + ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d + ## + ## NOTE 2: This overwrites existing diskpart.script file without confirmation. + $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber + $diskpart_script += "clean`r`n" + $diskpart_script += "convert gpt`r`n" + + # 1. Windows RE tools partition (Windows 8+) + if ($dest_windows_version.Name -imatch '^Windows (8|10)') { + $diskpart_script += "create partition primary size=300`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" + $diskpart_script += "assign letter='T'`r`n" + $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" + $diskpart_script += "gpt attributes=0x8000000000000001`r`n" + } + + # 2. System partition + $diskpart_script += "create partition efi size=260`r`n" + ## NOTE: Allows for Advanced Format 4Kn drives + $diskpart_script += "format quick fs=fat32 label='System'`r`n" + $diskpart_script += "assign letter='S'`r`n" + + # 3. Microsoft Reserved (MSR) partition + $diskpart_script += "create partition msr size=128`r`n" + + # 4. Windows partition + $diskpart_script += "create partition primary`r`n" + $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" + $diskpart_script += "assign letter='W'`r`n" + + # Run script + Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script + Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow | out-null +} +function format-mbr { + Param($dest_disk) + wk-write "Drive will use a MBR (legacy) layout." + + if ($dest_disk.PartitionStyle -inotmatch '^RAW$') { + # Only clean if necessary + clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false | out-null + } + Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' | out-null + New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true | out-null + New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false | out-null + Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' | out-null + Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' | out-null +} +function select-disk { + param([string]$title, [bool]$skip_usb=$false) + $_skipped_parts = 0 + + # Get Disk(s) + if ($skip_usb) { + $disks = @(Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} | Sort-Object -Property "Number") + } else { + $disks = @(Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number") + } + + # Check if any drives were detected + if ($disks.count -eq 0) { + wk-error "No suitable drives were detected." + return $false + } + + # Get selection + $selection = $null + $main_set = @() + if ($disks.count -eq 1) { + # Only one disk is available + $selection = $disks[0] + } else { + # Multiple options. Build and use menu + foreach ($_ in $disks) { + $_entry = "{0}`t[{1}] ({2}) {3}" -f (human-size $_.Size 0), $_.PartitionStyle, $_.BusType, $_.FriendlyName + $main_set += @{Name=$_entry} + } + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select $title $main_set $actions) + } + + if ($selection -imatch '^\d+$') { + $selection -= 1 + return $disks[$selection] + } else { + return $selection + } +} +function menu-imaging { + wk-write "Drive Imaging" + wk-write "" + + # Pre-emptively mount Server(s) + ## Helps ensure a successfull backup and/or setup + mount-servers + + ## WARNING + wk-warn "WARNING: This section is experimental" + pause + ## WARNING + + # Service Order + $menu_service_order += "Please enter the service order`r`n" + do { + clear + $service_order = read-host -prompt $menu_service_order + } until ($service_order -imatch '^\d[\w\-]+$') + + # Select Disk + $disk = (select-disk "For which drive are we creating backup image(s)?") + + if (!($disk)) { + # No drives detected or user aborted + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($disk -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($disk.DiskNumber -imatch '^\d+$') { + # Valid disk selected + clear + wk-write ("Disk:`t{0}`t[{1}] ({2}) {3}" -f (human-size $disk.Size 0), $disk.PartitionStyle, $disk.BusType, $disk.FriendlyName) + wk-write "Partition(s):" + + # Print partition info + $partitions = Get-Partition -DiskNumber $disk.DiskNumber + $_skipped_parts = 0 + foreach ($_p in $partitions) { + # Assign letter + Add-PartitionAccessPath -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null + + # Update partition info + $_p = Get-Partition -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber + $_v = Get-Volume -Partition $_p + + # Set size label + $_size = (human-size $_p.size 0) + $_used = "" + if ($_v) { + $_used = "({0} used)" -f (human-size ($_v.Size - $_v.SizeRemaining) 0) + } + + # Print partition info + if ($_p.AccessPaths) { + # Has drive letter + $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + $_label = " {0}" -f $_p.Type + if ($_v -and $_v.FileSystemLabel -ne "") { + $_label = '"{0}"' -f $_v.FileSystemLabel + } + $_msg = " {0:N0}:`t{1} ({2,6}) {3} {4}" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used + wk-write "$_msg" + } else { + # No drive letter + $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type + wk-error "$_msg" + $_skipped_parts += 1 + } + } + if ($_skipped_parts -gt 0) { + wk-warn " *`tUnable to backup these partition(s)" + } + wk-write "" + if (!(ask " Backup these partition(s)?")) { + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + wk-write "" + + # Select Server + $server = (select-server) + if (!($server)) { + # No servers detected + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($server -imatch '^M$') { + # User selected to return to the menu + return + } + wk-write "" + wk-write ("Saving partition backups to: {0}" -f $server.Description) + wk-write "" + + # Backup partitions + $partitions = Get-Partition -DiskNumber $disk.DiskNumber + foreach ($_p in $partitions) { + $_v = Get-Volume -Partition $_p + + $_name = "{0}" -f $_p.PartitionNumber + if ($_v -and $_v.FileSystemLabel -ne "") { + $_name += "_{0}" -f $_v.FileSystemLabel + } else { + $_name += "_{0}" -f $_p.Type + } + # Sanitize the name + $_name = $_name -replace '\s', '_' + + $_imagepath = "{0}{1}" -f $server.Root, $service_order + $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name + + if ($_p.AccessPaths -ne $null) { + # Avoid unwanted clobbering + if (Test-Path "$_imagefile") { + if (!(ask ("Overwrite backup image: {0}" -f $_imagefile))) { + wk-warn "Drive Imaging aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + $_capturedir = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} + + # Take image + wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) + if (!(Test-Path "$_imagepath")) { + mkdir "$_imagepath" | out-null + } + $_dism_args = @( + "/Capture-Image", + "/ImageFile:$_imagefile", + "/CaptureDir:$_capturedir", + "/Name:$_name", + "/Compress:fast", + "/Quiet") + Start-Process "$windir\System32\Dism.exe" -ArgumentList $_dism_args -NoNewWindow -Wait | out-null + + ## The following command fails to capture OS partitions consitantly. Until this is fixed I will use DISM directly (as above). + #New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturedir" -Name "$_name" -CompressionType "fast" | out-null + + # Verify image + ## Code borrowed from: https://stackoverflow/a/10262275 + $pinfo = New-Object System.Diagnostics.ProcessStartInfo + $pinfo.FileName = "$WKPath\7-Zip\7z.exe" + $pinfo.RedirectStandardError = $true + $pinfo.RedirectStandardOutput = $true + $pinfo.UseShellExecute = $false + $pinfo.Arguments = 't "{0}"' -f $_imagefile + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $pinfo + $p.Start() | Out-Null + write-host " Verifying . . . " -NoNewline + $p.WaitForExit() + if ($p.ExitCode -eq 0) { + write-host "Complete." -foreground "green" + } else { + write-host "Failed." -foreground "red" + } + } + } + pause "Press Enter to return to main menu... " +} +function menu-setup { + # Pre-emptively mount Server(s) + ## Helps ensure a successfull backup and/or setup + mount-servers + + # Select Disk + $dest_disk = (select-disk "To which drive are we installing Windows?" -skip_usb=$true) + + if (!($dest_disk)) { + # No drives detected or user aborted + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } elseif ($dest_disk -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($dest_disk.DiskNumber -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + wk-warn "All data will be deleted from the following drive:" + wk-warn ("`t{0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (!(ask "Proceed and install Windows?")) { + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + } + + # Set available Windows versions + $windows_versions = @( + @{Name="Windows 7 Home Basic"; ImageFile="Win7"; ImageName="Windows 7 HOMEBASIC"} + @{Name="Windows 7 Home Premium"; ImageFile="Win7"; ImageName="Windows 7 HOMEPREMIUM"} + @{Name="Windows 7 Professional"; ImageFile="Win7"; ImageName="Windows 7 PROFESSIONAL"} + @{Name="Windows 7 Ultimate"; ImageFile="Win7"; ImageName="Windows 7 ULTIMATE"} + + @{Name="Windows 8.1"; ImageFile="Win8"; ImageName="Windows 8.1"; CRLF=$true} + @{Name="Windows 8.1 Pro"; ImageFile="Win8"; ImageName="Windows 8.1 Pro"} + + # The ISOs from the MediaCreationTool are apparently Technical Previews + @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Technical Preview"; CRLF=$true} + @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro Technical Preview"} + ) + + # Build menu and get selection + $dest_windows_version = $null + $selection = $null + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select "Which version of Windows are we installing?" $windows_versions $actions) + + if ($selection -imatch '^M$') { + # User selected to return to the menu + return $false + } elseif ($selection -inotmatch '^\d+$') { + # This shouldn't happen? + throw + } else { + $selection -= 1 + $dest_windows_version = $windows_versions[$selection] + } + + # Double check before deleting data + wk-warn "SAFTEY CHECK:" + wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) + wk-error (" And ERASING:`tDisk: {0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) + if (!(ask "Is this correct?")) { + wk-warn "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } + + ## WARNING + wk-warn "WARNING: This section is experimental" + ## WARNING + + ## Here be dragons + try { + # Select UEFI or BIOS partition layout + if ($UEFI) { + # System booted via UEFI so assume new layout should be GPT + if (ask "Setup drive using GPT (UEFI) layout?") { + format-gpt $dest_disk + } else { + format-mbr $dest_disk + } + } else{ + if (ask "Setup drive using MBR (legacy) layout?") { + format-mbr $dest_disk + } else { + format-gpt $dest_disk + } + } + + # Apply image + apply-image $dest_windows_version.ImageFile $dest_windows_version.ImageName + + # Create boot files (copies files for both Legacy and UEFI) + wk-write " Copying boot files..." + bcdboot W:\Windows /s S: /f ALL 2>&1 | out-null + if ($dest_windows_version.Name -imatch '^Windows (8|10)') { + W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows 2>&1 | out-null + } + + # Done + wk-write "Windows Setup complete." + wk-write "" + pause "Press Enter to return to main menu... " + } catch { + # Error(s) + wk-error "$Error" + wk-error "Windows Setup aborted." + wk-write "" + pause "Press Enter to return to main menu... " -warning=$true + return $false + } +} diff --git a/WK_64/Scripts/init.ps1 b/WK_64/Scripts/init.ps1 new file mode 100644 index 00000000..b198fdd8 --- /dev/null +++ b/WK_64/Scripts/init.ps1 @@ -0,0 +1,158 @@ +# WK-Init +# +# Some common settings and functions + +$host.UI.RawUI.BackgroundColor = "black" +$host.UI.RawUI.ForegroundColor = "cyan" +#$appdata = (gci env:appdata).value +#$localappdata = (gci env:localappdata).value +#$username = (gci env:username).value +#$userprofile = (gci env:userprofile).value +$systemdrive = (gci env:systemdrive).value +$windir = (gci env:windir).value +#$programfiles = (gci env:programfiles).value +#$programfiles86 = $programfiles +#if (test-path env:"programfiles(x86)") { +# $programfiles86 = (gci env:"programfiles(x86)").value +#} +$WKPath = "$systemdrive\WK" +$date = get-date -uformat "%Y-%m-%d" +#$logpath = "$WKPath\Info\$date" + +# Check if booted via UEFI +$UEFI = $false +if ((Get-ItemProperty -path "HKLM:\System\CurrentControlSet\Control").PEFirmwareType -eq 2) { + $UEFI = $true +} + +function ask { + param([string]$text = "Kotaero", [string]$log = "WK.log") + $answered = $false + $text += " [Y/N]" + while (!$answered) { + $answer = read-host $text + if ($answer -imatch '^(y|yes)$') { + $answer = $true + $answered = $true + } elseif ($answer -imatch '^(n|no)$') { + $answer = $false + $answered = $true + } + } + $text += ": $answer" + out-file -filepath $log -inputobject $text -append + return $answer +} +function wk-error { + param([string]$text = "ERROR", [string]$log = "WK.log") + write-host ($text) -foreground "red" + out-file -filepath $log -inputobject $text -append +} +function wk-warn { + param([string]$text = "WARNING", [string]$log = "WK.log") + write-host ($text) -foreground "yellow" + out-file -filepath $log -inputobject $text -append +} +function wk-write { + param([string]$text = "", [string]$log = "WK.log") + write-host ($text) + out-file -filepath $log -inputobject $text -append +} +function human-size { + param($bytes, [int]$decimals = 2) + if ($bytes -gt 1Tb) { + $size = "{0:N$decimals} Tb" -f ($bytes / 1Tb) + } elseif ($bytes -gt 1Gb) { + $size = "{0:N$decimals} Gb" -f ($bytes / 1Gb) + } elseif ($bytes -gt 1Mb) { + $size = "{0:N$decimals} Mb" -f ($bytes / 1Mb) + } elseif ($bytes -gt 1Kb) { + $size = "{0:N$decimals} Kb" -f ($bytes / 1Kb) + } else { + $size = "{0:N$decimals} b" -f $bytes + } + return $size +} +function menu-select { + ## $MainEntries should be an "AoH" object (with at least the key "Name" for each item) + ## NOTE: if the CRLF=$true; then a spacer is added before that entry. + ## Example: + ## $MainEntries = @( + ## @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"} + ## @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} + ##) + + ## $ActionEntries should be an "AoH" object (with at least the keys "Name" and "Letter" for each item) + ## NOTE: if the CRLF=$true; then a spacer is added before that entry. + ## Example: + ## $ActionEntries = @( + ## @{Name="Reboot"; Letter="R"} + ## @{Name="Shutdown"; Letter="S"} + ##) + + param( + [string]$Title = "## Untitled Menu ##", + $MainEntries = @(), + $ActionEntries = @(), + [string]$Prompt = "Please make a selection", + [bool]$SecretExit = $false + ) + + # Bail early if no items given + if ($MainEntries.length -eq 0 -and $ActionEntries.length -eq 0) { + throw "MenuError: No items given." + } + + # Build menu + $menu_splash = "{0}`r`n`r`n" -f $title + $valid_answers = @() + if ($SecretExit) { + $valid_answers += "Q" + } + + # Add main items to splash + if ($MainEntries.length -gt 0) { + for ($i=0; $i -lt $MainEntries.length; $i++) { + if ($MainEntries[$i].CRLF) { + # Add spacer + $menu_splash += "`r`n" + } + $valid_answers += ($i + 1) + $menu_splash += "{0,2:N0}: {1}`r`n" -f ($i + 1), $MainEntries[$i].Name + } + $menu_splash += "`r`n" + } + + # Add action items to splash + if ($ActionEntries.length -gt 0) { + foreach ($_item in $ActionEntries) { + if ($_item.CRLF) { + # Add spacer + $menu_splash += "`r`n" + } + $menu_splash += " {0}: {1}`r`n" -f $_item.Letter.ToUpper(), $_item.Name + $valid_answers += $_item.Letter.ToLower(), $_item.Letter.ToUpper() + } + $menu_splash += "`r`n" + } + + # Add prompt to splash + $menu_splash += "{0}`r`n" -f $prompt + + # Select Windows version + do { + clear + $answer = read-host -prompt $menu_splash + } until ($valid_answers -contains $answer) + + return $answer.ToUpper() +} +function pause { + param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) + if ($warning) { + write-host ($message) -foreground "yellow" + } else { + write-host ($message) + } + $x = read-host +} diff --git a/WK_64/Scripts/servers.ps1 b/WK_64/Scripts/servers.ps1 new file mode 100644 index 00000000..2d47e19f --- /dev/null +++ b/WK_64/Scripts/servers.ps1 @@ -0,0 +1,85 @@ +# WK server functions + +## Init ## +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +pushd "$wd" +. .\init.ps1 + +# Variables +$source_server = "10.0.0.10" +$backup_servers = @( + @{ "ip"="10.0.0.10"; + "letter"="Z"; + "name"="ServerOne"; + "path"="Backups"}, + @{ "ip"="10.0.0.11"; + "name"="ServerTwo"; + "letter"="Y"; + "path"="Backups"} + ) +$backup_user = "backup" +$backup_pass = "Abracadabra" + +# Functions +function select-server { + # Check for available servers + $avail_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) + if ($avail_servers.count -eq 0) { + wk-error "No suitable backup servers were detected." + return $false + } + + # Build menu and get selection + $selection = $null + $main_set = @() + foreach ($server in $avail_servers) { + $_entry = "{0} ({1} free)" -f $server.Description, (human-size $server.Free) + $main_set += @{Name=$_entry} + } + $actions = @(@{Name="Main Menu"; Letter="M"}) + $selection = (menu-select "Where are we saving the backup image(s)?" $main_set $actions) + + if ($selection -imatch '^\d+$') { + $selection -= 1 + return $avail_servers[$selection] + } + return $selection +} +function mount-servers { + # Mount servers + wk-write "Connecting to backup server(s)" + foreach ($_server in $backup_servers) { + if (test-connection $_server.ip -count 3 -quiet) { + try { + $_path = "\\{0}\{1}" -f $_server.ip, $_server.path + $_drive = "{0}:" -f $_server.letter + net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null + wk-write ("`t{0} server: mounted" -f $_server.name) + + # Add friendly description + $_regex = "^{0}$" -f $_server.letter + (Get-PSDrive | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name + } catch { + wk-warn ("`t{0} server: failed" -f $_server.name) + } + } else { + wk-warn ("`t{0} server: timed-out" -f $_server.name) + } + } +} +function unmount-servers { + # Unmount servers + wk-write "Disconnecting from backup server(s)" + $mounted_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) + foreach ($_server in $mounted_servers) { + try { + $_drive = "{0}:" -f $_server.Name + net use $_drive /delete | Out-Null + #wk-warn ("`t{0} server: unmounted" -f $_server.name) + wk-warn "`tServer: unmounted" + } catch { + #wk-warn ("`t{0} server: failed" -f $_server.name) + wk-warn "`tServer: failed" + } + } +} From 919c4e73a2d4b2b8c896d3f028c4a6a6e4a994e6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:01:27 -0800 Subject: [PATCH 06/85] 2016-04: Retroactive Updates * Finished code for 32-bit and 64-bit builds * Unified scripts for use under both builds --- {WK_32/Scripts => Scripts}/WK.ps1 | 6 +- {WK_32/Scripts => Scripts}/imaging.ps1 | 14 +- {WK_32/Scripts => Scripts}/init.ps1 | 0 {WK_32/Scripts => Scripts}/servers.ps1 | 0 System32/Winpeshl.ini | 2 +- System32/menu.cmd | 2 +- {WK_32 => WK/amd64}/CPU-Z/cpuz.ini | 0 {WK_32 => WK/amd64}/ConEmu/ConEmu.xml | 0 {WK_32 => WK/amd64}/Explorer++/config.xml | 0 {WK_32 => WK/amd64}/HWMonitor/hwmonitorw.ini | 0 {WK_32 => WK/amd64}/Notepad2/Notepad2.ini | 0 {WK_64 => WK/x86}/CPU-Z/cpuz.ini | 0 {WK_64 => WK/x86}/ConEmu/ConEmu.xml | 0 {WK_64 => WK/x86}/Explorer++/config.xml | 0 {WK_64 => WK/x86}/HWMonitor/hwmonitorw.ini | 0 {WK_64 => WK/x86}/Notepad2/Notepad2.ini | 0 WK_64/Scripts/WK.ps1 | 116 ----- WK_64/Scripts/imaging.ps1 | 467 ------------------- WK_64/Scripts/init.ps1 | 158 ------- WK_64/Scripts/servers.ps1 | 85 ---- make-cd.cmd | 37 -- make.cmd | 246 ++++++---- 22 files changed, 176 insertions(+), 957 deletions(-) rename {WK_32/Scripts => Scripts}/WK.ps1 (91%) rename {WK_32/Scripts => Scripts}/imaging.ps1 (95%) rename {WK_32/Scripts => Scripts}/init.ps1 (100%) rename {WK_32/Scripts => Scripts}/servers.ps1 (100%) rename {WK_32 => WK/amd64}/CPU-Z/cpuz.ini (100%) rename {WK_32 => WK/amd64}/ConEmu/ConEmu.xml (100%) rename {WK_32 => WK/amd64}/Explorer++/config.xml (100%) rename {WK_32 => WK/amd64}/HWMonitor/hwmonitorw.ini (100%) rename {WK_32 => WK/amd64}/Notepad2/Notepad2.ini (100%) rename {WK_64 => WK/x86}/CPU-Z/cpuz.ini (100%) rename {WK_64 => WK/x86}/ConEmu/ConEmu.xml (100%) rename {WK_64 => WK/x86}/Explorer++/config.xml (100%) rename {WK_64 => WK/x86}/HWMonitor/hwmonitorw.ini (100%) rename {WK_64 => WK/x86}/Notepad2/Notepad2.ini (100%) delete mode 100644 WK_64/Scripts/WK.ps1 delete mode 100644 WK_64/Scripts/imaging.ps1 delete mode 100644 WK_64/Scripts/init.ps1 delete mode 100644 WK_64/Scripts/servers.ps1 delete mode 100644 make-cd.cmd diff --git a/WK_32/Scripts/WK.ps1 b/Scripts/WK.ps1 similarity index 91% rename from WK_32/Scripts/WK.ps1 rename to Scripts/WK.ps1 index bf346b17..d18fc94f 100644 --- a/WK_32/Scripts/WK.ps1 +++ b/Scripts/WK.ps1 @@ -27,16 +27,16 @@ function menu-tools { # Avail tools $tools = @( @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView.exe"}, + @{Name="CPU-Z"; Folder="CPU-Z"; File="cpuz.exe"}, @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++.exe"}, @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor.exe"}, @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit.exe"}, @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod.exe"}, + @{Name="PhotoRec"; Folder="TestDisk"; File="photorec_win.exe"}, @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, @{Name="ProduKey"; Folder="ProduKey"; File="ProduKey.exe"}, - @{Name="PhotoRec (GUI)"; Folder="TestDisk"; File="qphotorec_win.exe"}, - @{Name="PhotoRec (CLI)"; Folder="TestDisk"; File="photorec_win.exe"}, - @{Name="TestDisk (CLI)"; Folder="TestDisk"; File="testdisk_win.exe"} + @{Name="TestDisk"; Folder="TestDisk"; File="testdisk_win.exe"} ) # Build menu diff --git a/WK_32/Scripts/imaging.ps1 b/Scripts/imaging.ps1 similarity index 95% rename from WK_32/Scripts/imaging.ps1 rename to Scripts/imaging.ps1 index 38b48b4c..a8a4e540 100644 --- a/WK_32/Scripts/imaging.ps1 +++ b/Scripts/imaging.ps1 @@ -19,14 +19,14 @@ function apply-image { $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) foreach ($v in $volumes) { $letter = $v.DriveLetter + ":" - if (Test-Path "$letter\sources\$image.wim") { - $path = "$letter\sources\$image.wim" - } elseif (Test-Path "$letter\sources\$image.esd") { - $path = "$letter\sources\$image.esd" - } elseif (Test-Path "$letter\sources\$image.swm") { - $path = "$letter\sources\$image.swm" + if (Test-Path "$letter\images\$image.wim") { + $path = "$letter\images\$image.wim" + } elseif (Test-Path "$letter\images\$image.esd") { + $path = "$letter\images\$image.esd" + } elseif (Test-Path "$letter\images\$image.swm") { + $path = "$letter\images\$image.swm" $split_image = $true - $split_image_pattern = "$letter\sources\$image*.swm" + $split_image_pattern = "$letter\images\$image*.swm" } } diff --git a/WK_32/Scripts/init.ps1 b/Scripts/init.ps1 similarity index 100% rename from WK_32/Scripts/init.ps1 rename to Scripts/init.ps1 diff --git a/WK_32/Scripts/servers.ps1 b/Scripts/servers.ps1 similarity index 100% rename from WK_32/Scripts/servers.ps1 rename to Scripts/servers.ps1 diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index 313d0a7b..ed840fb7 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,4 +2,4 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -"%SystemDrive%\WK\ConEmu\ConEmu64.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n \ No newline at end of file +"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n diff --git a/System32/menu.cmd b/System32/menu.cmd index eb9c80be..c433ff39 100644 --- a/System32/menu.cmd +++ b/System32/menu.cmd @@ -12,7 +12,7 @@ for %%f in (%*) do ( ) :LaunchMenu -"%SystemDrive%\WK\ConEmu\ConEmu64.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n +"%SystemDrive%\WK\ConEmu\ConEmu.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n goto Done :Abort diff --git a/WK_32/CPU-Z/cpuz.ini b/WK/amd64/CPU-Z/cpuz.ini similarity index 100% rename from WK_32/CPU-Z/cpuz.ini rename to WK/amd64/CPU-Z/cpuz.ini diff --git a/WK_32/ConEmu/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml similarity index 100% rename from WK_32/ConEmu/ConEmu.xml rename to WK/amd64/ConEmu/ConEmu.xml diff --git a/WK_32/Explorer++/config.xml b/WK/amd64/Explorer++/config.xml similarity index 100% rename from WK_32/Explorer++/config.xml rename to WK/amd64/Explorer++/config.xml diff --git a/WK_32/HWMonitor/hwmonitorw.ini b/WK/amd64/HWMonitor/hwmonitorw.ini similarity index 100% rename from WK_32/HWMonitor/hwmonitorw.ini rename to WK/amd64/HWMonitor/hwmonitorw.ini diff --git a/WK_32/Notepad2/Notepad2.ini b/WK/amd64/Notepad2/Notepad2.ini similarity index 100% rename from WK_32/Notepad2/Notepad2.ini rename to WK/amd64/Notepad2/Notepad2.ini diff --git a/WK_64/CPU-Z/cpuz.ini b/WK/x86/CPU-Z/cpuz.ini similarity index 100% rename from WK_64/CPU-Z/cpuz.ini rename to WK/x86/CPU-Z/cpuz.ini diff --git a/WK_64/ConEmu/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml similarity index 100% rename from WK_64/ConEmu/ConEmu.xml rename to WK/x86/ConEmu/ConEmu.xml diff --git a/WK_64/Explorer++/config.xml b/WK/x86/Explorer++/config.xml similarity index 100% rename from WK_64/Explorer++/config.xml rename to WK/x86/Explorer++/config.xml diff --git a/WK_64/HWMonitor/hwmonitorw.ini b/WK/x86/HWMonitor/hwmonitorw.ini similarity index 100% rename from WK_64/HWMonitor/hwmonitorw.ini rename to WK/x86/HWMonitor/hwmonitorw.ini diff --git a/WK_64/Notepad2/Notepad2.ini b/WK/x86/Notepad2/Notepad2.ini similarity index 100% rename from WK_64/Notepad2/Notepad2.ini rename to WK/x86/Notepad2/Notepad2.ini diff --git a/WK_64/Scripts/WK.ps1 b/WK_64/Scripts/WK.ps1 deleted file mode 100644 index bf346b17..00000000 --- a/WK_64/Scripts/WK.ps1 +++ /dev/null @@ -1,116 +0,0 @@ -# WK-Checklist - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 -. .\servers.ps1 -. .\imaging.ps1 -clear -$host.UI.RawUI.WindowTitle = "WK PE Tool" -$logpath = "$WKPath\Info\$date" -md "$logpath" 2>&1 | Out-Null -$log = "$logpath\winpe.log" - -# Functions -function wk-exit { - param([string]$action) - switch ($action) { - 'Q' {PowerShell -ExecutionPolicy Bypass; break} - 'R' {wpeutil reboot; break} - 'S' {wpeutil shutdown; break} - default {throw} - } - exit 0 -} -function menu-tools { - # Avail tools - $tools = @( - @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView.exe"}, - @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++.exe"}, - @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, - @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor.exe"}, - @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit.exe"}, - @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod.exe"}, - @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, - @{Name="ProduKey"; Folder="ProduKey"; File="ProduKey.exe"}, - @{Name="PhotoRec (GUI)"; Folder="TestDisk"; File="qphotorec_win.exe"}, - @{Name="PhotoRec (CLI)"; Folder="TestDisk"; File="photorec_win.exe"}, - @{Name="TestDisk (CLI)"; Folder="TestDisk"; File="testdisk_win.exe"} - ) - - # Build menu - $selection = $null - $actions = @(@{Name="Main Menu"; Letter="M"}) - - # Run Loop - $_done = $false - do { - $selection = (menu-select "Tools Menu" $tools $actions) - - if ($selection -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - $selection -= 1 - $path = "{0}\{1}" -f $WKPath, $tools[$selection].Folder - if ($tools[$selection].ContainsKey("Args")) { - Start-Process $tools[$selection].File -ArgumentList $tools[$selection].Args -WorkingDirectory $path - } else { - Start-Process $tools[$selection].File -WorkingDirectory $path - } - } - } until ($_done) -} -function menu-main { - # Build menu - $selection = $null - $menus = @( - @{Name="Drive Imaging"; Menu="menu-imaging"} - @{Name="Windows Setup"; Menu="menu-setup"} - @{Name="Misc Tools"; Menu="menu-tools"} - ) - $actions = @( - @{Name="Command Prompt"; Letter="C"} - @{Name="PowerShell"; Letter="P"} - @{Name="Reboot"; Letter="R"} - @{Name="Shutdown"; Letter="S"} - ) - - # Show Menu - $selection = (menu-select "Main Menu" $menus $actions -SecretExit $true) - - if ($selection -imatch '^C$') { - Start-Process "$windir\System32\cmd.exe" -argumentlist @("-new_console:n") -WorkingDirectory "$WKPath" - return - } elseif ($selection -imatch '^P$') { - Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-new_console:n") -WorkingDirectory "$WKPath" - return - } elseif ($selection -imatch '^[QRS]$') { - wk-exit $selection - return - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - # Launch sub-menu - $selection -= 1 - & $menus[$selection].Menu - } -} - -# Mount all partitions -foreach ($_d in @(Get-Disk)) { - foreach ($_p in @(Get-Partition -DiskNumber $_d.DiskNumber)) { - # Assign letter - Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null - } -} - -# Main Loop -do { - menu-main -} while ($true) diff --git a/WK_64/Scripts/imaging.ps1 b/WK_64/Scripts/imaging.ps1 deleted file mode 100644 index 38b48b4c..00000000 --- a/WK_64/Scripts/imaging.ps1 +++ /dev/null @@ -1,467 +0,0 @@ -# WK imaging functions - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 - -# Functions -function apply-image { - # Apply a Windows image to W:\ - Param([string]$image, [string]$name) - $path = "" - $split_image = $false - $split_image_pattern = "" - - # Check for source image - ## This checks all drive letters for the source image. - ## It starts with local sources and then tries the server(s) (usually Y: and Z:) - $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) - foreach ($v in $volumes) { - $letter = $v.DriveLetter + ":" - if (Test-Path "$letter\sources\$image.wim") { - $path = "$letter\sources\$image.wim" - } elseif (Test-Path "$letter\sources\$image.esd") { - $path = "$letter\sources\$image.esd" - } elseif (Test-Path "$letter\sources\$image.swm") { - $path = "$letter\sources\$image.swm" - $split_image = $true - $split_image_pattern = "$letter\sources\$image*.swm" - } - } - - # Check for FQDN remote source (if necessary) - if ($path -imatch '^$') { - # Temporarily set path to network source - $path = "\\$source_server\Windows\$image" - wk-warn "Searching for network source" - if (Test-Path "$path.wim") { - $path = "$path.wim" - } elseif (Test-Path "$path.esd") { - $path = "$path.esd" - } elseif (Test-Path "$path.swm") { - $path = "$path.swm" - $split_image = $true - $split_image_pattern = "$path*.swm" - } else { - # Revert to empty path if nothing found. - $path = "" - } - } - - # Expand Image - if ($path -imatch 'Win\d+\.(esd|wim)$') { - wk-write " Applying image..." - Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' | out-null - } elseif ($path -imatch 'Win\d+\.swm$') { - wk-write " Applying split-image..." - Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" | out-null - } else { - wk-error "Image not found." - throw - } -} -function format-gpt { - Param($dest_disk) - wk-write "Drive will use a GPT (UEFI) layout." - - # Double-check we have the right drive - ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets - $_sel_uid = $dest_disk.Guid - if ($dest_disk.PartitionStyle -imatch "MBR") { - # MBR disks don't have GUIDs and use the signature in hex instead - $_sel_uid = "{0:x}" -f $dest_disk.Signature - } - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "uniqueid disk" - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null - if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { - # GUIDs do not match - wk-error "Diskpart failed to select the same disk for formatting, aborting setup." - wk-warn "This system requires manual formatting & setup" - wk-write "" - throw "Failed to format disk" - } else { - wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) - } - - # Generate Diskpart script and execute - ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: - ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d - ## - ## NOTE 2: This overwrites existing diskpart.script file without confirmation. - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "clean`r`n" - $diskpart_script += "convert gpt`r`n" - - # 1. Windows RE tools partition (Windows 8+) - if ($dest_windows_version.Name -imatch '^Windows (8|10)') { - $diskpart_script += "create partition primary size=300`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" - $diskpart_script += "assign letter='T'`r`n" - $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" - $diskpart_script += "gpt attributes=0x8000000000000001`r`n" - } - - # 2. System partition - $diskpart_script += "create partition efi size=260`r`n" - ## NOTE: Allows for Advanced Format 4Kn drives - $diskpart_script += "format quick fs=fat32 label='System'`r`n" - $diskpart_script += "assign letter='S'`r`n" - - # 3. Microsoft Reserved (MSR) partition - $diskpart_script += "create partition msr size=128`r`n" - - # 4. Windows partition - $diskpart_script += "create partition primary`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" - $diskpart_script += "assign letter='W'`r`n" - - # Run script - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow | out-null -} -function format-mbr { - Param($dest_disk) - wk-write "Drive will use a MBR (legacy) layout." - - if ($dest_disk.PartitionStyle -inotmatch '^RAW$') { - # Only clean if necessary - clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false | out-null - } - Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' | out-null - New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true | out-null - New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false | out-null - Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' | out-null - Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' | out-null -} -function select-disk { - param([string]$title, [bool]$skip_usb=$false) - $_skipped_parts = 0 - - # Get Disk(s) - if ($skip_usb) { - $disks = @(Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} | Sort-Object -Property "Number") - } else { - $disks = @(Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number") - } - - # Check if any drives were detected - if ($disks.count -eq 0) { - wk-error "No suitable drives were detected." - return $false - } - - # Get selection - $selection = $null - $main_set = @() - if ($disks.count -eq 1) { - # Only one disk is available - $selection = $disks[0] - } else { - # Multiple options. Build and use menu - foreach ($_ in $disks) { - $_entry = "{0}`t[{1}] ({2}) {3}" -f (human-size $_.Size 0), $_.PartitionStyle, $_.BusType, $_.FriendlyName - $main_set += @{Name=$_entry} - } - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select $title $main_set $actions) - } - - if ($selection -imatch '^\d+$') { - $selection -= 1 - return $disks[$selection] - } else { - return $selection - } -} -function menu-imaging { - wk-write "Drive Imaging" - wk-write "" - - # Pre-emptively mount Server(s) - ## Helps ensure a successfull backup and/or setup - mount-servers - - ## WARNING - wk-warn "WARNING: This section is experimental" - pause - ## WARNING - - # Service Order - $menu_service_order += "Please enter the service order`r`n" - do { - clear - $service_order = read-host -prompt $menu_service_order - } until ($service_order -imatch '^\d[\w\-]+$') - - # Select Disk - $disk = (select-disk "For which drive are we creating backup image(s)?") - - if (!($disk)) { - # No drives detected or user aborted - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($disk -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($disk.DiskNumber -imatch '^\d+$') { - # Valid disk selected - clear - wk-write ("Disk:`t{0}`t[{1}] ({2}) {3}" -f (human-size $disk.Size 0), $disk.PartitionStyle, $disk.BusType, $disk.FriendlyName) - wk-write "Partition(s):" - - # Print partition info - $partitions = Get-Partition -DiskNumber $disk.DiskNumber - $_skipped_parts = 0 - foreach ($_p in $partitions) { - # Assign letter - Add-PartitionAccessPath -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null - - # Update partition info - $_p = Get-Partition -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber - $_v = Get-Volume -Partition $_p - - # Set size label - $_size = (human-size $_p.size 0) - $_used = "" - if ($_v) { - $_used = "({0} used)" -f (human-size ($_v.Size - $_v.SizeRemaining) 0) - } - - # Print partition info - if ($_p.AccessPaths) { - # Has drive letter - $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - $_label = " {0}" -f $_p.Type - if ($_v -and $_v.FileSystemLabel -ne "") { - $_label = '"{0}"' -f $_v.FileSystemLabel - } - $_msg = " {0:N0}:`t{1} ({2,6}) {3} {4}" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used - wk-write "$_msg" - } else { - # No drive letter - $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type - wk-error "$_msg" - $_skipped_parts += 1 - } - } - if ($_skipped_parts -gt 0) { - wk-warn " *`tUnable to backup these partition(s)" - } - wk-write "" - if (!(ask " Backup these partition(s)?")) { - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - wk-write "" - - # Select Server - $server = (select-server) - if (!($server)) { - # No servers detected - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($server -imatch '^M$') { - # User selected to return to the menu - return - } - wk-write "" - wk-write ("Saving partition backups to: {0}" -f $server.Description) - wk-write "" - - # Backup partitions - $partitions = Get-Partition -DiskNumber $disk.DiskNumber - foreach ($_p in $partitions) { - $_v = Get-Volume -Partition $_p - - $_name = "{0}" -f $_p.PartitionNumber - if ($_v -and $_v.FileSystemLabel -ne "") { - $_name += "_{0}" -f $_v.FileSystemLabel - } else { - $_name += "_{0}" -f $_p.Type - } - # Sanitize the name - $_name = $_name -replace '\s', '_' - - $_imagepath = "{0}{1}" -f $server.Root, $service_order - $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name - - if ($_p.AccessPaths -ne $null) { - # Avoid unwanted clobbering - if (Test-Path "$_imagefile") { - if (!(ask ("Overwrite backup image: {0}" -f $_imagefile))) { - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - $_capturedir = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - - # Take image - wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) - if (!(Test-Path "$_imagepath")) { - mkdir "$_imagepath" | out-null - } - $_dism_args = @( - "/Capture-Image", - "/ImageFile:$_imagefile", - "/CaptureDir:$_capturedir", - "/Name:$_name", - "/Compress:fast", - "/Quiet") - Start-Process "$windir\System32\Dism.exe" -ArgumentList $_dism_args -NoNewWindow -Wait | out-null - - ## The following command fails to capture OS partitions consitantly. Until this is fixed I will use DISM directly (as above). - #New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturedir" -Name "$_name" -CompressionType "fast" | out-null - - # Verify image - ## Code borrowed from: https://stackoverflow/a/10262275 - $pinfo = New-Object System.Diagnostics.ProcessStartInfo - $pinfo.FileName = "$WKPath\7-Zip\7z.exe" - $pinfo.RedirectStandardError = $true - $pinfo.RedirectStandardOutput = $true - $pinfo.UseShellExecute = $false - $pinfo.Arguments = 't "{0}"' -f $_imagefile - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $pinfo - $p.Start() | Out-Null - write-host " Verifying . . . " -NoNewline - $p.WaitForExit() - if ($p.ExitCode -eq 0) { - write-host "Complete." -foreground "green" - } else { - write-host "Failed." -foreground "red" - } - } - } - pause "Press Enter to return to main menu... " -} -function menu-setup { - # Pre-emptively mount Server(s) - ## Helps ensure a successfull backup and/or setup - mount-servers - - # Select Disk - $dest_disk = (select-disk "To which drive are we installing Windows?" -skip_usb=$true) - - if (!($dest_disk)) { - # No drives detected or user aborted - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($dest_disk -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($dest_disk.DiskNumber -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - wk-warn "All data will be deleted from the following drive:" - wk-warn ("`t{0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (!(ask "Proceed and install Windows?")) { - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - - # Set available Windows versions - $windows_versions = @( - @{Name="Windows 7 Home Basic"; ImageFile="Win7"; ImageName="Windows 7 HOMEBASIC"} - @{Name="Windows 7 Home Premium"; ImageFile="Win7"; ImageName="Windows 7 HOMEPREMIUM"} - @{Name="Windows 7 Professional"; ImageFile="Win7"; ImageName="Windows 7 PROFESSIONAL"} - @{Name="Windows 7 Ultimate"; ImageFile="Win7"; ImageName="Windows 7 ULTIMATE"} - - @{Name="Windows 8.1"; ImageFile="Win8"; ImageName="Windows 8.1"; CRLF=$true} - @{Name="Windows 8.1 Pro"; ImageFile="Win8"; ImageName="Windows 8.1 Pro"} - - # The ISOs from the MediaCreationTool are apparently Technical Previews - @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Technical Preview"; CRLF=$true} - @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro Technical Preview"} - ) - - # Build menu and get selection - $dest_windows_version = $null - $selection = $null - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select "Which version of Windows are we installing?" $windows_versions $actions) - - if ($selection -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - $selection -= 1 - $dest_windows_version = $windows_versions[$selection] - } - - # Double check before deleting data - wk-warn "SAFTEY CHECK:" - wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) - wk-error (" And ERASING:`tDisk: {0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (!(ask "Is this correct?")) { - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - - ## WARNING - wk-warn "WARNING: This section is experimental" - ## WARNING - - ## Here be dragons - try { - # Select UEFI or BIOS partition layout - if ($UEFI) { - # System booted via UEFI so assume new layout should be GPT - if (ask "Setup drive using GPT (UEFI) layout?") { - format-gpt $dest_disk - } else { - format-mbr $dest_disk - } - } else{ - if (ask "Setup drive using MBR (legacy) layout?") { - format-mbr $dest_disk - } else { - format-gpt $dest_disk - } - } - - # Apply image - apply-image $dest_windows_version.ImageFile $dest_windows_version.ImageName - - # Create boot files (copies files for both Legacy and UEFI) - wk-write " Copying boot files..." - bcdboot W:\Windows /s S: /f ALL 2>&1 | out-null - if ($dest_windows_version.Name -imatch '^Windows (8|10)') { - W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows 2>&1 | out-null - } - - # Done - wk-write "Windows Setup complete." - wk-write "" - pause "Press Enter to return to main menu... " - } catch { - # Error(s) - wk-error "$Error" - wk-error "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } -} diff --git a/WK_64/Scripts/init.ps1 b/WK_64/Scripts/init.ps1 deleted file mode 100644 index b198fdd8..00000000 --- a/WK_64/Scripts/init.ps1 +++ /dev/null @@ -1,158 +0,0 @@ -# WK-Init -# -# Some common settings and functions - -$host.UI.RawUI.BackgroundColor = "black" -$host.UI.RawUI.ForegroundColor = "cyan" -#$appdata = (gci env:appdata).value -#$localappdata = (gci env:localappdata).value -#$username = (gci env:username).value -#$userprofile = (gci env:userprofile).value -$systemdrive = (gci env:systemdrive).value -$windir = (gci env:windir).value -#$programfiles = (gci env:programfiles).value -#$programfiles86 = $programfiles -#if (test-path env:"programfiles(x86)") { -# $programfiles86 = (gci env:"programfiles(x86)").value -#} -$WKPath = "$systemdrive\WK" -$date = get-date -uformat "%Y-%m-%d" -#$logpath = "$WKPath\Info\$date" - -# Check if booted via UEFI -$UEFI = $false -if ((Get-ItemProperty -path "HKLM:\System\CurrentControlSet\Control").PEFirmwareType -eq 2) { - $UEFI = $true -} - -function ask { - param([string]$text = "Kotaero", [string]$log = "WK.log") - $answered = $false - $text += " [Y/N]" - while (!$answered) { - $answer = read-host $text - if ($answer -imatch '^(y|yes)$') { - $answer = $true - $answered = $true - } elseif ($answer -imatch '^(n|no)$') { - $answer = $false - $answered = $true - } - } - $text += ": $answer" - out-file -filepath $log -inputobject $text -append - return $answer -} -function wk-error { - param([string]$text = "ERROR", [string]$log = "WK.log") - write-host ($text) -foreground "red" - out-file -filepath $log -inputobject $text -append -} -function wk-warn { - param([string]$text = "WARNING", [string]$log = "WK.log") - write-host ($text) -foreground "yellow" - out-file -filepath $log -inputobject $text -append -} -function wk-write { - param([string]$text = "", [string]$log = "WK.log") - write-host ($text) - out-file -filepath $log -inputobject $text -append -} -function human-size { - param($bytes, [int]$decimals = 2) - if ($bytes -gt 1Tb) { - $size = "{0:N$decimals} Tb" -f ($bytes / 1Tb) - } elseif ($bytes -gt 1Gb) { - $size = "{0:N$decimals} Gb" -f ($bytes / 1Gb) - } elseif ($bytes -gt 1Mb) { - $size = "{0:N$decimals} Mb" -f ($bytes / 1Mb) - } elseif ($bytes -gt 1Kb) { - $size = "{0:N$decimals} Kb" -f ($bytes / 1Kb) - } else { - $size = "{0:N$decimals} b" -f $bytes - } - return $size -} -function menu-select { - ## $MainEntries should be an "AoH" object (with at least the key "Name" for each item) - ## NOTE: if the CRLF=$true; then a spacer is added before that entry. - ## Example: - ## $MainEntries = @( - ## @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"} - ## @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} - ##) - - ## $ActionEntries should be an "AoH" object (with at least the keys "Name" and "Letter" for each item) - ## NOTE: if the CRLF=$true; then a spacer is added before that entry. - ## Example: - ## $ActionEntries = @( - ## @{Name="Reboot"; Letter="R"} - ## @{Name="Shutdown"; Letter="S"} - ##) - - param( - [string]$Title = "## Untitled Menu ##", - $MainEntries = @(), - $ActionEntries = @(), - [string]$Prompt = "Please make a selection", - [bool]$SecretExit = $false - ) - - # Bail early if no items given - if ($MainEntries.length -eq 0 -and $ActionEntries.length -eq 0) { - throw "MenuError: No items given." - } - - # Build menu - $menu_splash = "{0}`r`n`r`n" -f $title - $valid_answers = @() - if ($SecretExit) { - $valid_answers += "Q" - } - - # Add main items to splash - if ($MainEntries.length -gt 0) { - for ($i=0; $i -lt $MainEntries.length; $i++) { - if ($MainEntries[$i].CRLF) { - # Add spacer - $menu_splash += "`r`n" - } - $valid_answers += ($i + 1) - $menu_splash += "{0,2:N0}: {1}`r`n" -f ($i + 1), $MainEntries[$i].Name - } - $menu_splash += "`r`n" - } - - # Add action items to splash - if ($ActionEntries.length -gt 0) { - foreach ($_item in $ActionEntries) { - if ($_item.CRLF) { - # Add spacer - $menu_splash += "`r`n" - } - $menu_splash += " {0}: {1}`r`n" -f $_item.Letter.ToUpper(), $_item.Name - $valid_answers += $_item.Letter.ToLower(), $_item.Letter.ToUpper() - } - $menu_splash += "`r`n" - } - - # Add prompt to splash - $menu_splash += "{0}`r`n" -f $prompt - - # Select Windows version - do { - clear - $answer = read-host -prompt $menu_splash - } until ($valid_answers -contains $answer) - - return $answer.ToUpper() -} -function pause { - param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) - if ($warning) { - write-host ($message) -foreground "yellow" - } else { - write-host ($message) - } - $x = read-host -} diff --git a/WK_64/Scripts/servers.ps1 b/WK_64/Scripts/servers.ps1 deleted file mode 100644 index 2d47e19f..00000000 --- a/WK_64/Scripts/servers.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -# WK server functions - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 - -# Variables -$source_server = "10.0.0.10" -$backup_servers = @( - @{ "ip"="10.0.0.10"; - "letter"="Z"; - "name"="ServerOne"; - "path"="Backups"}, - @{ "ip"="10.0.0.11"; - "name"="ServerTwo"; - "letter"="Y"; - "path"="Backups"} - ) -$backup_user = "backup" -$backup_pass = "Abracadabra" - -# Functions -function select-server { - # Check for available servers - $avail_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - if ($avail_servers.count -eq 0) { - wk-error "No suitable backup servers were detected." - return $false - } - - # Build menu and get selection - $selection = $null - $main_set = @() - foreach ($server in $avail_servers) { - $_entry = "{0} ({1} free)" -f $server.Description, (human-size $server.Free) - $main_set += @{Name=$_entry} - } - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select "Where are we saving the backup image(s)?" $main_set $actions) - - if ($selection -imatch '^\d+$') { - $selection -= 1 - return $avail_servers[$selection] - } - return $selection -} -function mount-servers { - # Mount servers - wk-write "Connecting to backup server(s)" - foreach ($_server in $backup_servers) { - if (test-connection $_server.ip -count 3 -quiet) { - try { - $_path = "\\{0}\{1}" -f $_server.ip, $_server.path - $_drive = "{0}:" -f $_server.letter - net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null - wk-write ("`t{0} server: mounted" -f $_server.name) - - # Add friendly description - $_regex = "^{0}$" -f $_server.letter - (Get-PSDrive | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name - } catch { - wk-warn ("`t{0} server: failed" -f $_server.name) - } - } else { - wk-warn ("`t{0} server: timed-out" -f $_server.name) - } - } -} -function unmount-servers { - # Unmount servers - wk-write "Disconnecting from backup server(s)" - $mounted_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - foreach ($_server in $mounted_servers) { - try { - $_drive = "{0}:" -f $_server.Name - net use $_drive /delete | Out-Null - #wk-warn ("`t{0} server: unmounted" -f $_server.name) - wk-warn "`tServer: unmounted" - } catch { - #wk-warn ("`t{0} server: failed" -f $_server.name) - wk-warn "`tServer: failed" - } - } -} diff --git a/make-cd.cmd b/make-cd.cmd deleted file mode 100644 index 2f7bf210..00000000 --- a/make-cd.cmd +++ /dev/null @@ -1,37 +0,0 @@ -@echo off - -:Init -setlocal EnableDelayedExpansion -title WinPE 10 creation tool -color 1b -pushd %~dp0 -set "wd=%cd%" -set "pe_iso=WinPE-2016-02d.iso" - -:Flags -for %%f in (%*) do ( - if /i "%%f" == "/DEBUG" (@echo on) -) - -:CreateISO -del "!pe_iso!" -makewinpemedia.cmd /iso "%wd%\pe_files" "!pe_iso!" -goto Done - -:Abort -echo. -echo Aborted. -goto Exit - -:Done -echo. -echo Done. -goto Exit - -:Exit -echo. -echo Press any key to exit... -pause>nul -popd -color -endlocal \ No newline at end of file diff --git a/make.cmd b/make.cmd index 5868691b..56207694 100644 --- a/make.cmd +++ b/make.cmd @@ -5,109 +5,191 @@ setlocal EnableDelayedExpansion title WinPE 10 creation tool color 1b pushd %~dp0 -set "wd=%cd%" -set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\amd64\WinPE_OCs" -set "pe_iso=WinPE-2016-02d.iso" :Flags for %%f in (%*) do ( if /i "%%f" == "/DEBUG" (@echo on) ) -:CopyPEFiles -call copype.cmd amd64 "%wd%\pe_files" +:GetDate +:: Credit to SS64.com Code taken from http://ss64.com/nt/syntax-getdate.html +:: Use WMIC to retrieve date and time in ISO 8601 format. +FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO ( +IF "%%~L"=="" goto s_done + Set _yyyy=%%L + Set _mm=00%%J + Set _dd=00%%G + Set _hour=00%%H + SET _minute=00%%I +) +:s_done +:: Pad digits with leading zeros +Set _mm=%_mm:~-2% +Set _dd=%_dd:~-2% +Set _hour=%_hour:~-2% +Set _minute=%_minute:~-2% +Set iso_date=%_yyyy%-%_mm%-%_dd% -:Mount -rem echo Press any key to configure the WinPE image... -rem pause>nul -mkdir "%wd%\mount" -dism /mount-image /imagefile:"%wd%\pe_files\media\sources\boot.wim" /index:1 /mountdir:"%wd%\mount" +:Variables +set "wd=%cd%" +set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment" +set "pe_out=!wd!\pe_out" -:AddPackages -mkdir "%wd%\log" +:CheckForCleanup +echo Scanning for old build folders... +set "found_old=" +if exist "!wd!\mount" ( + echo. Found: "!wd!\mount" + set "found_old=true" +) +if exist "!wd!\pe_files" ( + echo. Found: "!wd!\pe_files" + set "found_old=true" +) +if defined found_old ( + goto Cleanup +) else ( + echo. No build folders found. +) +goto :BuildBoth -:: More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382(v=vs.85).aspx -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-FMAPI.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-WMI.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-WMI_en-us.cab" /logpath:"dism.log" +:Cleanup +echo. +choice /t 30 /c YN /d N /m "Delete the above folders?" +if %errorlevel% neq 1 goto Abort +rmdir /s /q "!wd!\mount" +rmdir /s /q "!wd!\pe_files" -:: Install WinPE-WMI before you install WinPE-NetFX. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-NetFx.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" +:BuildBoth +for %%a in (amd64 x86) do ( + rem set vars + set "arch=%%a" + set "drivers=!wd!\Drivers\!arch!" + set "mount=!wd!\mount\!arch!" + set "pe_files=!wd!\pe_files\!arch!" + set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\!arch!\WinPE_OCs" + + rem Copy main files + call copype.cmd !arch! "!pe_files!" + rmdir /s /q "!pe_files!\media\bg-bg" + rmdir /s /q "!pe_files!\media\cs-cz" + rmdir /s /q "!pe_files!\media\da-dk" + rmdir /s /q "!pe_files!\media\de-de" + rmdir /s /q "!pe_files!\media\el-gr" + rmdir /s /q "!pe_files!\media\en-gb" + rmdir /s /q "!pe_files!\media\es-es" + rmdir /s /q "!pe_files!\media\es-mx" + rmdir /s /q "!pe_files!\media\et-ee" + rmdir /s /q "!pe_files!\media\fi-fi" + rmdir /s /q "!pe_files!\media\fr-ca" + rmdir /s /q "!pe_files!\media\fr-fr" + rmdir /s /q "!pe_files!\media\hr-hr" + rmdir /s /q "!pe_files!\media\hu-hu" + rmdir /s /q "!pe_files!\media\it-it" + rmdir /s /q "!pe_files!\media\ja-jp" + rmdir /s /q "!pe_files!\media\ko-kr" + rmdir /s /q "!pe_files!\media\lt-lt" + rmdir /s /q "!pe_files!\media\lv-lv" + rmdir /s /q "!pe_files!\media\nb-no" + rmdir /s /q "!pe_files!\media\nl-nl" + rmdir /s /q "!pe_files!\media\pl-pl" + rmdir /s /q "!pe_files!\media\pt-br" + rmdir /s /q "!pe_files!\media\pt-pt" + rmdir /s /q "!pe_files!\media\ro-ro" + rmdir /s /q "!pe_files!\media\ru-ru" + rmdir /s /q "!pe_files!\media\sk-sk" + rmdir /s /q "!pe_files!\media\sl-si" + rmdir /s /q "!pe_files!\media\sr-latn-cs" + rmdir /s /q "!pe_files!\media\sr-latn-rs" + rmdir /s /q "!pe_files!\media\sv-se" + rmdir /s /q "!pe_files!\media\tr-tr" + rmdir /s /q "!pe_files!\media\uk-ua" + rmdir /s /q "!pe_files!\media\zh-cn" + rmdir /s /q "!pe_files!\media\zh-hk" + rmdir /s /q "!pe_files!\media\zh-tw" + + rem Mount Image + mkdir "!mount!" + dism /mount-image /imagefile:"!pe_files!\media\sources\boot.wim" /index:1 /mountdir:"!mount!" /logpath:"dism.log" + + rem Add Packages - More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382.aspx + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-EnhancedStorage.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-FMAPI.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-WMI.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-EnhancedStorage_en-us.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-WMI_en-us.cab" /logpath:"dism.log" -:: Install WinPE-WMI > WinPE-NetFX before you install WinPE-Scripting. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-Scripting.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" + rem Install WinPE-WMI before you install WinPE-NetFX. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-NetFx.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" -:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting before you install WinPE-PowerShell. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-PowerShell.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" + rem Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-Scripting.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" -:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-DismCmdlets. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-DismCmdlets.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" + rem Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-PowerShell.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" -:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-SecureBootCmdlets. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" + rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-DismCmdlets.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" -:: Install WinPE-WMI > WinPE-NetFX > WinPE-Scripting > WinPE-PowerShell before you install WinPE-StorageWMI. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-StorageWMI.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" + rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" -:: Install ?? before you install WinPE-EnhancedStorage. -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\WinPE-EnhancedStorage.cab" /logpath:"dism.log" -dism /add-package /image:"%wd%\mount" /packagepath:"%winpe_ocs%\en-us\WinPE-EnhancedStorage_en-us.cab" /logpath:"dism.log" + rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-StorageWMI.cab" /logpath:"dism.log" + dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" + + rem Add Drivers + dism /add-driver /image:"!mount!" /driver:"!drivers!" /recurse /logpath:"dism.log" + + rem Force RamDisk size to try and avoid capture-image errors + dism /image:"!mount!" /set-scratchspace:512 + + rem Add WK Stuff + del "!wd!\WK\Scripts\WK.log" + mkdir "!mount!\WK" + robocopy /s /r:3 /w:0 "!wd!\WK\!arch!" "!mount!\WK" + mkdir "!mount!\WK\Scripts" + robocopy /s /r:3 /w:0 "!wd!\Scripts" "!mount!\WK\Scripts" + + rem Add System32 Stuff + copy /y "!wd!\System32\menu.cmd" "!mount!\Windows\System32\menu.cmd" + copy /y "!wd!\System32\Winpeshl.ini" "!mount!\Windows\System32\Winpeshl.ini" + + rem Background + takeown /f "!mount!\Windows\System32\winpe.jpg" /a + icacls "!mount!\Windows\System32\winpe.jpg" /grant administrators:F + copy /y "!wd!\System32\winpe.jpg" "!mount!\Windows\System32\winpe.jpg" + copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\ConEmu\winpe.jpg" + + rem Registry Edits + reg load HKLM\WinPE-SW "!mount!\Windows\System32\config\SOFTWARE" + reg load HKLM\WinPE-SYS "!mount!\Windows\System32\config\SYSTEM" + + rem Add 7-Zip to path + reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip" /f -:Robocopy -del "%wd%\WK\Scripts\WK.log" -mkdir "%wd%\mount\WK" -robocopy /e "%wd%\WK" "%wd%\mount\WK" -del "%wd%\mount\Windows\explorer.exe" -mklink /h "%wd%\mount\Windows\explorer.exe" "%wd%\mount\WK\Explorer++\Explorer++64.exe" + rem Replace Notepad + reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod.exe /z" /f -:System32Stuff -copy /y "%wd%\System32\menu.cmd" "%wd%\mount\Windows\System32\menu.cmd" -copy /y "%wd%\System32\Winpeshl.ini" "%wd%\mount\Windows\System32\Winpeshl.ini" - -:RegistryEdits -reg load HKLM\WinPE-SW mount\Windows\System32\config\SOFTWARE -reg load HKLM\WinPE-SYS mount\Windows\System32\config\SYSTEM - -rem Add 7-Zip to path -reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip" /f - -rem Replace Notepad -reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod64.exe /z" /f - -rem Unload registry hives -reg unload HKLM\WinPE-SW -reg unload HKLM\WinPE-SYS - -:Background -takeown /f "%wd%\mount\Windows\System32\winpe.jpg" /a -icacls "%wd%\mount\Windows\System32\winpe.jpg" /grant administrators:F -copy /y "%wd%\System32\winpe.jpg" "%wd%\mount\Windows\System32\winpe.jpg" -copy /y "%wd%\System32\winpe.jpg" "%wd%\mount\WK\ConEmu\winpe.jpg" - -:ManualStuff -REM echo Now is the time to add stuff (optional). -REM echo. -REM echo Press any key to commit changes... -REM pause>nul - -:Set-ScratchSpace -rem Force RamDisk size to try and avoid capture-image errors -dism /image:"%wd%\mount" /set-scratchspace:512 - -:Unmount -dism /unmount-image /mountdir:"%wd%\mount" /commit - -:CreateISO -del "!pe_iso!" -makewinpemedia.cmd /iso "%wd%\pe_files" "!pe_iso!" + rem Unload registry hives + reg unload HKLM\WinPE-SW + reg unload HKLM\WinPE-SYS + + rem Unmount Image + dism /unmount-image /mountdir:"!mount!" /commit + + rem Create ISO + del "WinPE-!iso_date!-!arch!.iso" + call makewinpemedia.cmd /iso "!pe_files!" "WinPE-!iso_date!-!arch!.iso" +) goto Done :Abort +color 4e echo. echo Aborted. goto Exit From cf4092f57b5608c746d867c2e36e3964266518dc Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:03:11 -0800 Subject: [PATCH 07/85] 2016-06: Retroactive Updates * Don't load PowerShell profiles (-NoProfile) * This should reduce the startup time for most actions in WinPE * MCT Windows 10 isos no longer have "Technical Preview" in the names * make.cmd script simplified and now removes more language folders --- Scripts/WK.ps1 | 2 +- Scripts/imaging.ps1 | 4 ++-- Scripts/init.ps1 | 2 +- System32/Winpeshl.ini | 2 +- System32/menu.cmd | 4 ++-- make.cmd | 43 ++++++------------------------------------- 6 files changed, 13 insertions(+), 44 deletions(-) diff --git a/Scripts/WK.ps1 b/Scripts/WK.ps1 index d18fc94f..ee0672cd 100644 --- a/Scripts/WK.ps1 +++ b/Scripts/WK.ps1 @@ -87,7 +87,7 @@ function menu-main { Start-Process "$windir\System32\cmd.exe" -argumentlist @("-new_console:n") -WorkingDirectory "$WKPath" return } elseif ($selection -imatch '^P$') { - Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-new_console:n") -WorkingDirectory "$WKPath" + Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-NoProfile", "-new_console:n") -WorkingDirectory "$WKPath" return } elseif ($selection -imatch '^[QRS]$') { wk-exit $selection diff --git a/Scripts/imaging.ps1 b/Scripts/imaging.ps1 index a8a4e540..c8a52e91 100644 --- a/Scripts/imaging.ps1 +++ b/Scripts/imaging.ps1 @@ -388,8 +388,8 @@ function menu-setup { @{Name="Windows 8.1 Pro"; ImageFile="Win8"; ImageName="Windows 8.1 Pro"} # The ISOs from the MediaCreationTool are apparently Technical Previews - @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Technical Preview"; CRLF=$true} - @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro Technical Preview"} + @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"; CRLF=$true} + @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} ) # Build menu and get selection diff --git a/Scripts/init.ps1 b/Scripts/init.ps1 index b198fdd8..662ad5cf 100644 --- a/Scripts/init.ps1 +++ b/Scripts/init.ps1 @@ -3,7 +3,7 @@ # Some common settings and functions $host.UI.RawUI.BackgroundColor = "black" -$host.UI.RawUI.ForegroundColor = "cyan" +$host.UI.RawUI.ForegroundColor = "white" #$appdata = (gci env:appdata).value #$localappdata = (gci env:localappdata).value #$username = (gci env:username).value diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index ed840fb7..28aee836 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,4 +2,4 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n +"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -NoProfile -new_console:n diff --git a/System32/menu.cmd b/System32/menu.cmd index c433ff39..2769cd76 100644 --- a/System32/menu.cmd +++ b/System32/menu.cmd @@ -12,7 +12,7 @@ for %%f in (%*) do ( ) :LaunchMenu -"%SystemDrive%\WK\ConEmu\ConEmu.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -new_console:n +"%SystemDrive%\WK\ConEmu\ConEmu.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -NoProfile -new_console:n goto Done :Abort @@ -28,4 +28,4 @@ goto Exit :Exit echo. popd -endlocal \ No newline at end of file +endlocal diff --git a/make.cmd b/make.cmd index 56207694..efc6a59d 100644 --- a/make.cmd +++ b/make.cmd @@ -71,42 +71,11 @@ for %%a in (amd64 x86) do ( rem Copy main files call copype.cmd !arch! "!pe_files!" - rmdir /s /q "!pe_files!\media\bg-bg" - rmdir /s /q "!pe_files!\media\cs-cz" - rmdir /s /q "!pe_files!\media\da-dk" - rmdir /s /q "!pe_files!\media\de-de" - rmdir /s /q "!pe_files!\media\el-gr" - rmdir /s /q "!pe_files!\media\en-gb" - rmdir /s /q "!pe_files!\media\es-es" - rmdir /s /q "!pe_files!\media\es-mx" - rmdir /s /q "!pe_files!\media\et-ee" - rmdir /s /q "!pe_files!\media\fi-fi" - rmdir /s /q "!pe_files!\media\fr-ca" - rmdir /s /q "!pe_files!\media\fr-fr" - rmdir /s /q "!pe_files!\media\hr-hr" - rmdir /s /q "!pe_files!\media\hu-hu" - rmdir /s /q "!pe_files!\media\it-it" - rmdir /s /q "!pe_files!\media\ja-jp" - rmdir /s /q "!pe_files!\media\ko-kr" - rmdir /s /q "!pe_files!\media\lt-lt" - rmdir /s /q "!pe_files!\media\lv-lv" - rmdir /s /q "!pe_files!\media\nb-no" - rmdir /s /q "!pe_files!\media\nl-nl" - rmdir /s /q "!pe_files!\media\pl-pl" - rmdir /s /q "!pe_files!\media\pt-br" - rmdir /s /q "!pe_files!\media\pt-pt" - rmdir /s /q "!pe_files!\media\ro-ro" - rmdir /s /q "!pe_files!\media\ru-ru" - rmdir /s /q "!pe_files!\media\sk-sk" - rmdir /s /q "!pe_files!\media\sl-si" - rmdir /s /q "!pe_files!\media\sr-latn-cs" - rmdir /s /q "!pe_files!\media\sr-latn-rs" - rmdir /s /q "!pe_files!\media\sv-se" - rmdir /s /q "!pe_files!\media\tr-tr" - rmdir /s /q "!pe_files!\media\uk-ua" - rmdir /s /q "!pe_files!\media\zh-cn" - rmdir /s /q "!pe_files!\media\zh-hk" - rmdir /s /q "!pe_files!\media\zh-tw" + for %%t in (bg-bg cs-cz da-dk de-de el-gr en-gb es-es es-mx et-ee fi-fi fr-ca fr-fr hr-hr hu-hu it-it ja-jp ko-kr lt-lt lv-lv nb-no nl-nl pl-pl pt-br pt-pt ro-ro ru-ru sk-sk sl-si sr-latn-cs sr-latn-rs sv-se tr-tr uk-ua zh-cn zh-hk zh-tw) do ( + rmdir /s /q "!pe_files!\media\%%t" + rmdir /s /q "!pe_files!\media\Boot\%%t" + rmdir /s /q "!pe_files!\media\EFI\Microsoft\Boot\%%t" + ) rem Mount Image mkdir "!mount!" @@ -136,7 +105,7 @@ for %%a in (amd64 x86) do ( dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-StorageWMI.cab" /logpath:"dism.log" From 29c18709573ad97e892ea7b9285adebc43fbcf21 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:04:39 -0800 Subject: [PATCH 08/85] 2016-08: Retroactive Updates ## Major Update ## * Converted all scripts to Python * Replaced ConEmu with ConEmu-maximus5 from cmder * Adjusted the menu so that entries are still aligned for lists of 10+ * This applies to both numbered and lettered entries * Can now select which MiniDump path to load for BlueScreenView * General disks / volumes * Better detection of non-partitioned drives * Detect and store the partition MBR Type / GPT GUIDs * Added a Partition UID list for better identification of partitions * Hide the extra partition details if currently accessible --- Scripts/WK.ps1 | 116 ---- Scripts/functions.py | 576 +++++++++++++++++++ Scripts/imaging.ps1 | 467 --------------- Scripts/init.ps1 | 158 ------ Scripts/menu.py | 345 ++++++++++++ Scripts/partition_uids.py | 325 +++++++++++ Scripts/servers.ps1 | 85 --- System32/Winpeshl.ini | 2 +- System32/menu.cmd | 31 - WK/amd64/ConEmu/ConEmu.xml | 643 --------------------- WK/amd64/HWMonitor/hwmonitorw.ini | 1 - WK/amd64/conemu-maximus5/ConEmu.xml | 844 ++++++++++++++++++++++++++++ WK/x86/ConEmu/ConEmu.xml | 643 --------------------- WK/x86/conemu-maximus5/ConEmu.xml | 844 ++++++++++++++++++++++++++++ make.cmd | 43 +- 15 files changed, 2956 insertions(+), 2167 deletions(-) delete mode 100644 Scripts/WK.ps1 create mode 100644 Scripts/functions.py delete mode 100644 Scripts/imaging.ps1 delete mode 100644 Scripts/init.ps1 create mode 100644 Scripts/menu.py create mode 100644 Scripts/partition_uids.py delete mode 100644 Scripts/servers.ps1 delete mode 100644 System32/menu.cmd delete mode 100644 WK/amd64/ConEmu/ConEmu.xml create mode 100644 WK/amd64/conemu-maximus5/ConEmu.xml delete mode 100644 WK/x86/ConEmu/ConEmu.xml create mode 100644 WK/x86/conemu-maximus5/ConEmu.xml diff --git a/Scripts/WK.ps1 b/Scripts/WK.ps1 deleted file mode 100644 index ee0672cd..00000000 --- a/Scripts/WK.ps1 +++ /dev/null @@ -1,116 +0,0 @@ -# WK-Checklist - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 -. .\servers.ps1 -. .\imaging.ps1 -clear -$host.UI.RawUI.WindowTitle = "WK PE Tool" -$logpath = "$WKPath\Info\$date" -md "$logpath" 2>&1 | Out-Null -$log = "$logpath\winpe.log" - -# Functions -function wk-exit { - param([string]$action) - switch ($action) { - 'Q' {PowerShell -ExecutionPolicy Bypass; break} - 'R' {wpeutil reboot; break} - 'S' {wpeutil shutdown; break} - default {throw} - } - exit 0 -} -function menu-tools { - # Avail tools - $tools = @( - @{Name="Blue Screen View"; Folder="BlueScreenView"; File="BlueScreenView.exe"}, - @{Name="CPU-Z"; Folder="CPU-Z"; File="cpuz.exe"}, - @{Name="Explorer++"; Folder="Explorer++"; File="Explorer++.exe"}, - @{Name="Fast Copy"; Folder="FastCopy"; File="FastCopy.exe"; Args=@('/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"')}, - @{Name="HW Monitor"; Folder="HWMonitor"; File="HWMonitor.exe"}, - @{Name="NT Password Editor"; Folder="NT Password Editor"; File="ntpwedit.exe"}, - @{Name="Notepad2"; Folder="Notepad2"; File="Notepad2-Mod.exe"}, - @{Name="PhotoRec"; Folder="TestDisk"; File="photorec_win.exe"}, - @{Name="Prime95"; Folder="Prime95"; File="prime95.exe"}, - @{Name="ProduKey"; Folder="ProduKey"; File="ProduKey.exe"}, - @{Name="TestDisk"; Folder="TestDisk"; File="testdisk_win.exe"} - ) - - # Build menu - $selection = $null - $actions = @(@{Name="Main Menu"; Letter="M"}) - - # Run Loop - $_done = $false - do { - $selection = (menu-select "Tools Menu" $tools $actions) - - if ($selection -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - $selection -= 1 - $path = "{0}\{1}" -f $WKPath, $tools[$selection].Folder - if ($tools[$selection].ContainsKey("Args")) { - Start-Process $tools[$selection].File -ArgumentList $tools[$selection].Args -WorkingDirectory $path - } else { - Start-Process $tools[$selection].File -WorkingDirectory $path - } - } - } until ($_done) -} -function menu-main { - # Build menu - $selection = $null - $menus = @( - @{Name="Drive Imaging"; Menu="menu-imaging"} - @{Name="Windows Setup"; Menu="menu-setup"} - @{Name="Misc Tools"; Menu="menu-tools"} - ) - $actions = @( - @{Name="Command Prompt"; Letter="C"} - @{Name="PowerShell"; Letter="P"} - @{Name="Reboot"; Letter="R"} - @{Name="Shutdown"; Letter="S"} - ) - - # Show Menu - $selection = (menu-select "Main Menu" $menus $actions -SecretExit $true) - - if ($selection -imatch '^C$') { - Start-Process "$windir\System32\cmd.exe" -argumentlist @("-new_console:n") -WorkingDirectory "$WKPath" - return - } elseif ($selection -imatch '^P$') { - Start-Process "$windir\System32\WindowsPowerShell\v1.0\powershell.exe" -argumentlist @("-ExecutionPolicy", "Bypass", "-NoProfile", "-new_console:n") -WorkingDirectory "$WKPath" - return - } elseif ($selection -imatch '^[QRS]$') { - wk-exit $selection - return - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - # Launch sub-menu - $selection -= 1 - & $menus[$selection].Menu - } -} - -# Mount all partitions -foreach ($_d in @(Get-Disk)) { - foreach ($_p in @(Get-Partition -DiskNumber $_d.DiskNumber)) { - # Assign letter - Add-PartitionAccessPath -DiskNumber $_d.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null - } -} - -# Main Loop -do { - menu-main -} while ($true) diff --git a/Scripts/functions.py b/Scripts/functions.py new file mode 100644 index 00000000..f7aea8f2 --- /dev/null +++ b/Scripts/functions.py @@ -0,0 +1,576 @@ +# WK WinPE Functions + +import os +import re +import shutil +import subprocess +import time +import partition_uids + +# Init +BACKUP_SERVERS = [ + { 'IP': '10.0.0.10', + 'Mounted': False, + 'Name': 'ServerOne', + 'Share': 'Backups', + 'User': 'backup', + 'Pass': 'Abracadabra', + }, + { 'IP': '10.0.0.11', + 'Name': 'ServerTwo', + 'Mounted': False, + 'Share': 'Backups', + 'User': 'backup', + 'Pass': 'Abracadabra', + }, +] +WINDOWS_SERVER = { + 'IP': '10.0.0.10', + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Windows', + 'User': 'backup', # Using these credentials in case both the windows source and backup shares are mounted. + 'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time. +} +diskpart_script = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) + +## Colors +COLORS = { + 'CLEAR': '\033[0m', + 'RED': '\033[31m', + 'GREEN': '\033[32m', + 'YELLOW': '\033[33m', + 'BLUE': '\033[34m'} + +def ask(prompt='Kotaero'): + answer = None + prompt = prompt + ' [Y/N]: ' + while answer is None: + tmp = input(prompt) + if re.search(r'^y(es|)$', tmp): + answer = True + elif re.search(r'^n(o|ope|)$', tmp): + answer = False + return answer + +def convert_to_bytes(size): + size = str(size) + tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) + if tmp: + size = int(tmp.group(1)) + units = tmp.group(2) + if units == 'TB': + size *= 1099511627776 + elif units == 'GB': + size *= 1073741824 + elif units == 'MB': + size *= 1048576 + elif units == 'KB': + size *= 1024 + else: + return -1 + + return size + +def human_readable_size(size, decimals=0): + # Prep string formatting + width = 3+decimals + if decimals > 0: + width += 1 + human_format = '>{width}.{decimals}f'.format(width=width, decimals=decimals) + tmp = '' + + # Convert size to int + try: + size = int(size) + except ValueError: + size = convert_to_bytes(size) + + # Verify we have a valid size + if size <= 0: + return '{size:>{width}} b'.format(size='???', width=width) + + # Format string + if size >= 1099511627776: + size /= 1099511627776 + tmp = '{size:{human_format}} Tb'.format(size=size, human_format=human_format) + elif size >= 1073741824: + size /= 1073741824 + tmp = '{size:{human_format}} Gb'.format(size=size, human_format=human_format) + elif size >= 1048576: + size /= 1048576 + tmp = '{size:{human_format}} Mb'.format(size=size, human_format=human_format) + elif size >= 1024: + size /= 1024 + tmp = '{size:{human_format}} Kb'.format(size=size, human_format=human_format) + else: + tmp = '{size:{human_format}} b'.format(size=size, human_format=human_format) + + # Return + return tmp + +def pause(prompt='Press Enter to continue... '): + input(prompt) + +def print_error(message='Generic error', **kwargs): + print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_info(message='Generic info', **kwargs): + print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_warning(message='Generic warning', **kwargs): + print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_success(message='Generic success', **kwargs): + print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def run_program(cmd=None, args=[], check=True): + if cmd is None: + raise Exception('No program passed.') + + if len(args) > 0: + args = [cmd] + args + process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + else: + process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + + return process_return + +def assign_volume_letters(): + with open(diskpart_script, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + with open(diskpart_script, 'w') as script: + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): + if tmp[1] == '': + script.write('select volume {number}\n'.format(number=tmp[0])) + script.write('assign\n') + try: + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except: + pass + +def remove_volume_letters(): + with open(diskpart_script, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + with open(diskpart_script, 'w') as script: + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): + if tmp[1] != '': + script.write('select volume {number}\n'.format(number=tmp[0])) + script.write('remove\n') + try: + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except: + pass + +def select_minidump_path(): + dumps = [] + + # Assign volume letters first + assign_volume_letters() + + # Search for minidumps + tmp = run_program('mountvol') + tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] + # Remove RAMDisk letter + if 'X' in tmp: + tmp.remove('X') + for drive in tmp: + if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): + dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) + + # Check results before showing menu + if len(dumps) == 0: + print_error(' No BSoD / MiniDump paths found') + time.sleep(2) + return None + + # Menu + selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) + return dumps[int(selection) - 1]['Name'] + +def find_windows_image(filename=None): + """Search for a Windows source image file on local drives and network drives (in that order)""" + image_file = None + + # Bail early + if filename is None: + raise Exception('Filename not specified.') + + # Search local source + process_return = run_program('mountvol') + for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): + for ext in ['esd', 'wim', 'swm']: + if os.path.isfile('{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename)): + image_file = '{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename) + break + + # Check for network source (if necessary) + if image_file is None: + if not WINDOWS_SERVER['Mounted']: + mount_windows_share() + for ext in ['esd', 'wim']: + if os.path.isfile('\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER)): + image_file = '\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER) + break + + return image_file + +def format_gpt(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + print_info('Drive will use a GPT (UEFI) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + script.write('convert gpt\n') + + # Windows RE tools partitions (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('create partition primary size=300\n') + script.write('format quick fs=ntfs label="Windows RE tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') + + # System partition + script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives + script.write('format quick fs=fat32 label="System"\n') + script.write('assign letter="S"\n') + + # Microsoft Reserved (MSR) partition + script.write('create partition msr size=128\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Windows"\n') + script.write('assign letter="W"\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def format_mbr(disk=None): + """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + + # Format drive + print_info('Drive will use a MBR (legacy) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + + # System partition + script.write('create partition primary size=100\n') + script.write('format fs=ntfs quick label="System Reserved"\n') + script.write('active\n') + script.write('assign letter=s\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format fs=ntfs quick label="Windows"\n') + script.write('assign letter=w\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def get_attached_disk_info(): + """Get details about the attached disks""" + disks = [] + print_info('Getting drive info...') + + # Assign all the letters + assign_volume_letters() + + # Get disk numbers + with open(diskpart_script, 'w') as script: + script.write('list disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return.stdout.decode()): + disks.append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) + + # Get disk details + for disk in disks: + # Get partition style + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('uniqueid disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return.stdout.decode()): + disk['Table'] = 'GPT' + elif re.findall(r'Disk ID: 00000000', process_return.stdout.decode()): + disk['Table'] = 'RAW' + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return.stdout.decode()): + disk['Table'] = 'MBR' + else: + disk['Table'] = 'Unknown' + + # Get disk name/model and physical details + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('detail disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + tmp = process_return.stdout.decode().strip().splitlines() + # Remove empty lines and those without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.strip() for s in tmp if s.strip() != ''] + # Set disk name + disk['Name'] = tmp[4] + tmp = [s.split(':') for s in tmp if ':' in s] + # Add new key/value pairs to the disks variable + disk.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get partition info for disk + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('list partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + disk['Partitions'] = [] + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return.stdout.decode().strip()): + disk['Partitions'].append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) + for par in disk['Partitions']: + # Get partition details + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('select partition {Number}\n'.format(**par)) + script.write('detail partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + for tmp in re.findall(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return.stdout.decode().strip()): + if tmp == 'RAW': + par['FileSystem'] = 'RAW' + else: + par['Letter'] = tmp + try: + process_return2 = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**par)) + for line in process_return2.stdout.decode().splitlines(): + line = line.strip() + # Get partition name + match = re.search(r'Volume Name\s+:\s+(.*)$', line) + if match: + par['Name'] = match.group(1).strip() + # Get filesystem type + match = re.search(r'File System Name\s+:\s+(.*)$', line) + if match: + par['FileSystem'] = match.group(1).strip() + usage = shutil.disk_usage('{Letter}:\\'.format(Letter=tmp)) + par['Used Space'] = human_readable_size(usage.used) + except subprocess.CalledProcessError: + par['FileSystem'] = 'Unknown' + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + for tmp in re.findall(r'Type\s+:\s+(\S+)', process_return.stdout.decode().strip()): + par['Type'] = tmp + uid = partition_uids.lookup_guid(tmp) + if uid is not None: + par.update({ + 'Description': uid.get('Description', ''), + 'OS': uid.get('OS', '')}) + # Ensure the Name has been set + if 'Name' not in par: + par['Name'] = '' + if 'FileSystem' not in par: + par['FileSystem'] = 'Unknown' + + # Done + return disks + +def select_disk(prompt='Which disk?'): + """Select a disk from the attached disks""" + disks = get_attached_disk_info() + + # Build menu + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + if len(disk['Partitions']) > 0: + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Show unsupported partition(s) in RED + par_skip = False + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): + par_skip = True + if par_skip: + display_name += COLORS['YELLOW'] + + # Main text + display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) + if par['Name'] != '': + display_name += '\t"{Name}"'.format(**par) + + # Clear color (if set above) + if par_skip: + display_name += COLORS['CLEAR'] + else: + display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select(prompt, disk_options, actions) + + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + return None + +def select_windows_version(): + versions = [ + {'Name': 'Windows 7 Home Basic', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 HOMEBASIC', 'Family': '7'}, + {'Name': 'Windows 7 Home Premium', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 HOMEPREMIUM', 'Family': '7'}, + {'Name': 'Windows 7 Professional', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 PROFESSIONAL', 'Family': '7'}, + {'Name': 'Windows 7 Ultimate', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 ULTIMATE', 'Family': '7'}, + + {'Name': 'Windows 8.1', 'ImageFile': 'Win8', 'ImageName': 'Windows 8.1', 'Family': '8', 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', 'ImageFile': 'Win8', 'ImageName': 'Windows 8.1 Pro', 'Family': '8'}, + + {'Name': 'Windows 10 Home', 'ImageFile': 'Win10', 'ImageName': 'Windows 10 Home', 'Family': '10', 'CRLF': True}, + {'Name': 'Windows 10 Pro', 'ImageFile': 'Win10', 'ImageName': 'Windows 10 Pro', 'Family': '10'}, + ] + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select('Which version of Windows are we installing?', versions, actions) + + if selection.isnumeric(): + return versions[int(selection)-1] + elif selection == 'M': + return None + +def select_destination(): + # Build menu + dests = [] + for server in BACKUP_SERVERS: + if server['Mounted']: + dests.append(server) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Size check + for dest in dests: + if 'IP' in dest: + dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) + else: + dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) + dest['Free Space'] = human_readable_size(dest['Usage'].free) + dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) + + # Show menu or bail + if len(dests) > 0: + selection = menu_select('Where are we backing up to?', dests, actions) + if selection == 'M': + return None + else: + return dests[int(selection)-1] + else: + print_warning('No backup destinations found.') + return None + +def mount_backup_shares(): + """Mount the backup shares for use as destinations for backup image creation""" + + # Attempt to mount share(s) + for server in BACKUP_SERVERS: + # Blindly skip if we mounted earlier + if server['Mounted']: + continue + else: + try: + # Test connection + run_program('ping -w 800 -n 2 {IP}'.format(**server)) + + # Mount + run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**server)) + print_info('Mounted {Name}'.format(**server)) + server['Mounted'] = True + except subprocess.CalledProcessError: + print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**server)) + time.sleep(1) + except: + print_warning('Failed to mount \\\\{Name}\\{Share} ({IP})'.format(**server)) + time.sleep(1) + +def mount_windows_share(): + """Mount the Windows images share for use in Windows setup""" + + # Blindly skip if we mounted earlier + if WINDOWS_SERVER['Mounted']: + return None + else: + try: + # Test connection + run_program('ping -w 800 -n 2 {IP}'.format(**WINDOWS_SERVER)) + # Mount + run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**WINDOWS_SERVER)) + print_info('Mounted {Name}'.format(**WINDOWS_SERVER)) + WINDOWS_SERVER['Mounted'] = True + except subprocess.CalledProcessError: + print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**WINDOWS_SERVER)) + time.sleep(1) + except: + print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) + time.sleep(1) + +def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): + """Display options in a menu for user selection""" + + # Bail early + if (len(main_entries) + len(action_entries) == 0): + raise Exception("MenuError: No items given") + + # Build menu + menu_splash = '{title}\n\n'.format(title=title) + valid_answers = [] + if (secret_exit): + valid_answers.append('Q') + + # Add main entries + if (len(main_entries) > 0): + for i in range(len(main_entries)): + entry = main_entries[i] + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(str(i+1)) + menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) + menu_splash += '\n' + + # Add action entries + if (len(action_entries) > 0): + for entry in action_entries: + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(entry['Letter']) + menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) + menu_splash += '\n' + + answer = '' + + while (answer.upper() not in valid_answers): + os.system('cls') + print(menu_splash) + answer = input('{prompt}: '.format(prompt=prompt)) + + return answer.upper() + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/imaging.ps1 b/Scripts/imaging.ps1 deleted file mode 100644 index c8a52e91..00000000 --- a/Scripts/imaging.ps1 +++ /dev/null @@ -1,467 +0,0 @@ -# WK imaging functions - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 - -# Functions -function apply-image { - # Apply a Windows image to W:\ - Param([string]$image, [string]$name) - $path = "" - $split_image = $false - $split_image_pattern = "" - - # Check for source image - ## This checks all drive letters for the source image. - ## It starts with local sources and then tries the server(s) (usually Y: and Z:) - $volumes = @(Get-Volume | Where-Object {$_.Size -ne 0 -and $_.DriveLetter -imatch '^[C-Z]$'}) - foreach ($v in $volumes) { - $letter = $v.DriveLetter + ":" - if (Test-Path "$letter\images\$image.wim") { - $path = "$letter\images\$image.wim" - } elseif (Test-Path "$letter\images\$image.esd") { - $path = "$letter\images\$image.esd" - } elseif (Test-Path "$letter\images\$image.swm") { - $path = "$letter\images\$image.swm" - $split_image = $true - $split_image_pattern = "$letter\images\$image*.swm" - } - } - - # Check for FQDN remote source (if necessary) - if ($path -imatch '^$') { - # Temporarily set path to network source - $path = "\\$source_server\Windows\$image" - wk-warn "Searching for network source" - if (Test-Path "$path.wim") { - $path = "$path.wim" - } elseif (Test-Path "$path.esd") { - $path = "$path.esd" - } elseif (Test-Path "$path.swm") { - $path = "$path.swm" - $split_image = $true - $split_image_pattern = "$path*.swm" - } else { - # Revert to empty path if nothing found. - $path = "" - } - } - - # Expand Image - if ($path -imatch 'Win\d+\.(esd|wim)$') { - wk-write " Applying image..." - Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' | out-null - } elseif ($path -imatch 'Win\d+\.swm$') { - wk-write " Applying split-image..." - Expand-WindowsImage -ImagePath "$path" -Name "$name" -ApplyPath 'W:\' -SplitImageFilePattern "$split_image_pattern" | out-null - } else { - wk-error "Image not found." - throw - } -} -function format-gpt { - Param($dest_disk) - wk-write "Drive will use a GPT (UEFI) layout." - - # Double-check we have the right drive - ## I don't trust the order will be the same for diskpart & PS Storage Cmdlets - $_sel_uid = $dest_disk.Guid - if ($dest_disk.PartitionStyle -imatch "MBR") { - # MBR disks don't have GUIDs and use the signature in hex instead - $_sel_uid = "{0:x}" -f $dest_disk.Signature - } - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "uniqueid disk" - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow -PassThru -RedirectStandardOutput "$wd\drive_uid" | Out-Null - if (!(Get-Content "$wd\drive_uid" | Where-Object {$_ -imatch $_sel_uid})) { - # GUIDs do not match - wk-error "Diskpart failed to select the same disk for formatting, aborting setup." - wk-warn "This system requires manual formatting & setup" - wk-write "" - throw "Failed to format disk" - } else { - wk-write ("Selecting Disk {0} ({1})" -f $dest_disk.DiskNumber, $_sel_uid) - } - - # Generate Diskpart script and execute - ## NOTE 1: PS Storage Cmdlets can't be used; See Keith Garner's response here: - ## https://social.technet.microsoft.com/Forums/en-US/9d78da31-557f-4408-89e0-a1603f7ebe0d - ## - ## NOTE 2: This overwrites existing diskpart.script file without confirmation. - $diskpart_script = "select disk {0}`r`n" -f $dest_disk.DiskNumber - $diskpart_script += "clean`r`n" - $diskpart_script += "convert gpt`r`n" - - # 1. Windows RE tools partition (Windows 8+) - if ($dest_windows_version.Name -imatch '^Windows (8|10)') { - $diskpart_script += "create partition primary size=300`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows RE tools'`r`n" - $diskpart_script += "assign letter='T'`r`n" - $diskpart_script += "set id='de94bba4-06d1-4d40-a16a-bfd50179d6ac'`r`n" - $diskpart_script += "gpt attributes=0x8000000000000001`r`n" - } - - # 2. System partition - $diskpart_script += "create partition efi size=260`r`n" - ## NOTE: Allows for Advanced Format 4Kn drives - $diskpart_script += "format quick fs=fat32 label='System'`r`n" - $diskpart_script += "assign letter='S'`r`n" - - # 3. Microsoft Reserved (MSR) partition - $diskpart_script += "create partition msr size=128`r`n" - - # 4. Windows partition - $diskpart_script += "create partition primary`r`n" - $diskpart_script += "format quick fs=ntfs label='Windows'`r`n" - $diskpart_script += "assign letter='W'`r`n" - - # Run script - Out-File -encoding 'UTF8' -filepath "$wd\diskpart.script" -inputobject $diskpart_script - Start-Process "diskpart" -argumentlist @("/s", "$wd\diskpart.script") -wait -nonewwindow | out-null -} -function format-mbr { - Param($dest_disk) - wk-write "Drive will use a MBR (legacy) layout." - - if ($dest_disk.PartitionStyle -inotmatch '^RAW$') { - # Only clean if necessary - clear-Disk $dest_disk.DiskNumber -RemoveData -RemoveOEM -Confirm:$false | out-null - } - Initialize-Disk $dest_disk.DiskNumber -PartitionStyle 'MBR' | out-null - New-Partition -DiskNumber $dest_disk.DiskNumber -Size 100Mb -DriveLetter 'S' -IsActive:$true | out-null - New-Partition -DiskNumber $dest_disk.DiskNumber -UseMaximumSize -DriveLetter 'W' -IsActive:$false | out-null - Format-Volume -DriveLetter 'S' -FileSystem 'NTFS' -NewFileSystemLabel 'System Reserved' | out-null - Format-Volume -DriveLetter 'W' -FileSystem 'NTFS' -NewFileSystemLabel 'Windows' | out-null -} -function select-disk { - param([string]$title, [bool]$skip_usb=$false) - $_skipped_parts = 0 - - # Get Disk(s) - if ($skip_usb) { - $disks = @(Get-Disk | Where-Object {$_.Size -ne 0 -and $_.BusType -inotmatch 'USB'} | Sort-Object -Property "Number") - } else { - $disks = @(Get-Disk | Where-Object {$_.Size -ne 0} | Sort-Object -Property "Number") - } - - # Check if any drives were detected - if ($disks.count -eq 0) { - wk-error "No suitable drives were detected." - return $false - } - - # Get selection - $selection = $null - $main_set = @() - if ($disks.count -eq 1) { - # Only one disk is available - $selection = $disks[0] - } else { - # Multiple options. Build and use menu - foreach ($_ in $disks) { - $_entry = "{0}`t[{1}] ({2}) {3}" -f (human-size $_.Size 0), $_.PartitionStyle, $_.BusType, $_.FriendlyName - $main_set += @{Name=$_entry} - } - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select $title $main_set $actions) - } - - if ($selection -imatch '^\d+$') { - $selection -= 1 - return $disks[$selection] - } else { - return $selection - } -} -function menu-imaging { - wk-write "Drive Imaging" - wk-write "" - - # Pre-emptively mount Server(s) - ## Helps ensure a successfull backup and/or setup - mount-servers - - ## WARNING - wk-warn "WARNING: This section is experimental" - pause - ## WARNING - - # Service Order - $menu_service_order += "Please enter the service order`r`n" - do { - clear - $service_order = read-host -prompt $menu_service_order - } until ($service_order -imatch '^\d[\w\-]+$') - - # Select Disk - $disk = (select-disk "For which drive are we creating backup image(s)?") - - if (!($disk)) { - # No drives detected or user aborted - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($disk -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($disk.DiskNumber -imatch '^\d+$') { - # Valid disk selected - clear - wk-write ("Disk:`t{0}`t[{1}] ({2}) {3}" -f (human-size $disk.Size 0), $disk.PartitionStyle, $disk.BusType, $disk.FriendlyName) - wk-write "Partition(s):" - - # Print partition info - $partitions = Get-Partition -DiskNumber $disk.DiskNumber - $_skipped_parts = 0 - foreach ($_p in $partitions) { - # Assign letter - Add-PartitionAccessPath -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber -AssignDriveLetter 2>&1 | Out-Null - - # Update partition info - $_p = Get-Partition -DiskNumber $disk.DiskNumber -PartitionNumber $_p.PartitionNumber - $_v = Get-Volume -Partition $_p - - # Set size label - $_size = (human-size $_p.size 0) - $_used = "" - if ($_v) { - $_used = "({0} used)" -f (human-size ($_v.Size - $_v.SizeRemaining) 0) - } - - # Print partition info - if ($_p.AccessPaths) { - # Has drive letter - $_path = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - $_label = " {0}" -f $_p.Type - if ($_v -and $_v.FileSystemLabel -ne "") { - $_label = '"{0}"' -f $_v.FileSystemLabel - } - $_msg = " {0:N0}:`t{1} ({2,6}) {3} {4}" -f $_p.PartitionNumber, $_path, $_size, $_label, $_used - wk-write "$_msg" - } else { - # No drive letter - $_msg = " *{0:N0}:`t ({1}) {2}" -f $_p.PartitionNumber, $_size, $_p.Type - wk-error "$_msg" - $_skipped_parts += 1 - } - } - if ($_skipped_parts -gt 0) { - wk-warn " *`tUnable to backup these partition(s)" - } - wk-write "" - if (!(ask " Backup these partition(s)?")) { - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - wk-write "" - - # Select Server - $server = (select-server) - if (!($server)) { - # No servers detected - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($server -imatch '^M$') { - # User selected to return to the menu - return - } - wk-write "" - wk-write ("Saving partition backups to: {0}" -f $server.Description) - wk-write "" - - # Backup partitions - $partitions = Get-Partition -DiskNumber $disk.DiskNumber - foreach ($_p in $partitions) { - $_v = Get-Volume -Partition $_p - - $_name = "{0}" -f $_p.PartitionNumber - if ($_v -and $_v.FileSystemLabel -ne "") { - $_name += "_{0}" -f $_v.FileSystemLabel - } else { - $_name += "_{0}" -f $_p.Type - } - # Sanitize the name - $_name = $_name -replace '\s', '_' - - $_imagepath = "{0}{1}" -f $server.Root, $service_order - $_imagefile = "{0}{1}\{2}.wim" -f $server.Root, $service_order, $_name - - if ($_p.AccessPaths -ne $null) { - # Avoid unwanted clobbering - if (Test-Path "$_imagefile") { - if (!(ask ("Overwrite backup image: {0}" -f $_imagefile))) { - wk-warn "Drive Imaging aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - $_capturedir = $_p.AccessPaths | Where-Object {$_ -imatch '^\w:\\$'} - - # Take image - wk-write (" Imaging partition {0} --> `"{1}`"" -f $_p.PartitionNumber, $_imagefile) - if (!(Test-Path "$_imagepath")) { - mkdir "$_imagepath" | out-null - } - $_dism_args = @( - "/Capture-Image", - "/ImageFile:$_imagefile", - "/CaptureDir:$_capturedir", - "/Name:$_name", - "/Compress:fast", - "/Quiet") - Start-Process "$windir\System32\Dism.exe" -ArgumentList $_dism_args -NoNewWindow -Wait | out-null - - ## The following command fails to capture OS partitions consitantly. Until this is fixed I will use DISM directly (as above). - #New-WindowsImage -ImagePath "$_imagefile" -CapturePath "$_capturedir" -Name "$_name" -CompressionType "fast" | out-null - - # Verify image - ## Code borrowed from: https://stackoverflow/a/10262275 - $pinfo = New-Object System.Diagnostics.ProcessStartInfo - $pinfo.FileName = "$WKPath\7-Zip\7z.exe" - $pinfo.RedirectStandardError = $true - $pinfo.RedirectStandardOutput = $true - $pinfo.UseShellExecute = $false - $pinfo.Arguments = 't "{0}"' -f $_imagefile - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $pinfo - $p.Start() | Out-Null - write-host " Verifying . . . " -NoNewline - $p.WaitForExit() - if ($p.ExitCode -eq 0) { - write-host "Complete." -foreground "green" - } else { - write-host "Failed." -foreground "red" - } - } - } - pause "Press Enter to return to main menu... " -} -function menu-setup { - # Pre-emptively mount Server(s) - ## Helps ensure a successfull backup and/or setup - mount-servers - - # Select Disk - $dest_disk = (select-disk "To which drive are we installing Windows?" -skip_usb=$true) - - if (!($dest_disk)) { - # No drives detected or user aborted - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } elseif ($dest_disk -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($dest_disk.DiskNumber -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - wk-warn "All data will be deleted from the following drive:" - wk-warn ("`t{0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (!(ask "Proceed and install Windows?")) { - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - } - - # Set available Windows versions - $windows_versions = @( - @{Name="Windows 7 Home Basic"; ImageFile="Win7"; ImageName="Windows 7 HOMEBASIC"} - @{Name="Windows 7 Home Premium"; ImageFile="Win7"; ImageName="Windows 7 HOMEPREMIUM"} - @{Name="Windows 7 Professional"; ImageFile="Win7"; ImageName="Windows 7 PROFESSIONAL"} - @{Name="Windows 7 Ultimate"; ImageFile="Win7"; ImageName="Windows 7 ULTIMATE"} - - @{Name="Windows 8.1"; ImageFile="Win8"; ImageName="Windows 8.1"; CRLF=$true} - @{Name="Windows 8.1 Pro"; ImageFile="Win8"; ImageName="Windows 8.1 Pro"} - - # The ISOs from the MediaCreationTool are apparently Technical Previews - @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"; CRLF=$true} - @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} - ) - - # Build menu and get selection - $dest_windows_version = $null - $selection = $null - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select "Which version of Windows are we installing?" $windows_versions $actions) - - if ($selection -imatch '^M$') { - # User selected to return to the menu - return $false - } elseif ($selection -inotmatch '^\d+$') { - # This shouldn't happen? - throw - } else { - $selection -= 1 - $dest_windows_version = $windows_versions[$selection] - } - - # Double check before deleting data - wk-warn "SAFTEY CHECK:" - wk-write (" Installing:`t{0}" -f $dest_windows_version.Name) - wk-error (" And ERASING:`tDisk: {0}`t({1}) {2}`r`n" -f (human-size $dest_disk.Size 0), $dest_disk.PartitionStyle, $dest_disk.FriendlyName) - if (!(ask "Is this correct?")) { - wk-warn "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } - - ## WARNING - wk-warn "WARNING: This section is experimental" - ## WARNING - - ## Here be dragons - try { - # Select UEFI or BIOS partition layout - if ($UEFI) { - # System booted via UEFI so assume new layout should be GPT - if (ask "Setup drive using GPT (UEFI) layout?") { - format-gpt $dest_disk - } else { - format-mbr $dest_disk - } - } else{ - if (ask "Setup drive using MBR (legacy) layout?") { - format-mbr $dest_disk - } else { - format-gpt $dest_disk - } - } - - # Apply image - apply-image $dest_windows_version.ImageFile $dest_windows_version.ImageName - - # Create boot files (copies files for both Legacy and UEFI) - wk-write " Copying boot files..." - bcdboot W:\Windows /s S: /f ALL 2>&1 | out-null - if ($dest_windows_version.Name -imatch '^Windows (8|10)') { - W:\Windows\System32\reagentc /setreimage /path T:\Recovery\WindowsRE /target W:\Windows 2>&1 | out-null - } - - # Done - wk-write "Windows Setup complete." - wk-write "" - pause "Press Enter to return to main menu... " - } catch { - # Error(s) - wk-error "$Error" - wk-error "Windows Setup aborted." - wk-write "" - pause "Press Enter to return to main menu... " -warning=$true - return $false - } -} diff --git a/Scripts/init.ps1 b/Scripts/init.ps1 deleted file mode 100644 index 662ad5cf..00000000 --- a/Scripts/init.ps1 +++ /dev/null @@ -1,158 +0,0 @@ -# WK-Init -# -# Some common settings and functions - -$host.UI.RawUI.BackgroundColor = "black" -$host.UI.RawUI.ForegroundColor = "white" -#$appdata = (gci env:appdata).value -#$localappdata = (gci env:localappdata).value -#$username = (gci env:username).value -#$userprofile = (gci env:userprofile).value -$systemdrive = (gci env:systemdrive).value -$windir = (gci env:windir).value -#$programfiles = (gci env:programfiles).value -#$programfiles86 = $programfiles -#if (test-path env:"programfiles(x86)") { -# $programfiles86 = (gci env:"programfiles(x86)").value -#} -$WKPath = "$systemdrive\WK" -$date = get-date -uformat "%Y-%m-%d" -#$logpath = "$WKPath\Info\$date" - -# Check if booted via UEFI -$UEFI = $false -if ((Get-ItemProperty -path "HKLM:\System\CurrentControlSet\Control").PEFirmwareType -eq 2) { - $UEFI = $true -} - -function ask { - param([string]$text = "Kotaero", [string]$log = "WK.log") - $answered = $false - $text += " [Y/N]" - while (!$answered) { - $answer = read-host $text - if ($answer -imatch '^(y|yes)$') { - $answer = $true - $answered = $true - } elseif ($answer -imatch '^(n|no)$') { - $answer = $false - $answered = $true - } - } - $text += ": $answer" - out-file -filepath $log -inputobject $text -append - return $answer -} -function wk-error { - param([string]$text = "ERROR", [string]$log = "WK.log") - write-host ($text) -foreground "red" - out-file -filepath $log -inputobject $text -append -} -function wk-warn { - param([string]$text = "WARNING", [string]$log = "WK.log") - write-host ($text) -foreground "yellow" - out-file -filepath $log -inputobject $text -append -} -function wk-write { - param([string]$text = "", [string]$log = "WK.log") - write-host ($text) - out-file -filepath $log -inputobject $text -append -} -function human-size { - param($bytes, [int]$decimals = 2) - if ($bytes -gt 1Tb) { - $size = "{0:N$decimals} Tb" -f ($bytes / 1Tb) - } elseif ($bytes -gt 1Gb) { - $size = "{0:N$decimals} Gb" -f ($bytes / 1Gb) - } elseif ($bytes -gt 1Mb) { - $size = "{0:N$decimals} Mb" -f ($bytes / 1Mb) - } elseif ($bytes -gt 1Kb) { - $size = "{0:N$decimals} Kb" -f ($bytes / 1Kb) - } else { - $size = "{0:N$decimals} b" -f $bytes - } - return $size -} -function menu-select { - ## $MainEntries should be an "AoH" object (with at least the key "Name" for each item) - ## NOTE: if the CRLF=$true; then a spacer is added before that entry. - ## Example: - ## $MainEntries = @( - ## @{Name="Windows 10 Home"; ImageFile="Win10"; ImageName="Windows 10 Home"} - ## @{Name="Windows 10 Pro"; ImageFile="Win10"; ImageName="Windows 10 Pro"} - ##) - - ## $ActionEntries should be an "AoH" object (with at least the keys "Name" and "Letter" for each item) - ## NOTE: if the CRLF=$true; then a spacer is added before that entry. - ## Example: - ## $ActionEntries = @( - ## @{Name="Reboot"; Letter="R"} - ## @{Name="Shutdown"; Letter="S"} - ##) - - param( - [string]$Title = "## Untitled Menu ##", - $MainEntries = @(), - $ActionEntries = @(), - [string]$Prompt = "Please make a selection", - [bool]$SecretExit = $false - ) - - # Bail early if no items given - if ($MainEntries.length -eq 0 -and $ActionEntries.length -eq 0) { - throw "MenuError: No items given." - } - - # Build menu - $menu_splash = "{0}`r`n`r`n" -f $title - $valid_answers = @() - if ($SecretExit) { - $valid_answers += "Q" - } - - # Add main items to splash - if ($MainEntries.length -gt 0) { - for ($i=0; $i -lt $MainEntries.length; $i++) { - if ($MainEntries[$i].CRLF) { - # Add spacer - $menu_splash += "`r`n" - } - $valid_answers += ($i + 1) - $menu_splash += "{0,2:N0}: {1}`r`n" -f ($i + 1), $MainEntries[$i].Name - } - $menu_splash += "`r`n" - } - - # Add action items to splash - if ($ActionEntries.length -gt 0) { - foreach ($_item in $ActionEntries) { - if ($_item.CRLF) { - # Add spacer - $menu_splash += "`r`n" - } - $menu_splash += " {0}: {1}`r`n" -f $_item.Letter.ToUpper(), $_item.Name - $valid_answers += $_item.Letter.ToLower(), $_item.Letter.ToUpper() - } - $menu_splash += "`r`n" - } - - # Add prompt to splash - $menu_splash += "{0}`r`n" -f $prompt - - # Select Windows version - do { - clear - $answer = read-host -prompt $menu_splash - } until ($valid_answers -contains $answer) - - return $answer.ToUpper() -} -function pause { - param([string]$message = "Press Enter to continue... ", [bool]$warning = $False) - if ($warning) { - write-host ($message) -foreground "yellow" - } else { - write-host ($message) - } - $x = read-host -} diff --git a/Scripts/menu.py b/Scripts/menu.py new file mode 100644 index 00000000..e5adc729 --- /dev/null +++ b/Scripts/menu.py @@ -0,0 +1,345 @@ +# WK WinPE Menu + +import os +import re +import subprocess +import time +import traceback +import winreg + +from functions import * + +# Init +os.chdir(os.path.dirname(os.path.realpath(__file__))) +bin = os.path.abspath('..\\') +## Check bootup type +BOOT_TYPE = 'Legacy' +try: + reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + BOOT_TYPE = 'UEFI' +except: + BOOT_TYPE = 'Unknown' + +class AbortException(Exception): + pass + +def abort_to_main_menu(message='Returning to main menu...'): + print_warning(message) + pause('Press Enter to return to main menu... ') + raise AbortException + +def menu_backup_imaging(): + """Take backup images of partition(s) in the WIM format and save them to a backup share""" + + # Mount backup shares + os.system('cls') + mount_backup_shares() + + # Set ticket number + ticket = None + while ticket is None: + tmp = input('Enter ticket number: ') + if re.match(r'^([0-9]+([-_]?\w+|))$', tmp): + ticket = tmp + + # Select disk to backup + disk = select_disk('For which drive are we creating backups?') + if disk is None: + abort_to_main_menu() + + # Get list of partitions that can't be imaged + bad_parts = [p['Number'] for p in disk['Partitions'] if 'Letter' not in p or re.search(r'(RAW|Unknown)', p['FileSystem'])] + + # Bail if no partitions are found (that can be imaged) + num_parts = len(disk['Partitions']) + if num_parts == 0 or num_parts == len(bad_parts): + abort_to_main_menu(' No partitions can be imaged for the selected drive') + + # Select destination + dest = select_destination() + if dest is None: + abort_to_main_menu('Aborting Backup Creation') + + # List (and update) partition details for selected drive + os.system('cls') + print('Details for selected drive:\n') + print(' Drive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk)) + clobber_risk = 0 + width=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Detail each partition + if par['Number'] in bad_parts: + print_warning(' * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par)) + else: + # Update info for WIM capture + par['ImageName'] = str(par['Name']) + if par['ImageName'] == '': + par['ImageName'] = 'Unknown' + if 'IP' in dest: + par['ImagePath'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket, **dest) + else: + par['ImagePath'] = '{Letter}:\\{ticket}'.format(ticket=ticket, **dest) + par['ImageFile'] = '{Number}_{ImageName}.wim'.format(**par) + + # Check for existing backups + par['ImageExists'] = False + if os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): + par['ImageExists'] = True + clobber_risk += 1 + print_info(' + Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par)) + else: + print(' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par)) + print('') # Spacer + + # Add warning about partition(s) that will be skipped + if len(bad_parts) > 1: + print_warning(' * Unable to backup these partitions') + elif len(bad_parts) == 1: + print_warning(' * Unable to backup this partition') + if clobber_risk > 1: + print_info(' + These partitions already have backup images on {TrueName}:'.format(**dest)) + elif clobber_risk == 1: + print_info(' + This partition already has a backup image on {TrueName}:'.format(**dest)) + if clobber_risk + len(bad_parts) > 1: + print_warning('\nIf you continue the partitions marked above will NOT be backed up.\n') + if clobber_risk + len(bad_parts) == 1: + print_warning('\nIf you continue the partition marked above will NOT be backed up.\n') + + # (re)display the destination + print(' Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) + + # Ask to proceed + if (not ask('Proceed with backup?')): + abort_to_main_menu('Aborting Backup Creation') + + # Backup partition(s) + print('\n\nStarting task.\n') + errors = False + for par in disk['Partitions']: + print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) + if par['Number'] in bad_parts: + print_warning('Skipped.') + else: + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{ImagePath}\\{ImageFile}" "{ImageName}" "{ImageName}" --check --compress=fast'.format(bin=bin, **par) + if par['ImageExists']: + print_warning('Skipped.') + else: + try: + os.makedirs('{ImagePath}'.format(**par), exist_ok=True) + run_program(cmd) + print_success('Complete.') + except subprocess.CalledProcessError as err: + print_error('Failed.') + errors = True + par['Error'] = err.stderr.decode().splitlines() + + # Print summary + if errors: + print_warning('\nErrors were encountered during imaging and are detailed below.') + for par in [p for p in disk['Partitions'] if 'Error' in p]: + print(' Partition {Number} Error:'.format(**par)) + for line in par['Error']: + line = line.strip() + if line != '': + print_error('\t{line}'.format(line=line)) + time.sleep(300) + else: + print_success('\nNo errors were encountered during imaging.') + time.sleep(10) + pause('\nPress Enter to return to main menu... ') + +def menu_windows_setup(): + """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" + + # Select the version of Windows to apply + os.system('cls') + selected_windows_version = select_windows_version() + if selected_windows_version is None: + abort_to_main_menu('Aborting Windows setup') + + # Find Windows image + image_file = find_windows_image(selected_windows_version['ImageFile']) + if image_file is None: + print_error('Failed to find Windows source image for {winver}'.format(winver=selected_windows_version['Name'])) + abort_to_main_menu('Aborting Windows setup') + + # Select drive to use as the OS drive + dest_drive = select_disk('To which drive are we installing Windows?') + if dest_drive is None: + abort_to_main_menu('Aborting Windows setup') + + # Confirm drive format + print_warning('All data will be deleted from the following drive:') + print_warning('\t{Size}\t({Table}) {Name}'.format(**dest_drive)) + if (not ask('Is this correct?')): + abort_to_main_menu('Aborting Windows setup') + + # MBR/Legacy or GPT/UEFI? + use_gpt = True + if (BOOT_TYPE == 'UEFI'): + if (not ask("Setup drive using GPT (UEFI) layout?")): + use_gpt = False + else: + if (ask("Setup drive using MBR (legacy) layout?")): + use_gpt = False + + # Safety check + print_warning('SAFETY CHECK\n') + print_error(' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}'.format(**dest_drive)) + if len(dest_drive['Partitions']) > 0: + width=len(str(len(dest_drive['Partitions']))) + for par in dest_drive['Partitions']: + if 'Letter' not in par or re.search(r'(RAW)', par['FileSystem']): + print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par)) + else: + print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par)) + else: + print_warning('\t\tNo partitions found') + if (use_gpt): + print(' Using: \tGPT (UEFI) layout') + else: + print(' Using: \tMBR (legacy) layout') + print_info(' Installing:\t{winver}'.format(winver=selected_windows_version['Name'])) + if (not ask('\nIs this correct?')): + abort_to_main_menu('Aborting Windows setup') + + # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) + remove_volume_letters() + + # Format and partition drive + if (use_gpt): + format_gpt(dest_drive, selected_windows_version['Family']) + else: + format_mbr(dest_drive) + + # Apply Windows image + errors = False + print(' Applying image...') + cmd = '{bin}\\wimlib\\wimlib-imagex apply "{image_file}" "{ImageName}" W:\\'.format(bin=bin, image_file=image_file, **selected_windows_version) + try: + run_program(cmd) + except subprocess.CalledProcessError: + errors = True + print_error('Failed to apply Windows image.') + + # Create boot files + if not errors: + print(' Creating boot files...'.format(**selected_windows_version)) + try: + run_program('bcdboot W:\\Windows /s S: /f ALL') + except subprocess.CalledProcessError: + errors = True + print_error('Failed to create boot files.') + if re.search(r'^(8|10)', selected_windows_version['Family']): + try: + run_program('W:\\Windows\\System32\\reagentc /setreimage /path T:\\Recovery\\WindowsRE /target W:\\Windows') + except subprocess.CalledProcessError: + errors = True + print_error('Failed to setup WindowsRE files.') + + # Print summary + if errors: + print_warning('\nErrors were encountered during setup.') + time.sleep(300) + else: + print_success('\nNo errors were encountered during setup.') + time.sleep(10) + pause('\nPress Enter to return to main menu... ') + +def menu_tools(): + tools = [ + {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, + {'Name': 'CPU-Z', 'Folder': 'CPU-Z', 'File': 'cpuz.exe'}, + {'Name': 'Explorer++', 'Folder': 'Explorer++', 'File': 'Explorer++.exe'}, + {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"']}, + {'Name': 'HW Monitor', 'Folder': 'HWMonitor', 'File': 'HWMonitor.exe'}, + {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, + {'Name': 'Notepad2', 'Folder': 'Notepad2', 'File': 'Notepad2-Mod.exe'}, + {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, + {'Name': 'Prime95', 'Folder': 'Prime95', 'File': 'prime95.exe'}, + {'Name': 'ProduKey', 'Folder': 'ProduKey', 'File': 'ProduKey.exe', 'Args': ['/external']}, + {'Name': 'TestDisk', 'Folder': 'TestDisk', 'File': 'testdisk_win.exe', 'Args': ['-new_console:n']}, + ] + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + while True: + selection = menu_select('Tools Menu', tools, actions) + + if (selection.isnumeric()): + tool = tools[int(selection)-1] + cmd = ['{bin}\\{folder}\\{file}'.format(bin=bin, folder=tool['Folder'], file=tool['File'])] + if tool['Name'] == 'Blue Screen View': + # Select path to scan + minidump_path = select_minidump_path() + if minidump_path is not None: + tool['Args'] = ['/MiniDumpFolder', minidump_path] + if 'Args' in tool: + cmd += tool['Args'] + try: + subprocess.Popen(cmd) + except: + print_error('Failed to run {prog}'.format(prog=tool['Name'])) + time.sleep(2) + elif (selection == 'M'): + break + +def menu_main(): + menus = [ + {'Name': 'Create Backups', 'Menu': menu_backup_imaging}, + {'Name': 'Install Windows', 'Menu': menu_windows_setup}, + {'Name': 'Misc Tools', 'Menu': menu_tools}, + ] + actions = [ + {'Name': 'Command Prompt', 'Letter': 'C'}, + {'Name': 'Reboot', 'Letter': 'R'}, + {'Name': 'Shutdown', 'Letter': 'S'}, + ] + + # Main loop + while True: + selection = menu_select('Main Menu', menus, actions, secret_exit=True) + + if (selection.isnumeric()): + try: + menus[int(selection)-1]['Menu']() + except AbortException: + pass + except: + print_error('Major exception in: {menu}'.format(menu=menus[int(selection)-1]['Name'])) + print_warning(' Please let The Wizard know and he\'ll look into it (Please include the details below).') + print(traceback.print_exc()) + print_info(' You can reboot and try again but if this crashes again an alternative approach is required.') + time.sleep(300) + pause('Press Enter to shutdown...') + run_program(['wpeutil', 'shutdown']) + elif (selection == 'C'): + run_program(['cmd', '-new_console:n'], check=False) + elif (selection == 'R'): + run_program(['wpeutil', 'reboot']) + elif (selection == 'S'): + run_program(['wpeutil', 'shutdown']) + else: + quit() + +if __name__ == '__main__': + menu_main() \ No newline at end of file diff --git a/Scripts/partition_uids.py b/Scripts/partition_uids.py new file mode 100644 index 00000000..1484e2af --- /dev/null +++ b/Scripts/partition_uids.py @@ -0,0 +1,325 @@ +# WK WinPE - PARTITION UIDs +# sources: https://en.wikipedia.org/wiki/GUID_Partition_Table +# https://en.wikipedia.org/wiki/Partition_type + +PARTITION_UIDS = { + '00': {'OS': 'All', 'Description': 'Empty partition entry'}, + '01': {'OS': 'DOS 2.0+', 'Description': 'FAT12 as primary partition in first physical 32 MB of disk or as logical drive anywhere on disk (else use 06hinstead)'}, + '02': {'OS': 'XENIX', 'Description': 'XENIX root'}, + '03': {'OS': 'XENIX', 'Description': 'XENIX usr'}, + '04': {'OS': 'DOS 3.0+', 'Description': 'FAT16 with less than 65536 sectors (32 MB). As primary partition it must reside in first physical 32 MB of disk, or as logical drive anywhere on disk (else use 06h instead).'}, + '05': {'OS': 'DOS (3.2) 3.3+ / SpeedStor', 'Description': 'Extended partition with CHS addressing. It must reside in first physical 8 GB of disk, else use 0Fh instead / can occur in SpeedStor MBRs'}, + '06': {'OS': 'DOS 3.31+', 'Description': 'FAT16B with 65536 or more sectors. It must reside in first physical 8 GB of disk, unless used for logical drives in an 0Fh extended partition (else use 0Eh instead). Also used for FAT12 and FAT16 volumes in primary partitions if they are not residing in first physical 32 MB of disk.'}, + '07': {'OS': 'OS/2 1.2+ / OS/2 1.2+, Windows NT / Windows NT / Windows Embedded CE / QNX 2', 'Description': 'IFS / HPFS / NTFS / exFAT / QNX "qnx" (7) (pre-1988 only)'}, + '08': {'OS': 'Commodore MS-DOS 3.x / OS/2 1.0-1.3 / AIX / QNX 1.x/2.x', 'Description': 'Logical sectored FAT12 or FAT16 / OS/2 (FAT?) / AIX boot/split / SplitDrive / QNX "qny" (8) / partition spanning multiple drives'}, + '09': {'OS': 'AIX / QNX 1.x/2.x / Coherent / OS-9', 'Description': 'AIX data/boot / QNX "qnz" (9) / Coherent file system / OS-9 RBF'}, + '0A': {'OS': 'OS/2 / Coherent', 'Description': 'OS/2 Boot Manager / Coherent swap partition'}, + '0B': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with CHS addressing'}, + '0C': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with LBA'}, + '0D': {'OS': 'Silicon Safe', 'Description': 'Reserved'}, + '0E': {'OS': 'DOS 7.0+', 'Description': 'FAT16B with LBA'}, + '0F': {'OS': 'DOS 7.0+', 'Description': 'Extended partition with LBA'}, + '10': {'OS': 'OPUS', 'Description': 'Unknown'}, + '11': {'OS': 'Leading Edge MS-DOS 3.x / OS/2 Boot Manager', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT12 '}, + '12': {'OS': 'Compaq Contura', 'Description': 'configuration partition (bootable FAT) / configuration partition / hibernation partition / diagnostics and firmware partition (bootable FAT) / service partition (bootable FAT) / Rescue and Recovery partition'}, + '14': {'OS': 'AST MS-DOS 3.x / OS/2 Boot Manager / Maverick OS', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT16 / Omega file system'}, + '15': {'OS': 'OS/2 Boot Manager / Maverick OS', 'Description': 'Hidden extended partition with CHS addressing / swap'}, + '16': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16B '}, + '17': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden IFS / Hidden HPFS / Hidden NTFS / Hidden exFAT '}, + '18': {'OS': 'AST Windows', 'Description': 'AST Zero Volt Suspend or SmartSleep partition'}, + '19': {'OS': 'Willowtech Photon coS', 'Description': 'Willowtech Photon coS'}, + '1B': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 '}, + '1C': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 with LBA '}, + '1E': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16 with LBA '}, + '1F': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden extended partition with LBA addressing '}, + '20': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile update XIP / Willowsoft Overture File System (OFS1)'}, + '21': {'OS': 'Oxygen', 'Description': 'HP Volume Expansion (SpeedStor) / FSo2 (Oxygen File System)'}, + '22': {'OS': 'Oxygen', 'Description': 'Oxygen Extended Partition Table'}, + '23': {'OS': 'Windows Mobile', 'Description': 'Reserved / Windows Mobile boot XIP'}, + '24': {'OS': 'NEC MS-DOS 3.30', 'Description': 'Logical sectored FAT12 or FAT16 '}, + '25': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile IMGFS[citation needed]'}, + '26': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '27': {'OS': 'Windows / PQservice / MirOS BSD / RooterBOOT', 'Description': 'Windows Recovery Environment (RE) partition (hidden NTFS partition type 07h) / FAT32 or NTFS rescue partition / MirOS partition / RooterBOOT kernel partition (contains a raw ELF Linux kernel, no file system)'}, + '2A': {'OS': 'AtheOS', 'Description': 'AtheOS file system (AthFS, AFS) (an extension of BFS, see 2Bh and EBh) / Reserved'}, + '2B': {'OS': 'SyllableOS', 'Description': 'SyllableSecure (SylStor), a variant of AthFS (an extension of BFS, see 2Ah and EBh)'}, + '31': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '32': {'OS': 'NOS', 'Description': 'Unknown'}, + '33': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '34': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '35': {'OS': 'OS/2 Warp Server /eComStation', 'Description': 'JFS (OS/2 implementation of AIX Journaling File system)'}, + '36': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '38': {'OS': 'THEOS', 'Description': 'THEOS version 3.2, 2 GB partition'}, + '39': {'OS': 'Plan 9 / THEOS', 'Description': 'Plan 9 edition 3 partition (sub-partitions described in second sector of partition) / THEOS version 4 spanned partition'}, + '3A': {'OS': 'THEOS', 'Description': 'THEOS version 4, 4 GB partition'}, + '3B': {'OS': 'THEOS', 'Description': 'THEOS version 4 extended partition'}, + '3C': {'OS': 'PartitionMagic', 'Description': 'PqRP (PartitionMagic or DriveImage in progress)'}, + '3D': {'OS': 'PartitionMagic', 'Description': 'Hidden NetWare'}, + '3F': {'OS': 'OS/32', 'Description': 'Unknown'}, + '40': {'OS': 'PICK / Venix', 'Description': 'PICK R83 / Venix 80286'}, + '41': {'OS': 'Personal RISC / Linux / PowerPC', 'Description': 'Personal RISC Boot / Old Linux/Minix (disk shared with DR DOS 6.0) / PPC PReP (Power PC Reference Platform) Boot'}, + '42': {'OS': 'SFS / Linux / Windows 2000, XP, etc.', 'Description': 'Secure File system (SFS) / Old Linux swap (disk shared with DR DOS 6.0) / Dynamic extended partition marker'}, + '43': {'OS': 'Linux', 'Description': 'Old Linux native (disk shared with DR DOS 6.0) '}, + '44': {'OS': 'GoBack', 'Description': 'Norton GoBack, WildFile GoBack, Adaptec GoBack, Roxio GoBack'}, + '45': {'OS': 'Boot-US / EUMEL/ELAN', 'Description': 'Priam / Boot-US boot manager (1 cylinder) / EUMEL/ELAN (L2)'}, + '46': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, + '47': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, + '48': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2), ERGOS L3'}, + '4A': {'OS': 'AdaOS / ALFS/THIN', 'Description': 'Aquila / ALFS/THIN advanced lightweight file system for DOS'}, + '4C': {'OS': 'ETH Oberon', 'Description': 'Aos (A2) file system (76)'}, + '4D': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Primary QNX POSIX volume on disk (77)'}, + '4E': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Secondary QNX POSIX volume on disk (78)'}, + '4F': {'OS': 'QNX 4.x, Neutrino / ETH Oberon', 'Description': 'Tertiary QNX POSIX volume on disk (79) / boot / native file system (79)'}, + '50': {'OS': 'ETH Oberon / Disk Manager 4 / LynxOS / Novell', 'Description': 'Alternative native file system (80) / Read-only partition (old) / Lynx RTOS'}, + '51': {'OS': 'Disk Manager 4-6', 'Description': 'Read-write partition (Aux 1)'}, + '52': {'OS': 'CP/M-80 / System V/AT, V/386', 'Description': 'CP/M-80'}, + '53': {'OS': 'Disk Manager 6', 'Description': 'Auxiliary 3 (WO)'}, + '54': {'OS': 'Disk Manager 6', 'Description': 'Dynamic Drive Overlay (DDO)'}, + '55': {'OS': 'EZ-Drive', 'Description': 'EZ-Drive, Maxtor, MaxBlast, or DriveGuide INT 13h redirector volume'}, + '56': {'OS': 'AT&T MS-DOS 3.x / EZ-Drive / VFeature', 'Description': 'Logical sectored FAT12 or FAT16 / Disk Manager partition converted to EZ-BIOS / VFeature partitionned volume'}, + '57': {'OS': 'DrivePro', 'Description': 'VNDI partition'}, + '5C': {'OS': 'EDISK', 'Description': 'Priam EDisk Partitioned Volume '}, + '61': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + '63': {'OS': 'Unix', 'Description': 'SCO Unix, ISC, UnixWare, AT&T System V/386, ix, MtXinu BSD 4.3 on Mach, GNU HURD'}, + '64': {'OS': 'SpeedStor / NetWare', 'Description': 'NetWare File System 286/2 / PC-ARMOUR'}, + '65': {'OS': 'NetWare', 'Description': 'NetWare File System 386'}, + '66': {'OS': 'NetWare / NetWare', 'Description': 'NetWare File System 386 / Storage Management Services (SMS)'}, + '67': {'OS': 'NetWare', 'Description': 'Wolf Mountain'}, + '68': {'OS': 'NetWare', 'Description': 'Unknown'}, + '69': {'OS': 'NetWare 5 / NetWare', 'Description': 'Novell Storage Services (NSS)'}, + '6E': {'Description': 'Unknown'}, + '70': {'OS': 'DiskSecure', 'Description': 'DiskSecure multiboot'}, + '71': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '72': {'OS': 'APTI conformant systems / Unix V7/x86', 'Description': 'APTI alternative FAT12 (CHS, SFN) / V7/x86'}, + '73': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '74': {'OS': 'Microsoft, IBM', 'Description': 'Reserved / Scramdisk'}, + '75': {'OS': 'PC/IX', 'Description': 'Unknown'}, + '76': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '77': {'OS': 'Novell', 'Description': 'VNDI, M2FS, M2CS'}, + '78': {'OS': 'Geurt Vos', 'Description': 'XOSL bootloader file system'}, + '79': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (CHS, SFN) '}, + '7A': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (LBA, SFN) '}, + '7B': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16B (CHS, SFN) '}, + '7C': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (LBA, SFN) '}, + '7D': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (CHS, SFN) '}, + '7E': {'OS': 'F.I.X. (claim) / PrimoCache', 'Description': 'Level 2 cache'}, + '7F': {'OS': 'Varies', 'Description': 'Alternative OS Development Partition Standard - reserved for individual or local use and temporary or experimental projects'}, + '80': {'OS': 'Minix 1.1-1.4a', 'Description': 'Minix file system (old)'}, + '81': {'OS': 'Minix 1.4b+ / Linux', 'Description': 'MINIX file system / Mitac Advanced Disk Manager'}, + '82': {'OS': 'Linux / Sun Microsystems', 'Description': 'Linux swap space / Solaris x86 (for Sun disklabels up to 2005) / Prime'}, + '83': {'OS': 'GNU/Linux', 'Description': 'Any native Linux file system '}, + '84': {'OS': 'OS/2 / Windows 7', 'Description': 'APM hibernation (suspend to disk, S2D) / Hidden C: (FAT16) / Rapid Start technology'}, + '85': {'OS': 'GNU/Linux', 'Description': 'Linux extended '}, + '86': {'OS': 'Windows NT 4 Server / Linux', 'Description': 'Fault-tolerant FAT16B mirrored volume set / Linux RAID superblock with auto-detect (old)'}, + '87': {'OS': 'Windows NT 4 Server', 'Description': 'Fault-tolerant HPFS/NTFS mirrored volume set '}, + '88': {'OS': 'GNU/Linux', 'Description': 'Linux plaintext partition table'}, + '8A': {'OS': 'AiR-BOOT', 'Description': 'Linux kernel image'}, + '8B': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, + '8C': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, + '8D': {'OS': 'Free FDISK', 'Description': 'Hidden FAT12 '}, + '8E': {'OS': 'Linux', 'Description': 'Linux LVM'}, + '90': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, + '91': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with CHS addressing '}, + '92': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16B '}, + '93': {'OS': 'Amoeba / Linux', 'Description': 'Amoeba native file system / Hidden Linux file system'}, + '94': {'OS': 'Amoeba', 'Description': 'Amoeba bad block table'}, + '95': {'OS': 'EXOPC', 'Description': 'EXOPC native'}, + '96': {'OS': 'CHRP', 'Description': 'ISO-9660 file system'}, + '97': {'OS': 'Free FDISK', 'Description': 'Hidden FAT32 '}, + '98': {'OS': 'Free FDISK / ROM-DOS', 'Description': 'Hidden FAT32 / service partition (bootable FAT) ROM-DOS SuperBoot / service partition (bootable FAT)'}, + '99': {'OS': 'early Unix', 'Description': 'Unknown'}, + '9A': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, + '9B': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with LBA '}, + '9E': {'OS': 'VSTA / ForthOS', 'Description': 'ForthOS (eForth port)'}, + '9F': {'OS': 'BSD/OS 3.0+, BSDI', 'Description': 'Unknown'}, + 'A0': {'OS': 'Hewlett Packard / Phoenix, IBM, Toshiba, Sony', 'Description': 'Diagnostic partition for HP laptops / Hibernate partition'}, + 'A1': {'OS': 'Hewlett Packard / Phoenix, NEC', 'Description': 'HP Volume Expansion (SpeedStor) / Hibernate partition'}, + 'A2': {'OS': 'Cyclone V', 'Description': 'Hard Processor System (HPS) ARM preloader'}, + 'A3': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'A4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'A5': {'OS': 'BSD', 'Description': 'BSD slice (BSD/386, 386BSD, NetBSD (old), FreeBSD)'}, + 'A6': {'OS': 'OpenBSD', 'Description': 'HP Volume Expansion (SpeedStor) / OpenBSD slice'}, + 'A7': {'OS': 'NeXT', 'Description': 'NeXTSTEP'}, + 'A8': {'OS': 'Darwin, Mac OS X', 'Description': 'Apple Darwin, Mac OS X UFS'}, + 'A9': {'OS': 'NetBSD', 'Description': 'NetBSD slice'}, + 'AA': {'OS': 'MS-DOS', 'Description': 'Olivetti MS-DOS FAT12 (1.44 MB) '}, + 'AB': {'OS': 'Darwin, Mac OS X / GO! OS', 'Description': 'Apple Darwin, Mac OS X boot / GO!'}, + 'AD': {'OS': 'RISC OS', 'Description': 'ADFS / FileCore format'}, + 'AE': {'OS': 'ShagOS', 'Description': 'ShagOS file system'}, + 'AF': {'OS': 'ShagOS', 'Description': 'Apple Mac OS X HFS and HFS+ / ShagOS swap'}, + 'B0': {'OS': 'Boot-Star', 'Description': 'Boot-Star dummy partition'}, + 'B1': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, + 'B2': {'OS': 'QNX 6.x', 'Description': 'QNX Neutrino power-safe file system'}, + 'B3': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, + 'B4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'B6': {'OS': 'Windows NT 4 Server', 'Description': 'HP Volume Expansion (SpeedStor) / Corrupted fault-tolerant FAT16B mirrored master volume '}, + 'B7': {'OS': 'BSDI (before 3.0) / Windows NT 4 Server', 'Description': 'BSDI native file system / swap / Corrupted fault-tolerant HPFS/NTFS mirrored master volume '}, + 'B8': {'OS': 'BSDI (before 3.0)', 'Description': 'BSDI swap / native file system'}, + 'BB': {'OS': 'BootWizard, OS Selector / Acronis True Image / Windows NT 4 Server', 'Description': 'PTS BootWizard 4 / OS Selector 5 for hidden partitions other than 01h, 04h, 06h, 07h, 0Bh, 0Ch, 0Eh and unformatted partitions / OEM Secure Zone (corresponds to BCh) / Corrupted fault-tolerant FAT32 mirrored master volume '}, + 'BC': {'OS': 'Windows NT 4 Server / Acronis True Image / Backup Capsule', 'Description': 'Corrupted fault-tolerant FAT32 mirrored master volume / Acronis Secure Zone / Backup Capsule'}, + 'BD': {'OS': 'BonnyDOS/286', 'Description': 'Unknown'}, + 'BE': {'OS': 'Solaris 8', 'Description': 'Solaris 8 boot'}, + 'BF': {'OS': 'Solaris', 'Description': 'Solaris x86 (for Sun disklabels, since 2005)'}, + 'C0': {'OS': 'DR-DOS, Multiuser DOS,REAL/32', 'Description': 'Secured FAT partition (smaller than 32 MB)'}, + 'C1': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT12 '}, + 'C2': {'OS': 'Power Boot', 'Description': 'Hidden Linux native file system'}, + 'C3': {'OS': 'Power Boot', 'Description': 'Hidden Linux swap'}, + 'C4': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT16 '}, + 'C5': {'OS': 'DR DOS 6.0+', 'Description': 'Secured extended partition with CHS addressing '}, + 'C6': {'OS': 'DR DOS 6.0+ / Windows NT 4 Server', 'Description': 'Secured FAT16B / Corrupted fault-tolerant FAT16B mirrored slave volume '}, + 'C7': {'OS': 'Syrinx / Windows NT 4 Server', 'Description': 'Syrinx boot / Corrupted fault-tolerant HPFS/NTFS mirrored slave volume '}, + 'C8': {'Description': 'Reserved for DR-DOS since 1997'}, + 'C9': {'Description': 'Reserved for DR-DOS since 1997'}, + 'CA': {'Description': 'Reserved for DR-DOS since 1997'}, + 'CB': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, + 'CC': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, + 'CD': {'OS': 'CTOS', 'Description': 'Memory dump'}, + 'CE': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured FAT16B '}, + 'CF': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured extended partition with LBA '}, + 'D0': {'OS': 'Multiuser DOS, REAL/32', 'Description': 'Secured FAT partition (larger than 32 MB)'}, + 'D1': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT12 '}, + 'D4': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16 '}, + 'D5': {'OS': 'Multiuser DOS', 'Description': 'Secured extended partition with CHS addressing '}, + 'D6': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16B '}, + 'D8': {'OS': 'Digital Research', 'Description': 'CP/M-86 [citation needed]'}, + 'DA': {'OS': 'Powercopy Backup', 'Description': 'Non-file system data / Shielded disk'}, + 'DB': {'OS': 'CP/M-86,Concurrent CP/M-86,Concurrent DOS / CTOS / D800 / DRMK', 'Description': 'CP/M-86, Concurrent CP/M-86, Concurrent DOS / boot image for x86 supervisor CPU (SCPU) module / FAT32 system restore partition (DSR)'}, + 'DD': {'OS': 'CTOS', 'Description': 'Hidden memory dump'}, + 'DE': {'OS': 'Dell', 'Description': 'FAT16 utility/diagnostic partition'}, + 'DF': {'OS': 'DG/UX / BootIt / Aviion', 'Description': 'DG/UX virtual disk manager / EMBRM'}, + 'E0': {'OS': 'STMicroelectronics', 'Description': 'ST AVFS'}, + 'E1': {'OS': 'SpeedStor', 'Description': 'Extended FAT12 (> 1023 cylinder)'}, + 'E2': {'Description': 'DOS read-only (XFDISK)'}, + 'E3': {'OS': 'SpeedStor', 'Description': 'DOS read-only'}, + 'E4': {'OS': 'SpeedStor', 'Description': 'Extended FAT16 (< 1024 cylinder)'}, + 'E5': {'OS': 'Tandy MS-DOS', 'Description': 'Logical sectored FAT12 or FAT16'}, + 'E6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'E8': {'OS': 'LUKS', 'Description': 'Linux Unified Key Setup'}, + 'EB': {'OS': 'BeOS, Haiku', 'Description': 'BFS'}, + 'EC': {'OS': 'SkyOS', 'Description': 'SkyFS'}, + 'ED': {'OS': 'Sprytix / EDD 4', 'Description': 'EDC loader / GPT hybrid MBR'}, + 'EE': {'OS': 'EFI', 'Description': 'GPT protective MBR'}, + 'EF': {'OS': 'EFI', 'Description': 'EFI system partition can be a FAT12, FAT16, FAT32 (or other) file system'}, + 'F0': {'OS': 'Linux / OS/32', 'Description': 'PA-RISC Linux boot loader. It must reside in first physical 2 GB. / floppy'}, + 'F1': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F2': {'OS': 'Sperry IT MS-DOS 3.x, Unisys MS-DOS 3.3, Digital ResearchDOS Plus 2.1', 'Description': 'Logical sectored FAT12 or FAT16 secondary partition'}, + 'F3': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F4': {'OS': 'SpeedStor / Prologue', 'Description': '"large" DOS partition / single volume partition for NGF or TwinFS'}, + 'F5': {'OS': 'Prologue', 'Description': 'MD0-MD9 multi volume partition for NGF or TwinFS'}, + 'F6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F7': {'OS': 'O.S.G. / X1', 'Description': 'EFAT / Solid State file system'}, + 'F9': {'OS': 'Linux', 'Description': 'pCache ext2/ext3 persistent cache'}, + 'FA': {'OS': 'Bochs', 'Description': 'x86 emulator'}, + 'FB': {'OS': 'VMware', 'Description': 'VMware VMFS file system partition'}, + 'FC': {'OS': 'VMware', 'Description': 'VMware swap / VMKCORE kernel dump partition'}, + 'FD': {'OS': 'Linux / FreeDOS', 'Description': 'Linux RAID superblock with auto-detect / Reserved for FreeDOS'}, + 'FE': {'OS': 'SpeedStor / LANstep / Windows NT / Linux', 'Description': 'partition > 1024 cylinder / PS/2 IML partition / PS/2 recovery partition (FAT12 reference disk floppy image), / Disk Administration hidden partition / old Linux LVM'}, + 'FF': {'OS': 'XENIX', 'Description': 'XENIX bad block table'}, + '00000000-0000-0000-0000-000000000000': {'Description': 'Unused entry'}, + '024DEE41-33E7-11D3-9D69-0008C781F39F': {'Description': 'MBR partition scheme'}, + 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B': {'Description': 'EFI System partition'}, + '21686148-6449-6E6F-744E-656564454649': {'Description': 'BIOS Boot partition'}, + 'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593': {'Description': 'Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)'}, + 'F4019732-066E-4E12-8273-346C5641494F': {'Description': 'Sony boot partition'}, + 'BFBFAFE7-A34F-448A-9A5B-6213EB736C22': {'Description': 'Lenovo boot partition'}, + 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE': {'OS': 'Windows', 'Description': 'Microsoft Reserved Partition (MSR)'}, + 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7': {'OS': 'Windows', 'Description': 'Basic data partition'}, + '5808C8AA-7E8F-42E0-85D2-E1E90434CFB3': {'OS': 'Windows', 'Description': 'Logical Disk Manager (LDM) metadata partition'}, + 'AF9B60A0-1431-4F62-BC68-3311714A69AD': {'OS': 'Windows', 'Description': 'Logical Disk Manager data partition'}, + 'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC': {'OS': 'Windows', 'Description': 'Windows Recovery Environment'}, + '37AFFC90-EF7D-4E96-91C3-2D7AE055B174': {'OS': 'Windows', 'Description': 'IBM General Parallel File System (GPFS) partition'}, + 'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D': {'OS': 'Windows', 'Description': 'Storage Spaces partition'}, + '75894C1E-3AEB-11D3-B7C1-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Data partition'}, + 'E2A1E728-32E3-11D6-A682-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Service Partition'}, + '0FC63DAF-8483-4772-8E79-3D69D8477DE4': {'OS': 'Linux', 'Description': 'Linux filesystem data'}, + 'A19D880F-05FC-4D3B-A006-743F0F84911E': {'OS': 'Linux', 'Description': 'RAID partition'}, + '44479540-F297-41B2-9AF7-D131D5F0458A': {'OS': 'Linux', 'Description': 'Root partition (x86)'}, + '4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709': {'OS': 'Linux', 'Description': 'Root partition (x86-64)'}, + '69DAD710-2CE4-4E3C-B16C-21A1D49ABED3': {'OS': 'Linux', 'Description': 'Root partition (32-bit ARM)'}, + 'B921B045-1DF0-41C3-AF44-4C6F280D3FAE': {'OS': 'Linux', 'Description': 'Root partition (64-bit ARM/AArch64)'}, + '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F': {'OS': 'Linux', 'Description': 'Swap partition'}, + 'E6D6D379-F507-44C2-A23C-238F2A3DF928': {'OS': 'Linux', 'Description': 'Logical Volume Manager (LVM) partition'}, + '933AC7E1-2EB4-4F13-B844-0E14E2AEF915': {'OS': 'Linux', 'Description': '/home partition'}, + '3B8F8425-20E0-4F3B-907F-1A25A76F98E8': {'OS': 'Linux', 'Description': '/srv (server data) partition'}, + '7FFEC5C9-2D00-49B7-8941-3EA10A5586B7': {'OS': 'Linux', 'Description': 'Plain dm-crypt partition'}, + 'CA7D7CCB-63ED-4C53-861C-1742536059CC': {'OS': 'Linux', 'Description': 'LUKS partition'}, + '8DA63339-0007-60C0-C436-083AC8230908': {'OS': 'Linux', 'Description': 'Reserved'}, + '83BD6B9D-7F41-11DC-BE0B-001560B84F0F': {'OS': 'FreeBSD', 'Description': 'Boot partition'}, + '516E7CB4-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Data partition'}, + '516E7CB5-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Swap partition'}, + '516E7CB6-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Unix File System (UFS) partition'}, + '516E7CB8-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Vinum volume manager partition'}, + '516E7CBA-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'ZFS partition'}, + '48465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Hierarchical File System Plus (HFS+) partition'}, + '55465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple UFS'}, + '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'OS X Darwin', 'Description': 'ZFS'}, + '52414944-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition'}, + '52414944-5F4F-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition, offline'}, + '426F6F74-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Boot partition (Recovery HD)'}, + '4C616265-6C00-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Label'}, + '5265636F-7665-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple TV Recovery partition'}, + '53746F72-6167-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Core Storage (i.e. Lion FileVault) partition'}, + '6A82CB45-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Boot partition'}, + '6A85CF4D-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Root partition'}, + '6A87C46F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Swap partition'}, + '6A8B642B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Backup partition'}, + '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/usr partition'}, + '6A8EF2E9-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/var partition'}, + '6A90BA39-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/home partition'}, + '6A9283A5-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Alternate sector'}, + '6A945A3B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Reserved partition'}, + '6A9630D1-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A980767-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A96237F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A8D2AC7-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '49F48D32-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Swap partition'}, + '49F48D5A-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'FFS partition'}, + '49F48D82-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'LFS partition'}, + '49F48DAA-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'RAID partition'}, + '2DB519C4-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Concatenated partition'}, + '2DB519EC-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Encrypted partition'}, + 'FE3A2A5D-4F32-41A7-B725-ACCC3285A309': {'OS': 'ChromeOS', 'Description': 'ChromeOS kernel'}, + '3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC': {'OS': 'ChromeOS', 'Description': 'ChromeOS rootfs'}, + '2E0A753D-9E48-43B0-8337-B15192CB1B5E': {'OS': 'ChromeOS', 'Description': 'ChromeOS future use'}, + '42465331-3BA3-10F1-802A-4861696B7521': {'OS': 'Haiku', 'Description': 'Haiku BFS'}, + '85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Boot partition'}, + '85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Data partition'}, + '85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Swap partition'}, + '0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Unix File System (UFS) partition'}, + '85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Vinum volume manager partition'}, + '85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'ZFS partition'}, + '45B0969E-9B03-4F30-B4C6-B4B80CEFF106': {'OS': 'Ceph', 'Description': 'Ceph Journal'}, + '45B0969E-9B03-4F30-B4C6-5EC00CEFF106': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt Encrypted Journal'}, + '4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph OSD'}, + '4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt OSD'}, + '89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph disk in creation'}, + '89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt disk in creation'}, + '824CC7A0-36A8-11E3-890A-952519AD3F61': {'OS': 'OpenBSD', 'Description': 'Data partition'}, + 'CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1': {'OS': 'QNX', 'Description': 'Power-safe (QNX6) file system'}, + 'C91818F9-8025-47AF-89D2-F030D7000C2C': {'OS': 'Plan 9', 'Description': 'Plan 9 partition'}, + '9D275380-40AD-11DB-BF97-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'vmkcore (coredump partition)'}, + 'AA31E02A-400F-11DB-9590-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMFS filesystem partition'}, + '9198EFFC-31C0-11DB-8F78-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMware Reserved'}, + '2568845D-2332-4675-BC39-8FA5A4748D15': {'OS': 'Android-IA', 'Description': 'Bootloader'}, + '114EAFFE-1552-4022-B26E-9B053604CF84': {'OS': 'Android-IA', 'Description': 'Bootloader2'}, + '49A4D17F-93A3-45C1-A0DE-F50B2EBE2599': {'OS': 'Android-IA', 'Description': 'Boot'}, + '4177C722-9E92-4AAB-8644-43502BFD5506': {'OS': 'Android-IA', 'Description': 'Recovery'}, + 'EF32A33B-A409-486C-9141-9FFB711F6266': {'OS': 'Android-IA', 'Description': 'Misc'}, + '20AC26BE-20B7-11E3-84C5-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Metadata'}, + '38F428E6-D326-425D-9140-6E0EA133647C': {'OS': 'Android-IA', 'Description': 'System'}, + 'A893EF21-E428-470A-9E55-0668FD91A2D9': {'OS': 'Android-IA', 'Description': 'Cache'}, + 'DC76DDA9-5AC1-491C-AF42-A82591580C0D': {'OS': 'Android-IA', 'Description': 'Data'}, + 'EBC597D0-2053-4B15-8B64-E0AAC75F4DB1': {'OS': 'Android-IA', 'Description': 'Persistent'}, + '8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80': {'OS': 'Android-IA', 'Description': 'Factory'}, + '767941D0-2085-11E3-AD3B-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Fastboot / Tertiary'}, + 'AC6D7924-EB71-4DF8-B48D-E267B27148FF': {'OS': 'Android-IA', 'Description': 'OEM'}, + '7412F7D5-A156-4B13-81DC-867174929325': {'OS': 'ONIE', 'Description': 'Boot'}, + 'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149': {'OS': 'ONIE', 'Description': 'Config'}, + '9E1A2D38-C612-4316-AA26-8B49521E5A8B': {'OS': 'PowerPC', 'Description': 'PReP boot'}, + 'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'}, +} + +def lookup_guid(guid): + return PARTITION_UIDS.get(guid.upper(), None) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/servers.ps1 b/Scripts/servers.ps1 deleted file mode 100644 index 2d47e19f..00000000 --- a/Scripts/servers.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -# WK server functions - -## Init ## -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -pushd "$wd" -. .\init.ps1 - -# Variables -$source_server = "10.0.0.10" -$backup_servers = @( - @{ "ip"="10.0.0.10"; - "letter"="Z"; - "name"="ServerOne"; - "path"="Backups"}, - @{ "ip"="10.0.0.11"; - "name"="ServerTwo"; - "letter"="Y"; - "path"="Backups"} - ) -$backup_user = "backup" -$backup_pass = "Abracadabra" - -# Functions -function select-server { - # Check for available servers - $avail_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - if ($avail_servers.count -eq 0) { - wk-error "No suitable backup servers were detected." - return $false - } - - # Build menu and get selection - $selection = $null - $main_set = @() - foreach ($server in $avail_servers) { - $_entry = "{0} ({1} free)" -f $server.Description, (human-size $server.Free) - $main_set += @{Name=$_entry} - } - $actions = @(@{Name="Main Menu"; Letter="M"}) - $selection = (menu-select "Where are we saving the backup image(s)?" $main_set $actions) - - if ($selection -imatch '^\d+$') { - $selection -= 1 - return $avail_servers[$selection] - } - return $selection -} -function mount-servers { - # Mount servers - wk-write "Connecting to backup server(s)" - foreach ($_server in $backup_servers) { - if (test-connection $_server.ip -count 3 -quiet) { - try { - $_path = "\\{0}\{1}" -f $_server.ip, $_server.path - $_drive = "{0}:" -f $_server.letter - net use $_drive "$_path" /user:$backup_user $backup_pass | Out-Null - wk-write ("`t{0} server: mounted" -f $_server.name) - - # Add friendly description - $_regex = "^{0}$" -f $_server.letter - (Get-PSDrive | Where-Object {$_.Name -imatch $_regex}).Description = $_server.name - } catch { - wk-warn ("`t{0} server: failed" -f $_server.name) - } - } else { - wk-warn ("`t{0} server: timed-out" -f $_server.name) - } - } -} -function unmount-servers { - # Unmount servers - wk-write "Disconnecting from backup server(s)" - $mounted_servers = @(Get-PSDrive | Where-Object {$_.DisplayRoot -imatch '\\\\'}) - foreach ($_server in $mounted_servers) { - try { - $_drive = "{0}:" -f $_server.Name - net use $_drive /delete | Out-Null - #wk-warn ("`t{0} server: unmounted" -f $_server.name) - wk-warn "`tServer: unmounted" - } catch { - #wk-warn ("`t{0} server: failed" -f $_server.name) - wk-warn "`tServer: failed" - } - } -} diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index 28aee836..cd3d04ab 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,4 +2,4 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -NoProfile -new_console:n +"%SystemDrive%\WK\conemu-maximus5\ConEmu.exe", /cmd cmd /k python %SystemDrive%\WK\Scripts\menu.py" diff --git a/System32/menu.cmd b/System32/menu.cmd deleted file mode 100644 index 2769cd76..00000000 --- a/System32/menu.cmd +++ /dev/null @@ -1,31 +0,0 @@ -@echo off - -:Init -setlocal EnableDelayedExpansion -title Menu Launcher -color 0b -pushd %~dp0 - -:Flags -for %%f in (%*) do ( - if /i "%%f" == "/DEBUG" (@echo on) -) - -:LaunchMenu -"%SystemDrive%\WK\ConEmu\ConEmu.exe" /cmd PowerShell -ExecutionPolicy Bypass "%SystemDrive%\WK\Scripts\WK.ps1" -NoProfile -new_console:n -goto Done - -:Abort -echo. -echo Aborted. -goto Exit - -:Done -echo. -echo Done. -goto Exit - -:Exit -echo. -popd -endlocal diff --git a/WK/amd64/ConEmu/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml deleted file mode 100644 index 26a3611c..00000000 --- a/WK/amd64/ConEmu/ConEmu.xml +++ /dev/null @@ -1,643 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/amd64/HWMonitor/hwmonitorw.ini b/WK/amd64/HWMonitor/hwmonitorw.ini index e3978b4e..0bfb23e7 100644 --- a/WK/amd64/HWMonitor/hwmonitorw.ini +++ b/WK/amd64/HWMonitor/hwmonitorw.ini @@ -4,5 +4,4 @@ USE_ACPI=1 USE_SMBUS=1 USE_SMART=1 USE_DISPLAY=1 -CPU_0_TJMAX=100.0 UPDATES=0 diff --git a/WK/amd64/conemu-maximus5/ConEmu.xml b/WK/amd64/conemu-maximus5/ConEmu.xml new file mode 100644 index 00000000..4d75ab86 --- /dev/null +++ b/WK/amd64/conemu-maximus5/ConEmu.xml @@ -0,0 +1,844 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/x86/ConEmu/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml deleted file mode 100644 index 26a3611c..00000000 --- a/WK/x86/ConEmu/ConEmu.xml +++ /dev/null @@ -1,643 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/x86/conemu-maximus5/ConEmu.xml b/WK/x86/conemu-maximus5/ConEmu.xml new file mode 100644 index 00000000..4d75ab86 --- /dev/null +++ b/WK/x86/conemu-maximus5/ConEmu.xml @@ -0,0 +1,844 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/make.cmd b/make.cmd index efc6a59d..1447ecd8 100644 --- a/make.cmd +++ b/make.cmd @@ -88,28 +88,28 @@ for %%a in (amd64 x86) do ( dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-EnhancedStorage_en-us.cab" /logpath:"dism.log" dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-WMI_en-us.cab" /logpath:"dism.log" - rem Install WinPE-WMI before you install WinPE-NetFX. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-NetFx.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI before you install WinPE-NetFX. + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-NetFx.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" - rem Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-Scripting.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-Scripting.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" - rem Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-PowerShell.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-PowerShell.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" - rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-DismCmdlets.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-DismCmdlets.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" - rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. + rem rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" - rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-StorageWMI.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" + rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-StorageWMI.cab" /logpath:"dism.log" + rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" rem Add Drivers dism /add-driver /image:"!mount!" /driver:"!drivers!" /recurse /logpath:"dism.log" @@ -125,21 +125,20 @@ for %%a in (amd64 x86) do ( robocopy /s /r:3 /w:0 "!wd!\Scripts" "!mount!\WK\Scripts" rem Add System32 Stuff - copy /y "!wd!\System32\menu.cmd" "!mount!\Windows\System32\menu.cmd" copy /y "!wd!\System32\Winpeshl.ini" "!mount!\Windows\System32\Winpeshl.ini" rem Background takeown /f "!mount!\Windows\System32\winpe.jpg" /a icacls "!mount!\Windows\System32\winpe.jpg" /grant administrators:F copy /y "!wd!\System32\winpe.jpg" "!mount!\Windows\System32\winpe.jpg" - copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\ConEmu\winpe.jpg" + copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\conemu-maximus5\winpe.jpg" rem Registry Edits reg load HKLM\WinPE-SW "!mount!\Windows\System32\config\SOFTWARE" reg load HKLM\WinPE-SYS "!mount!\Windows\System32\config\SYSTEM" - rem Add 7-Zip to path - reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip" /f + rem Add 7-Zip and Python to path + reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip;%%SystemDrive%%\WK\python;%%SystemDrive%%\WK\wimlib" /f rem Replace Notepad reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod.exe /z" /f @@ -153,7 +152,7 @@ for %%a in (amd64 x86) do ( rem Create ISO del "WinPE-!iso_date!-!arch!.iso" - call makewinpemedia.cmd /iso "!pe_files!" "WinPE-!iso_date!-!arch!.iso" + call makewinpemedia.cmd /iso "!pe_files!" "WinPE-!iso_date!-!arch!-testing.iso" ) goto Done From 8cf135d9ebff594b4a925d60834602359aa42e94 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:05:40 -0800 Subject: [PATCH 09/85] 2016-09: Retroactive Updates * Added WIM backup image verification phase * WIM backup images now created much faster * This was done by not creating the extra integrity information * Readded support for swm files * ComEmu will now open in fullscreen mode without the titlebar --- Scripts/functions.py | 71 ++++++++++++++++++++++------- Scripts/menu.py | 45 +++++++++++++----- WK/amd64/conemu-maximus5/ConEmu.xml | 28 ++++++------ WK/x86/conemu-maximus5/ConEmu.xml | 2 +- 4 files changed, 102 insertions(+), 44 deletions(-) diff --git a/Scripts/functions.py b/Scripts/functions.py index f7aea8f2..3f69b408 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -150,13 +150,13 @@ def assign_volume_letters(): except: pass -def remove_volume_letters(): +def remove_volume_letters(keep=None): with open(diskpart_script, 'w') as script: script.write('list volume\n') process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) with open(diskpart_script, 'w') as script: for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): - if tmp[1] != '': + if tmp[1] != '' and tmp[1] != keep: script.write('select volume {number}\n'.format(number=tmp[0])) script.write('remove\n') try: @@ -192,7 +192,7 @@ def select_minidump_path(): def find_windows_image(filename=None): """Search for a Windows source image file on local drives and network drives (in that order)""" - image_file = None + image = {} # Bail early if filename is None: @@ -203,19 +203,30 @@ def find_windows_image(filename=None): for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): for ext in ['esd', 'wim', 'swm']: if os.path.isfile('{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename)): - image_file = '{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename) + image['Ext'] = ext + image['File'] = '{drive}:\\images\\{filename}'.format(drive=tmp[0], filename=filename) + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = tmp[0] break # Check for network source (if necessary) - if image_file is None: + if not any(image): if not WINDOWS_SERVER['Mounted']: mount_windows_share() - for ext in ['esd', 'wim']: + for ext in ['esd', 'wim', 'swm']: if os.path.isfile('\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER)): - image_file = '\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER) + image['Ext'] = ext + image['File'] = '\\\\{IP}\\{Share}\\images\\{filename}'.format(filename=filename, **WINDOWS_SERVER) + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = None break - - return image_file + + # Display image to be used (if any) and return + if any(image): + print_info('Using image: {File}.{Ext}'.format(**image)) + return image + else: + return None def format_gpt(disk=None, windows_family=None): """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" @@ -431,16 +442,42 @@ def select_disk(prompt='Which disk?'): def select_windows_version(): versions = [ - {'Name': 'Windows 7 Home Basic', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 HOMEBASIC', 'Family': '7'}, - {'Name': 'Windows 7 Home Premium', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 HOMEPREMIUM', 'Family': '7'}, - {'Name': 'Windows 7 Professional', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 PROFESSIONAL', 'Family': '7'}, - {'Name': 'Windows 7 Ultimate', 'ImageFile': 'Win7', 'ImageName': 'Windows 7 ULTIMATE', 'Family': '7'}, + {'Name': 'Windows 7 Home Basic', + 'ImageFile': 'Win7', + 'ImageName': 'Windows 7 HOMEBASIC', + 'Family': '7'}, + {'Name': 'Windows 7 Home Premium', + 'ImageFile': 'Win7', + 'ImageName': 'Windows 7 HOMEPREMIUM', + 'Family': '7'}, + {'Name': 'Windows 7 Professional', + 'ImageFile': 'Win7', + 'ImageName': 'Windows 7 PROFESSIONAL', + 'Family': '7'}, + {'Name': 'Windows 7 Ultimate', + 'ImageFile': 'Win7', + 'ImageName': 'Windows 7 ULTIMATE', + 'Family': '7'}, - {'Name': 'Windows 8.1', 'ImageFile': 'Win8', 'ImageName': 'Windows 8.1', 'Family': '8', 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', 'ImageFile': 'Win8', 'ImageName': 'Windows 8.1 Pro', 'Family': '8'}, + {'Name': 'Windows 8.1', + 'ImageFile': 'Win8', + 'ImageName': 'Windows 8.1', + 'Family': '8', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'ImageFile': 'Win8', + 'ImageName': 'Windows 8.1 Pro', + 'Family': '8'}, - {'Name': 'Windows 10 Home', 'ImageFile': 'Win10', 'ImageName': 'Windows 10 Home', 'Family': '10', 'CRLF': True}, - {'Name': 'Windows 10 Pro', 'ImageFile': 'Win10', 'ImageName': 'Windows 10 Pro', 'Family': '10'}, + {'Name': 'Windows 10 Home', + 'ImageFile': 'Win10', + 'ImageName': 'Windows 10 Home', + 'Family': '10', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'ImageFile': 'Win10', + 'ImageName': 'Windows 10 Pro', + 'Family': '10'}, ] actions = [ {'Name': 'Main Menu', 'Letter': 'M'}, diff --git a/Scripts/menu.py b/Scripts/menu.py index e5adc729..3c58bd93 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -64,7 +64,7 @@ def menu_backup_imaging(): # List (and update) partition details for selected drive os.system('cls') - print('Details for selected drive:\n') + print('Create Backup - Details:\n') print(' Drive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk)) clobber_risk = 0 width=len(str(len(disk['Partitions']))) @@ -84,7 +84,8 @@ def menu_backup_imaging(): par['ImagePath'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket, **dest) else: par['ImagePath'] = '{Letter}:\\{ticket}'.format(ticket=ticket, **dest) - par['ImageFile'] = '{Number}_{ImageName}.wim'.format(**par) + par['ImageFile'] = '{Number}_{ImageName}'.format(**par) + par['ImageFile'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['ImageFile'])) # Check for existing backups par['ImageExists'] = False @@ -108,9 +109,9 @@ def menu_backup_imaging(): elif len(bad_parts) == 1: print_warning(' * Unable to backup this partition') if clobber_risk > 1: - print_info(' + These partitions already have backup images on {TrueName}:'.format(**dest)) + print_info(' + These partitions already have backup images on {Display Name}:'.format(**dest)) elif clobber_risk == 1: - print_info(' + This partition already has a backup image on {TrueName}:'.format(**dest)) + print_info(' + This partition already has a backup image on {Display Name}:'.format(**dest)) if clobber_risk + len(bad_parts) > 1: print_warning('\nIf you continue the partitions marked above will NOT be backed up.\n') if clobber_risk + len(bad_parts) == 1: @@ -131,7 +132,7 @@ def menu_backup_imaging(): if par['Number'] in bad_parts: print_warning('Skipped.') else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{ImagePath}\\{ImageFile}" "{ImageName}" "{ImageName}" --check --compress=fast'.format(bin=bin, **par) + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{ImagePath}\\{ImageFile}" "{ImageName}" "{ImageName}" --compress=fast'.format(bin=bin, **par) if par['ImageExists']: print_warning('Skipped.') else: @@ -144,9 +145,29 @@ def menu_backup_imaging(): errors = True par['Error'] = err.stderr.decode().splitlines() + # Verify backup(s) + if len(par) - len(bad_parts) > 1: + print('\n\n Verifying backups\n') + else: + print('\n\n Verifying backup\n') + for par in disk['Partitions']: + if par['Number'] not in bad_parts: + print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) + cmd = '{bin}\\wimlib\\wimlib-imagex verify "{ImagePath}\\{ImageFile}" --nocheck'.format(bin=bin, **par) + if not os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): + print_error('Missing.') + else: + try: + run_program(cmd) + print_success('OK.') + except subprocess.CalledProcessError as err: + print_error('Damaged.') + errors = True + par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + # Print summary if errors: - print_warning('\nErrors were encountered during imaging and are detailed below.') + print_warning('\nErrors were encountered and are detailed below.') for par in [p for p in disk['Partitions'] if 'Error' in p]: print(' Partition {Number} Error:'.format(**par)) for line in par['Error']: @@ -169,8 +190,8 @@ def menu_windows_setup(): abort_to_main_menu('Aborting Windows setup') # Find Windows image - image_file = find_windows_image(selected_windows_version['ImageFile']) - if image_file is None: + image = find_windows_image(selected_windows_version['ImageFile']) + if not any(image): print_error('Failed to find Windows source image for {winver}'.format(winver=selected_windows_version['Name'])) abort_to_main_menu('Aborting Windows setup') @@ -221,7 +242,7 @@ def menu_windows_setup(): abort_to_main_menu('Aborting Windows setup') # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) - remove_volume_letters() + remove_volume_letters(keep=image['Source']) # Format and partition drive if (use_gpt): @@ -232,7 +253,7 @@ def menu_windows_setup(): # Apply Windows image errors = False print(' Applying image...') - cmd = '{bin}\\wimlib\\wimlib-imagex apply "{image_file}" "{ImageName}" W:\\'.format(bin=bin, image_file=image_file, **selected_windows_version) + cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{ImageName}" W:\\ {Glob}'.format(bin=bin, **image, **selected_windows_version) try: run_program(cmd) except subprocess.CalledProcessError: @@ -251,8 +272,8 @@ def menu_windows_setup(): try: run_program('W:\\Windows\\System32\\reagentc /setreimage /path T:\\Recovery\\WindowsRE /target W:\\Windows') except subprocess.CalledProcessError: - errors = True - print_error('Failed to setup WindowsRE files.') + # errors = True # Changed to warning. + print_warning('Failed to setup WindowsRE files.') # Print summary if errors: diff --git a/WK/amd64/conemu-maximus5/ConEmu.xml b/WK/amd64/conemu-maximus5/ConEmu.xml index 4d75ab86..9752d747 100644 --- a/WK/amd64/conemu-maximus5/ConEmu.xml +++ b/WK/amd64/conemu-maximus5/ConEmu.xml @@ -1,7 +1,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -123,7 +123,7 @@ - + @@ -134,10 +134,10 @@ - + - + @@ -483,9 +483,9 @@ - + - + @@ -494,7 +494,7 @@ - + @@ -503,7 +503,7 @@ - + @@ -512,7 +512,7 @@ - + @@ -523,11 +523,11 @@ - + - - + + @@ -628,7 +628,7 @@ - + diff --git a/WK/x86/conemu-maximus5/ConEmu.xml b/WK/x86/conemu-maximus5/ConEmu.xml index 4d75ab86..a54f9ab5 100644 --- a/WK/x86/conemu-maximus5/ConEmu.xml +++ b/WK/x86/conemu-maximus5/ConEmu.xml @@ -112,7 +112,7 @@ - + From 93250b22ed1e55ce5133958dfcaf8b2e2444cee8 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:07:03 -0800 Subject: [PATCH 10/85] 2016-10: Retroactive Updates * HWiNFO added * Q-Dir added * Perhaps a replacement for Explorer++ --- Scripts/menu.py | 6 +- WK/amd64/CPU-Z/cpuz.ini | 2 +- WK/amd64/HWMonitor/hwmonitorw.ini | 2 +- WK/amd64/HWiNFO/HWiNFO64.INI | 210 ++++++++++ WK/amd64/Q-Dir/Q-Dir.ini | 59 +++ WK/x86/CPU-Z/cpuz.ini | 2 +- WK/x86/HWMonitor/hwmonitorw.ini | 3 +- WK/x86/HWiNFO/HWiNFO32.INI | 671 ++++++++++++++++++++++++++++++ WK/x86/Q-Dir/Q-Dir.ini | 59 +++ 9 files changed, 1007 insertions(+), 7 deletions(-) create mode 100644 WK/amd64/HWiNFO/HWiNFO64.INI create mode 100644 WK/amd64/Q-Dir/Q-Dir.ini create mode 100644 WK/x86/HWiNFO/HWiNFO32.INI create mode 100644 WK/x86/Q-Dir/Q-Dir.ini diff --git a/Scripts/menu.py b/Scripts/menu.py index 3c58bd93..e781c14c 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -289,13 +289,15 @@ def menu_tools(): {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, {'Name': 'CPU-Z', 'Folder': 'CPU-Z', 'File': 'cpuz.exe'}, {'Name': 'Explorer++', 'Folder': 'Explorer++', 'File': 'Explorer++.exe'}, - {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/exclude="desktop.ini;Thumbs.db"']}, + {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, + {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, {'Name': 'HW Monitor', 'Folder': 'HWMonitor', 'File': 'HWMonitor.exe'}, {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, {'Name': 'Notepad2', 'Folder': 'Notepad2', 'File': 'Notepad2-Mod.exe'}, {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, {'Name': 'Prime95', 'Folder': 'Prime95', 'File': 'prime95.exe'}, - {'Name': 'ProduKey', 'Folder': 'ProduKey', 'File': 'ProduKey.exe', 'Args': ['/external']}, + {'Name': 'ProduKey', 'Folder': 'ProduKey', 'File': 'ProduKey.exe', 'Args': ['/external', '/ExtractEdition:1']}, + {'Name': 'Q-Dir', 'Folder': 'Q-Dir', 'File': 'Q-Dir.exe'}, {'Name': 'TestDisk', 'Folder': 'TestDisk', 'File': 'testdisk_win.exe', 'Args': ['-new_console:n']}, ] actions = [ diff --git a/WK/amd64/CPU-Z/cpuz.ini b/WK/amd64/CPU-Z/cpuz.ini index fa6114f0..e10ce749 100644 --- a/WK/amd64/CPU-Z/cpuz.ini +++ b/WK/amd64/CPU-Z/cpuz.ini @@ -1,5 +1,5 @@ [CPU-Z] -VERSION=1.7.5.0 +VERSION=1.7.7.0 TextFontName= TextFontSize=14 TextFontColor=000080 diff --git a/WK/amd64/HWMonitor/hwmonitorw.ini b/WK/amd64/HWMonitor/hwmonitorw.ini index 0bfb23e7..85f41603 100644 --- a/WK/amd64/HWMonitor/hwmonitorw.ini +++ b/WK/amd64/HWMonitor/hwmonitorw.ini @@ -1,5 +1,5 @@ [HWMonitor] -VERSION=1.2.8.0 +VERSION=1.2.9.0 USE_ACPI=1 USE_SMBUS=1 USE_SMART=1 diff --git a/WK/amd64/HWiNFO/HWiNFO64.INI b/WK/amd64/HWiNFO/HWiNFO64.INI new file mode 100644 index 00000000..700c5ff6 --- /dev/null +++ b/WK/amd64/HWiNFO/HWiNFO64.INI @@ -0,0 +1,210 @@ + +[LogfileSettings] +COMP=1 +COMP_SP=1 +COMP_Name=1 +COMP_Os=1 +COMP_User=0 +CPU=1 +CPU_Name=1 +CPU_ID=1 +CPU_Vendor=1 +CPU_Stepping=1 +CPU_Type=1 +CPU_BrandID=1 +CPU_PN=1 +CPU_Clock=1 +CPU_MaxFreq=1 +CPU_CacheL1=1 +CPU_CacheL2=1 +CPU_TLB_I=1 +CPU_TLB_D=1 +CPU_Features=1 +CPU_PIROM=1 +MEM=1 +MEM_TotalSize=1 +MEM_Timing=1 +MEM_Row=1 +MEM_Row_Size=1 +MEM_Row_Type=1 +MEM_Row_Speed=1 +MEM_Row_Model=1 +MEM_Row_ECC=1 +MEM_Row_Date=1 +MEM_Row_SN=1 +MEM_Row_Cfg=1 +MEM_Row_Latency=1 +MEM_Row_Features=1 +MEM_Row_iFeatures=1 +BUS=1 +BUS_PCI=1 +BUS_PCI_DevName=1 +BUS_PCI_DevNumber=1 +BUS_PCI_Resources=1 +BUS_PCI_Features=1 +BUS_PCI_DevSpecific=1 +BUS_PCIX_Features=1 +BUS_PCIe_Features=1 +BUS_PCI_DRV_INFO=1 +BUS_EISA=1 +DMI=1 +DMI_0=1 +DMI_1=1 +DMI_2=1 +DMI_3=1 +DMI_4=1 +DMI_5=1 +DMI_6=1 +DMI_7=1 +DMI_8=1 +DMI_9=1 +DMI_10=1 +DMI_11=1 +DMI_12=1 +DMI_13=1 +DMI_14=1 +DMI_15=1 +DMI_16=1 +DMI_17=1 +DMI_18=1 +DMI_19=1 +DMI_20=1 +DMI_21=1 +DMI_22=1 +DMI_23=1 +DMI_24=1 +DMI_25=1 +DMI_26=1 +DMI_27=1 +DMI_28=1 +DMI_29=1 +DMI_30=1 +DMI_31=1 +DMI_32=1 +DMI_33=1 +DMI_34=1 +DMI_35=1 +DMI_36=1 +DMI_37=1 +DMI_38=1 +DMI_39=1 +DMI_129=1 +DMI_130=1 +DMI_131=1 +VIDEO=1 +VIDEO_Chipset=1 +VIDEO_Memory=1 +VIDEO_Card=1 +VIDEO_Bus=1 +VIDEO_RAMDAC=1 +VIDEO_BIOSver=1 +VIDEO_Clock=1 +VIDEO_HWID=1 +VIDEO_DRV_INFO=1 +VIDEO_DirectX=1 +MON=1 +MON_Name=1 +MON_SN=1 +MON_Date=1 +MON_Dimensions=1 +MON_DisplayType=1 +MON_InputSignal=1 +MON_Gamma=1 +MON_DPMSinput=1 +MON_DPMSmodes=1 +MOBO=1 +MOBO_Model=1 +MOBO_Chipset=1 +MOBO_CompName=1 +MOBO_MachineType=1 +MOBO_Slots=1 +MOBO_BIOS_Manuf=1 +MOBO_BIOS_Date=1 +MOBO_PNP_Devs=1 +MOBO_PNP_Nodes=1 +MOBO_ACPI_Devs=1 +MOBO_ACPI_Enum=1 +DRIVE=1 +DRIVE_IDE=1 +DRIVE_IDE_Ctrller=1 +DRIVE_IDE_Channel=1 +DRIVE_IDE_Model=1 +DRIVE_IDE_Rev=1 +DRIVE_IDE_SN=1 +DRIVE_IDE_Capacity=1 +DRIVE_IDE_Geometry=1 +DRIVE_IDE_Cache=1 +DRIVE_IDE_Xfer=1 +DRIVE_IDE_BasicCapab=1 +DRIVE_IDE_ATA2Capab=1 +DRIVE_IDE_SMART=1 +DRIVE_SCSI=1 +DRIVE_SCSI_ID=1 +DRIVE_SCSI_Desc=1 +DRIVE_SCSI_Class=1 +DRIVE_Floppy=1 +NETWORK=1 +NETWORK_HWID=1 +NETWORK_DRV_INFO=1 +AUDIO=1 +AUDIO_DRV_INFO=1 +AUDIO_HWID=1 +PORTS=1 +BUS_USB=1 +BUS_USB_DRV_INFO=1 +BATTERY=1 +SENSORS=1 + +[Settings] +HighestIdeAddress=0 +AcpiEnum=0 +SWSMI=1 +DebugMode=0 +SMBus=1 +TempScale=C +AC97CodecID=1 +SkipProblematicPciDev=0 +GPUI2C=1 +LPC=1 +DefReportType=5 +TPM=0 +PCIdirect=1 +OpenSystemSummary=0 +RememberPreferences=1 +LargeFonts=0 +OpenSensors=1 +MinimalizeMainWnd=0 +MinimalizeSensors=0 +PersistentDriver=0 +UseHPET=1 +AutoUpdate=0 +GPUI2CNVAPI=1 +GPUI2CADL=0 +SensorsOnly=1 +AcpiEval=1 +CpuClkFromBusClk=1 +BusClkPolling=1 +SMBusAdrExclude=11111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +GPUI2CBusExclude=00000000 +SensorsSM=1 +IoctlKernel=0 +SummaryOnly=0 +WakeGPUs=1 +KeepTheme=0 +FlushBuffers=1 +iMEsupport=1 +GPUI2Ccaching=1 +CSMI_SAS_Support=1 +DebugDirect=1 +MinimalizeSensorsClose=0 +WakeGPUsExt=0 +PollSleepingGPUs=0 +ShowWelcomeAndProgress=1 +EnablePchTherm=0 +ReorderGPUs=1 +NvmlSupport=1 +DecimalSeparator=. +ThousandsSeparator=, +CsvSeparator=, +MinimizeGraphs=1 +TextButtons=0 diff --git a/WK/amd64/Q-Dir/Q-Dir.ini b/WK/amd64/Q-Dir/Q-Dir.ini new file mode 100644 index 00000000..a9bdcb74 --- /dev/null +++ b/WK/amd64/Q-Dir/Q-Dir.ini @@ -0,0 +1,59 @@ +[Start] +m_lang_id=1 +QDir_Id=0 +useColorStart=1 +Als=12 +designe_mode=2 +WinRC=-1;-29;1441;873 +showCmd=1 +StartCrash=0 +default_tab= +Max=3 +show_ext_in_type=1 +title_info=1 +adresbar_style=1 +useTreeColor=1 +useColor=1 +[Favoriten] +Ordner=.\Favoriten\ +[Q] +Link=.\Favoriten\Quick-Link\ +[Q-Dir] +Lizenz=1 + + + + + +[Vorschau] +Filter=*.avi;*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.mp*;*.pdf;*.png;*.wm*; +[Filter2] +0=#Hidden=1=-1=1=1=-1=0 +1=*.zip;*.rar;*.gz;*.7z;=1=00AA00=-1=1=-1=0 +2=*.mp*;*.avi;*.wma;=1=DD0058=-1=1=-1=0 +3=#DIR=1=008800=-1=1=-1=0 +4=*.jpg;*.jpeg;*.png,*.gif;*.bmp;*.ico=1=BB00BB=-1=1=-1=0 +5=*.html;*.htm;*.url=1=456789=-1=1=-1=0 +6=*.pl;*.cgi;*.php;*.pdf;*.doc;*.rtf;*.xls=1=BB8844=-1=1=-1=0 +7=*.cpp;*.hpp;*.h=1=DD0058=-1=1=-1=0 +8=*.exe;*.dll;*.bat=1=FF0000=-1=1=-1=0 +9=*=1=0000BB=-1=1=-1=0 +10=#BG=1=-1=-1=1=-1=0 +11=#BG-A=1=-1=-1=1=-1=0 +[Ordner] +Filter= +[Column_OS_6.1_Ploder1] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +Spatlen_291=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%00%00%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%EE%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0E%00%00%00%69%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%91%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0C%00%00%00%46%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%00%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-563719693|772 +[Column_OS_6.1_Ploder2] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder3] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder4] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Programs_State] +Disable=0 +[Quick-Links] +WK=%systemdrive%/WK +[Options] +Start=0 diff --git a/WK/x86/CPU-Z/cpuz.ini b/WK/x86/CPU-Z/cpuz.ini index fa6114f0..e10ce749 100644 --- a/WK/x86/CPU-Z/cpuz.ini +++ b/WK/x86/CPU-Z/cpuz.ini @@ -1,5 +1,5 @@ [CPU-Z] -VERSION=1.7.5.0 +VERSION=1.7.7.0 TextFontName= TextFontSize=14 TextFontColor=000080 diff --git a/WK/x86/HWMonitor/hwmonitorw.ini b/WK/x86/HWMonitor/hwmonitorw.ini index e3978b4e..85f41603 100644 --- a/WK/x86/HWMonitor/hwmonitorw.ini +++ b/WK/x86/HWMonitor/hwmonitorw.ini @@ -1,8 +1,7 @@ [HWMonitor] -VERSION=1.2.8.0 +VERSION=1.2.9.0 USE_ACPI=1 USE_SMBUS=1 USE_SMART=1 USE_DISPLAY=1 -CPU_0_TJMAX=100.0 UPDATES=0 diff --git a/WK/x86/HWiNFO/HWiNFO32.INI b/WK/x86/HWiNFO/HWiNFO32.INI new file mode 100644 index 00000000..ace15fef --- /dev/null +++ b/WK/x86/HWiNFO/HWiNFO32.INI @@ -0,0 +1,671 @@ +[Benchmark_CPU] +Intel Pentium-100=707 +Intel Pentium-120/Notebook=835 +Intel Pentium-166/QDI=1380 +Cyrix 6x86MX-PR300=1411 +AMD-K6-166/QDI=1482 +Intel Pentium MMX-200=1484 +Cyrix MII-PR333=1518 +Intel Mobile Pentium MMX-233=1642 +Intel Pentium Pro-166 Dual CPU=1679 +AMD-K6-200/DTK=1777 +AMD-K6-200/QDI=1778 +Intel Pentium Pro-200=1944 +AMD-K6-233/DTK=2067 +Intel P2-233/Siemens=2350 +VIA Cyrix III 533/133=2362 +Intel Celeron-266/BXmaster=2586 +Intel P2-266/Siemens=2603 +AMD-K6-2-300/PCChips M577=2655 +Intel Celeron 300=2883 +Intel Celeron-300/PCChips=2922 +AMD-K6-2-350/FIC=3092 +AMD-K6-III-400=3524 +AMD-K6-III-400/FIC VA-503A=3557 +Intel Celeron-366/BXmaster=3718 +Intel P2-400/Siemens=3886 +Intel Celeron-400/BXmaster=3890 +AMD-K6-2-450/FIC=3964 +AMD-K6-III-448/FIC VA-503A=3975 +AMD-K6-III-450=3978 +Intel Mobile P2-400/Scenic=4047 +Intel Celeron-413/BXmaster=4175 +Intel Celeron-433=4219 +Intel P3-450/CC820=4363 +Intel P3-450/Siemens=4372 +Intel Celeron-450=4555 +Intel Celeron-300A@467=4686 +Intel Celeron-466/BXmaster=4789 +Intel P3-500/GA-6BXDS=5021 +Intel Pentium III Xeon-550=5299 +Intel Celeron-525/BXmaster=5314 +Intel P3-550/Siemens=5543 +Intel Celeron-550/BXmaster=5579 +Intel Celeron-575/BXmaster=5845 +Intel Celeron-616/BXmaster=5999 +Intel P3-617/GA-BX2000=6241 +AMD Athlon-600/AMD-750=6303 +AMD Duron-600/KT133=6436 +Intel P3-650/BX=6497 +AMD Athlon-650/KX133=6749 +AMD Duron-650/KT133=6971 +Intel P3-700/BX=7013 +AMD Athlon-700/KX133=7185 +AMD Duron-700/KT133=7507 +Intel Celeron-815/BXmaster=7985 +AMD Athlon-750/KT133=8085 +AMD Athlon-800/AMD-750=8286 +AMD Duron-800/KT133=8580 +Intel P3-650@870/BX=8675 +AMD Duron-850/KT133=9120 +Intel P3-650@917/BX=9175 +AMD Duron-900/KT133=9654 +AMD Duron-928 (9x103)=9952 +Intel Celeron-566@1010=10115 +VIA Antaur-1000=6108 +VIA C3-1333=7601 +AMD Duron-950/KT133=10190 +AMD Athlon-1000/KT133=10734 +AMD Athlon-1200/KT133=12949 +AMD Athlon XP 1500+/KT133=14297 +AMD Athlon XP 2000+/KT133A=17691 +AMD Athlon XP 2200+/KT133A=19490 +AMD Athlon XP-M 2500+/KM400=19590 +AMD Athlon XP-M 3000+/SiS748=23391 +Intel P3-1000/i815=10381 +Intel P4-1600=6636 +Intel P4-1800=7445 +Intel P4-2000=8272 +Intel P4-2500=11051 +Intel Pentium-M ULV-1000=10515 +Intel Pentium-M-1300=13590 +Intel Pentium-M-1600=16856 +Intel Pentium-M 735=16958 +Intel Pentium-M 755=20008 +Intel Pentium-M 770=21163 +Intel P4-2800(noHT)/i875P=12399 +Intel P4-3066(noHT)/i845PE=13479 +Intel P4-3000E(noHT)/i915P=22136 +Intel P4-3000 530 (HT)=34013 +Intel P4-3200E(noHT)/i875P=23446 +Intel P4-3600E(noHT)/i925X=26424 +Intel Xeon-3800(HT)=55028 +AMD Athlon64 3200+=23814 +AMD Athlon64 3800+=28731 +AMD Athlon64 FX-53=28727 +AMD Opteron 248=25920 +AMD Turion64 ML-34+=18520 +AMD Turion64 X2 TL-60=47697 +AMD Athlon 64 X2 4400+=52867 +Intel Core Duo T2600 (1core)=20293 +Intel Core Duo T2600 (2core)=40849 +Intel Core 2 Duo E6700=51765 +Intel Core 2 Duo T7400=53238 +Transmeta Crusoe TM5800-1000=6382 +2xIntel Xeon 5150/5000P=131832 +4xIntel Xeon MP 7040=180052 +Intel Core 2 Extreme QX6700=129908 +AMD Phenom 9500=103687 +Intel Atom 230=15438 +Intel Core i5-520M=94834 +Intel Core i7-860=180329 +Intel Core i7-820QM=123279 +Intel Core i7-980X=347501 +Intel Core i5-2520M=111448 +Intel Core i7-3820=265424 + +[Benchmark_FPU] +Intel Pentium-100=1109 +VIA Cyrix III 533/133=1327 +Intel Pentium 120/Notebook=1350 +Intel Pentium Pro-166 Dual CPU=1663 +Intel Pentium Pro-200=1934 +Cyrix 6x86MX-PR300=2304 +Intel P2-233/Siemens=2323 +AMD-K6-166/QDI=2533 +Cyrix MII-PR333=2585 +Intel Celeron-266/BXmaster=2630 +Intel Mobile Pentium MMX-233=2647 +Intel P2-266/Siemens=2662 +Intel Celeron-300=2862 +AMD-K6-200/DTK=2999 +AMD-K6-200/QDI=3041 +AMD-K6-233/DTK=3492 +Intel Celeron-366/BXmaster=3650 +Intel P2-400/Siemens=3968 +Intel Celeron-400/BXmaster=3972 +Intel Mobile P2-400/Scenic=3973 +Intel Celeron-413/BXmaster=4097 +Intel Celeron-433=4304 +Intel P3-450/CC820=4444 +Intel P3-450/Siemens=4452 +Intel Celeron-450=4472 +Intel Celeron-300A@467=4599 +AMD-K6-2-300/PCChips M577=4605 +Intel Celeron-466/BXmaster=4628 +Intel P3-500/GA-6BXDS=4958 +Intel Celeron-525/BXmaster=5215 +AMD-K6-2-350/FIC=5368 +Intel Pentium III Xeon-550=5417 +Intel P3-550/Siemens=5440 +Intel Celeron-550/BXmaster=5477 +Intel Celeron-575/BXmaster=5738 +Intel Celeron-616/BXmaster=5897 +Intel P3-617/GA-BX2000=6114 +AMD-K6-III-400/FIC VA-503A=6166 +AMD-K6-III-400=6169 +Intel P3-650/BX=6446 +AMD-K6-2-450/FIC=6876 +AMD-K6-III-448/FIC VA-503A=6893 +AMD-K6-III-450=6895 +Intel P3-700/BX=6942 +Intel Celeron-815/BXmaster=7799 +Intel P3-650@870/BX=8614 +Intel P3-650@917/BX=9080 +VIA C3-1333=3160 +AMD Duron-600/KT133=9132 +AMD Athlon-600/AMD-750=9231 +AMD Athlon-650/KX133=9888 +Intel Celeron-566@1010=9977 +AMD Athlon-700/KX133=10527 +AMD Athlon-750/KT133=11457 +AMD Athlon-800/AMD-750=12149 +AMD Duron-850/KT133=12954 +AMD Duron-900/KT133=13712 +AMD Duron-928 (9x103)=14150 +AMD Duron-950/KT133=14479 +AMD Athlon-1000/KT133=15252 +AMD Athlon-1200/KT133=18378 +AMD Athlon XP 1500+/KT133=20757 +AMD Athlon XP 1800+=23375 +AMD Athlon XP 2000+/KT133A=25693 +AMD Athlon XP 2200+/KT133A=28296 +AMD Athlon XP-M 2500+/KM400=28877 +AMD Athlon XP-M 3000+/SiS748=34104 +Intel P3-1000/i815=9813 +Intel P4-1600=3282 +Intel P4-1800=3833 +Intel P4-2000=4256 +Intel P4-2500=6020 +Intel Pentium-M ULV-1000=8547 +Intel Pentium-M-1300=11089 +Intel Pentium-M-1600=13614 +Intel Pentium-M 735=14211 +Intel Pentium-M 755=16772 +Intel Pentium-M 770=17807 +Intel P4-2800(noHT)/i875P=6799 +Intel P4-3066(noHT)/i845PE=7396 +Intel P4-3000 530 (HT)=9220 +Intel P4-3200E(noHT)/i875P=6578 +Intel P4-3600E(noHT)/i925X=8163 +Intel Xeon-3800(HT)=17241 +AMD Athlon64 3200+=31194 +AMD Athlon64 3800+=37379 +AMD Athlon64 FX-53=37426 +AMD Opteron 248=34115 +AMD Turion64 ML-34+=28056 +AMD Turion64 X2 TL-60=62143 +AMD Athlon 64 X2 4400+=68974 +Intel Core Duo T2600 (1core)=16967 +Intel Core Duo T2600 (2core)=34039 +Intel Core 2 Duo E6600=36031 +Intel Core 2 Duo E6700=40075 +Intel Core 2 Duo T7400=32659 +Transmeta Crusoe TM5800-1000=4251 +2xIntel Xeon 5150/5000P=80725 +4xIntel Xeon MP 7040=54379 +Intel Core 2 Extreme QX6700=80338 +AMD Phenom 9500=133430 +Intel Atom 230=10769 +Intel Core i5-520M=60634 +Intel Core i7-860=131820 +Intel Core i7-820QM=90751 +Intel Core i7-980X=215620 +Intel Core i5-2520M=55354 +Intel Core i7-3820=130252 + +[Benchmark_MMX] +AMD-K6-166/QDI=909 +AMD-K6-200/QDI=1070 +Intel P2-266/440LX=1339 +VIA Cyrix III 533/133=1815 +Intel Pentium MMX-200=2041 +Intel Mobile Pentium MMX-233=2363 +Intel P2-233/440BX=2390 +Intel Celeron-300=2931 +Intel Celeron-366=3742 +Intel Celeron-450=4602 +Intel Celeron-300A@467=4737 +Intel P3-500/GA-6BXDS=5009 +AMD Duron-600/KT133=5454 +Intel P3-550/Siemens=5513 +AMD Athlon-650/KX133=5906 +AMD Athlon-700/Abit KA7=6356 +Intel P3-650/BX=6490 +AMD Duron-750/KT133=6823 +AMD Athlon-750/KT133=6846 +Intel P3-700/BX=7025 +AMD Duron-800/KT133=7277 +AMD Duron-850/KT133=7738 +AMD Duron-900/KT133=8192 +AMD Duron-928 (9x103)=8448 +AMD Duron-950/KT133=8645 +Intel P3-650@870/BX=8706 +AMD Athlon-1000/KT133=9110 +Intel P3-650@917/BX=9173 +Intel Celeron-566@1010=10080 +VIA C3-1333=6063 +AMD Athlon-1200/KT133=10998 +AMD Athlon XP 1500+/KT133=12125 +AMD Athlon XP 1800+=13642 +AMD Athlon XP 2000+/KT133A=15013 +AMD Athlon XP 2200+/KT133A=16516 +AMD Athlon XP-M 2500+/KM400=16858 +AMD Athlon XP-M 3000+/SiS748=20040 +Intel P3-1000=9903 +Intel P4-1600=14468 +Intel P4-1800=16319 +Intel P4-2000=18140 +Intel P4-2500=22681 +Intel Pentium-M ULV-1000=9937 +Intel Pentium-M-1300=12865 +Intel Pentium-M-1600=15835 +Intel Pentium-M 735=16839 +Intel Pentium-M 755=19869 +Intel Pentium-M 770=21149 +Intel P4-2800(noHT)/i875P=24478 +Intel P4-3066(noHT)/i845PE=26437 +Intel P4-3000 530 (HT)=27352 +Intel P4-3200E(noHT)/i875P=22592 +Intel P4-3600E(noHT)/i925X=25314 +Intel Xeon-3800(HT)=53268 +AMD Athlon64 3200+=18228 +AMD Athlon64 3800+=21859 +AMD Athlon64 FX-53=21856 +AMD Opteron 248=19926 +AMD Turion64 ML-34+=16403 +AMD Turion64 X2 TL-60=36363 +AMD Athlon 64 X2 4400+=40282 +Intel Core Duo T2600 (1core)=21423 +Intel Core Duo T2600 (2core)=42912 +Intel Core 2 Duo E6600=74154 +Intel Core 2 Duo E6700=82312 +Intel Core 2 Duo T7400=67321 +Transmeta Crusoe TM5800-1000=5272 +2xIntel Xeon 5150/5000P=51186 +4xIntel Xeon MP 7040=83086 +Intel Core 2 Extreme QX6700=165067 +AMD Phenom 9500=80202 +Intel Atom 230=14545 +Intel Core i5-520M=80822 +Intel Core i7-860=171336 +Intel Core i7-820QM=115063 +Intel Core i7-980X=261051 +Intel Core i5-2520M=81444 +Intel Core i7-3820=160178 + +[Benchmark_Memory] +Intel Pentium-100/FPM=69 +Intel Pentium Pro-166 Dual CPU=78 +AMD-K6-166/QDI/EDO=85 +Intel Pentium MMX-200/EDO=92 +AMD-K6-200/QDI/EDO=93 +Intel Pentium MMX-233/PC66=101 +Intel P2-233/440BX/PC66=111 +VIA Cyrix III 533/133=114 +Intel P2-266/440BX/PC66=117 +AMD-K6-III-400=135 +Intel Celeron-366/PC66=163 +AMD Duron-600/KT133=173 +AMD Athlon-700/KX133/PC133=202 +AMD Athlon-650/KX133=205 +Intel P3-500/GA-6BXDS/PC100=209 +Intel P3-550/Siemens/PC100=215 +Intel Celeron-300A@467/PC66=209 +Intel Celeron-300/PC66=146 +Intel P3-650/BX/PC100=238 +Intel P3-700/BX/PC100=211 +AMD Athlon-750/KT133/PC133=214 +AMD Duron-750/KT133=263 +Intel Celeron-566@1010=273 +VIA C3-1333/CN400=223 +AMD Duron-950/KT133=275 +AMD Duron-928 (9x103)/KT133=292 +AMD Duron-1100/SiS745/DDR333=477 +AMD Athlon XP-M 2500+/DDR333=548 +Intel P3-650@917/FSB140=310 +Intel P3-1000/PC133=218 +Intel P4-1600/i850=1115 +Intel P4-2000/i850/PC800=1245 +Intel P4-1800/i845G/DDR266=867 +Intel P4-2500/i845/DDR266=757 +Intel Pentium-M-1600/DDR266=830 +Intel Pentium-M 735/855PM/DDR400=971 +Intel P4-3066/i845PE/DDR266=1028 +Intel P4-2800/i875P/2Ch/DDR400=2056 +Intel P4-3200E/i875P/2Ch/DDR400=2342 +Intel P4-3600E/i915P/DDR2-533=2556 +Intel P4-3600E/i925X/DDR2-533=2844 +Intel Xeon-3800/E7525/DDR2-400=1635 +AMD Athlon64 3200+/1Ch/DDR400=1266 +AMD Athlon64 3800+/2Ch/DDR400=2375 +AMD Athlon64 FX-53/2Ch/DDR400=2166 +AMD Opteron 248/DDR266=947 +AMD Turion64 ML-34+=1071 +Intel Core 2 Duo E6700/DDR2-800=2894 +Transmeta Crusoe TM5800-1000=337 +2xIntel Xeon 5150/5000P/DDR2-667F=2919 +4xIntel Xeon MP 7040=1721 +AMD Phenom 9500=1795 +Intel Atom 230/945/DDR2-800=1682 +Intel Core i5-520M=5235 +Intel Core i7-860/DDR3-667/2CH=6506 +Intel Core i7-820QM=5424 +Intel Core i7-980X=9343 +Intel Core i7-3820/DDR3-1600/4CH=13366 + +[Benchmark_Disk_ReadBurst] +Fujitsu MPB3043ATU E/PIO=4.03 +Seagate ST38410A/PIO=4.33 +Maxtor 91021U2/PIO=4.61 +Maxtor 92041U4/PIO=4.82 +Quantum Fireball_TM2110S300X=6.83 +SEAGATE ST51080N=7.92 +Seagate ST31277A=8,37 +IBM DCAS-32160 S65A=8.65 +QUANTUM FIREBALL ST3.2A/PIO=14.74 +Seagate ST39102LW Cheetah=30.05 +IBM DJNA-370910/UDMA66=15.27 +Seagate ST34321A/UDMA33=21.03 +Seagate ST38421A=23.82 +Seagate ST34310A=23.88 +QUANTUM FIREBALL SE2.1A=26.43 +Maxtor 91021U2/UDMA33=29.13 +Maxtor 54098U8/UDMA33=29.5 +IBM DTTA-350430=29.7 +IBM-DPTA-371360=29.86 +Seagate ST320420A=47.3 +IBM-DJNA-371350=27.87 +IBM-DTLA-307030/ATA100=82.22 +SEAGATE Cheetah X15/RAID=137.08 +IBM Deskstar 60GXP/ATA100=81.98 +MAXTOR 4K020H1/ATA100=84.58 +Seagate ST317221A/UDMA66=42.03 +Maxtor 6E040L0=79.36 +Seagate ST380021A/ATA100=73.11 +HITACHI DK23EA-40=80.04 +WDC WD800JB/ATA100=85.71 +TOSHIBA MK4019GAX=83.60 +Maxtor MaxLine III SATA+NCQ=119.96 +ST312002 6AS=106.61 +Maxtor Atlas 10K5 73SCA=145.86 +WDC WD3200YS-01PGB0=167.33 +Hitachi HTE726040M9AT00=84.61 +Seagate ST3160827AS=120.88 +WDC WD5000AADS-00S9B0=122.87 +Hitachi HTS545032B9A=161.10 +Seagate ST1000DM003-9YN1=282.43 + +[Benchmark_Disk_ReadRandom] +Hitachi HTE726040M9AT00=22.82 +Maxtor Atlas 10K5 73SCA=31.61 +Seagate ST3160827AS=32.26 +FUJITSU MHV2080BH=17.79 +TOSHIBA MK8034GSX=18.12 +ST916082 1AS=22.27 +WDC WD5000AADS-00S9B0=24.58 +Hitachi HTS545032B9A=24.72 +Seagate ST1000DM003-9YN1=37.09 + +[Benchmark_Disk_RandomAccess] +SEAGATE ST51080N=20.96 +Quantum Fireball_TM2110S300X=20.74 +Seagate ST34321A/UDMA33=17.21 +Seagate ST38410A/PIO=17.17 +Seagate ST31277A=16.75 +Fujitsu MPB3043ATU E=16.18 +IBM DTTA-350430=16.5 +IBM DCAS-32160 S65A=15.95 +Maxtor 92041U4/PIO=15.81 +Seagate ST34310A=15.56 +Maxtor 91021U2/PIO=15.66 +Seagate ST38421A=15.71 +QUANTUM FIREBALL ST3.2A=15.50 +QUANTUM FIREBALL SE2.1A=14.94 +Maxtor 54098U8/UDMA33=13.77 +Seagate ST320420A=12.57 +IBM DJNA-370910/UDMA66=12.10 +Seagate ST39102LW Cheetah=8.78 +IBM-DPTA-371360=13.37 +IBM-DJNA-371350=13.38 +IBM-DTLA-307030/ATA100=12.44 +IBM-DTLA-307030/ATA100+AAM=22.34 +SEAGATE Cheetah X15/RAID=5.65 +IBM Deskstar 60GXP=12.70 +MAXTOR 4K020H1/ATA100=19.12 +Seagate ST317221A/UDMA66=16.60 +Maxtor 6E040L0=14.52 +Seagate ST380021A/ATA100=14.58 +HITACHI DK23EA-40=19.40 +WDC WD800JB/ATA100=13.61 +TOSHIBA MK4019GAX=18.61 +Maxtor MaxLine III SATA+NCQ=15.82 +ST312002 6AS=12.51 +Maxtor Atlas 10K5 73SCA=10.16 +WDC WD3200YS-01PGB0=13.16 +Hitachi HTE726040M9AT00=12.90 +Seagate ST3160827AS=11.65 +Seagate ST380215A=14.82 +WDC WD5000AADS-00S9B0=17.37 +Hitachi HTS545032B9A=22.16 +Seagate ST1000DM003-9YN1=15.53 + +[LogfileSettings] +COMP=1 +COMP_SP=1 +COMP_Name=1 +COMP_Os=1 +COMP_User=0 +CPU=1 +CPU_Name=1 +CPU_ID=1 +CPU_Vendor=1 +CPU_Stepping=1 +CPU_Type=1 +CPU_BrandID=1 +CPU_PN=1 +CPU_Clock=1 +CPU_MaxFreq=1 +CPU_CacheL1=1 +CPU_CacheL2=1 +CPU_TLB_I=1 +CPU_TLB_D=1 +CPU_Features=1 +CPU_PIROM=1 +MEM=1 +MEM_TotalSize=1 +MEM_Timing=1 +MEM_Row=1 +MEM_Row_Size=1 +MEM_Row_Type=1 +MEM_Row_Speed=1 +MEM_Row_Model=1 +MEM_Row_ECC=1 +MEM_Row_Date=1 +MEM_Row_SN=1 +MEM_Row_Cfg=1 +MEM_Row_Latency=1 +MEM_Row_Features=1 +MEM_Row_iFeatures=1 +BUS=1 +BUS_PCI=1 +BUS_PCI_DevName=1 +BUS_PCI_DevNumber=1 +BUS_PCI_Resources=1 +BUS_PCI_Features=1 +BUS_PCI_DevSpecific=1 +BUS_PCIX_Features=1 +BUS_PCIe_Features=1 +BUS_PCI_DRV_INFO=1 +BUS_EISA=1 +DMI=1 +DMI_0=1 +DMI_1=1 +DMI_2=1 +DMI_3=1 +DMI_4=1 +DMI_5=1 +DMI_6=1 +DMI_7=1 +DMI_8=1 +DMI_9=1 +DMI_10=1 +DMI_11=1 +DMI_12=1 +DMI_13=1 +DMI_14=1 +DMI_15=1 +DMI_16=1 +DMI_17=1 +DMI_18=1 +DMI_19=1 +DMI_20=1 +DMI_21=1 +DMI_22=1 +DMI_23=1 +DMI_24=1 +DMI_25=1 +DMI_26=1 +DMI_27=1 +DMI_28=1 +DMI_29=1 +DMI_30=1 +DMI_31=1 +DMI_32=1 +DMI_33=1 +DMI_34=1 +DMI_35=1 +DMI_36=1 +DMI_37=1 +DMI_38=1 +DMI_39=1 +DMI_129=1 +DMI_130=1 +DMI_131=1 +VIDEO=1 +VIDEO_Chipset=1 +VIDEO_Memory=1 +VIDEO_Card=1 +VIDEO_Bus=1 +VIDEO_RAMDAC=1 +VIDEO_BIOSver=1 +VIDEO_Clock=1 +VIDEO_HWID=1 +VIDEO_DRV_INFO=1 +VIDEO_DirectX=1 +MON=1 +MON_Name=1 +MON_SN=1 +MON_Date=1 +MON_Dimensions=1 +MON_DisplayType=1 +MON_InputSignal=1 +MON_Gamma=1 +MON_DPMSinput=1 +MON_DPMSmodes=1 +MOBO=1 +MOBO_Model=1 +MOBO_Chipset=1 +MOBO_CompName=1 +MOBO_MachineType=1 +MOBO_Slots=1 +MOBO_BIOS_Manuf=1 +MOBO_BIOS_Date=1 +MOBO_PNP_Devs=1 +MOBO_PNP_Nodes=1 +MOBO_ACPI_Devs=1 +MOBO_ACPI_Enum=1 +DRIVE=1 +DRIVE_IDE=1 +DRIVE_IDE_Ctrller=1 +DRIVE_IDE_Channel=1 +DRIVE_IDE_Model=1 +DRIVE_IDE_Rev=1 +DRIVE_IDE_SN=1 +DRIVE_IDE_Capacity=1 +DRIVE_IDE_Geometry=1 +DRIVE_IDE_Cache=1 +DRIVE_IDE_Xfer=1 +DRIVE_IDE_BasicCapab=1 +DRIVE_IDE_ATA2Capab=1 +DRIVE_IDE_SMART=1 +DRIVE_SCSI=1 +DRIVE_SCSI_ID=1 +DRIVE_SCSI_Desc=1 +DRIVE_SCSI_Class=1 +DRIVE_Floppy=1 +NETWORK=1 +NETWORK_HWID=1 +NETWORK_DRV_INFO=1 +AUDIO=1 +AUDIO_DRV_INFO=1 +AUDIO_HWID=1 +PORTS=1 +BUS_USB=1 +BUS_USB_DRV_INFO=1 +BATTERY=1 +SENSORS=1 + +[Settings] +HighestIdeAddress=0 +AcpiEnum=0 +SWSMI=1 +DebugMode=0 +SMBus=1 +TempScale=C +AC97CodecID=1 +SkipProblematicPciDev=0 +GPUI2C=1 +LPC=1 +DefReportType=5 +TPM=0 +PCIdirect=1 +OpenSystemSummary=0 +RememberPreferences=1 +LargeFonts=0 +OpenSensors=1 +MinimalizeMainWnd=0 +MinimalizeSensors=0 +PersistentDriver=0 +UseHPET=1 +AutoUpdate=0 +GPUI2CNVAPI=1 +GPUI2CADL=0 +SensorsOnly=1 +AcpiEval=1 +CpuClkFromBusClk=1 +BusClkPolling=1 +SMBusAdrExclude=11111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +GPUI2CBusExclude=00000000 +SensorsSM=1 +IoctlKernel=0 +SummaryOnly=0 +WakeGPUs=1 +KeepTheme=0 +FlushBuffers=1 +iMEsupport=1 +GPUI2Ccaching=1 +CSMI_SAS_Support=1 +DebugDirect=1 +MinimalizeSensorsClose=0 +WakeGPUsExt=0 +PollSleepingGPUs=0 +ShowWelcomeAndProgress=1 +EnablePchTherm=0 +ReorderGPUs=1 +NvmlSupport=1 +DecimalSeparator=. +ThousandsSeparator=, +CsvSeparator=, +MinimizeGraphs=1 +TextButtons=0 diff --git a/WK/x86/Q-Dir/Q-Dir.ini b/WK/x86/Q-Dir/Q-Dir.ini new file mode 100644 index 00000000..a9bdcb74 --- /dev/null +++ b/WK/x86/Q-Dir/Q-Dir.ini @@ -0,0 +1,59 @@ +[Start] +m_lang_id=1 +QDir_Id=0 +useColorStart=1 +Als=12 +designe_mode=2 +WinRC=-1;-29;1441;873 +showCmd=1 +StartCrash=0 +default_tab= +Max=3 +show_ext_in_type=1 +title_info=1 +adresbar_style=1 +useTreeColor=1 +useColor=1 +[Favoriten] +Ordner=.\Favoriten\ +[Q] +Link=.\Favoriten\Quick-Link\ +[Q-Dir] +Lizenz=1 + + + + + +[Vorschau] +Filter=*.avi;*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.mp*;*.pdf;*.png;*.wm*; +[Filter2] +0=#Hidden=1=-1=1=1=-1=0 +1=*.zip;*.rar;*.gz;*.7z;=1=00AA00=-1=1=-1=0 +2=*.mp*;*.avi;*.wma;=1=DD0058=-1=1=-1=0 +3=#DIR=1=008800=-1=1=-1=0 +4=*.jpg;*.jpeg;*.png,*.gif;*.bmp;*.ico=1=BB00BB=-1=1=-1=0 +5=*.html;*.htm;*.url=1=456789=-1=1=-1=0 +6=*.pl;*.cgi;*.php;*.pdf;*.doc;*.rtf;*.xls=1=BB8844=-1=1=-1=0 +7=*.cpp;*.hpp;*.h=1=DD0058=-1=1=-1=0 +8=*.exe;*.dll;*.bat=1=FF0000=-1=1=-1=0 +9=*=1=0000BB=-1=1=-1=0 +10=#BG=1=-1=-1=1=-1=0 +11=#BG-A=1=-1=-1=1=-1=0 +[Ordner] +Filter= +[Column_OS_6.1_Ploder1] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +Spatlen_291=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%00%00%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%EE%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0E%00%00%00%69%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%91%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0C%00%00%00%46%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%00%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-563719693|772 +[Column_OS_6.1_Ploder2] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder3] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder4] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Programs_State] +Disable=0 +[Quick-Links] +WK=%systemdrive%/WK +[Options] +Start=0 From e05d2ce86249b6dbc3c64bd398634ee9a95b8580 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:08:39 -0800 Subject: [PATCH 11/85] 2017-01: Retroactive Updates * Added get_volumes() * This makes Assign/Remove letters sections more readable * Adjusted WinPE launch settings * Should now chdir to X:\WK * Added menu.cmd for easier (re)launching of menu * i.e. just type `menu` * Enabled user to return to the main menu after a major crash * make.cmd: Changed iso names to match the Linux build names * Refactored backup imaging code * More readable * More consistent variable naming * Moved classes and abort function to functions.py * Refactored disk/partition info sections * Refactored Windows Setup sections * Much more readable menu section * Majority of code moved to functions.py * More consistent variable naming * Boot mode detection now a callable function * Expanded WinRE section to match current recommended setup * WinRE is now setup for Legacy setups running Win8+ * Problems during setup will again be reported as errors instead of warnings * Verify source windows images and abort if invalid * Allows for earlier aborts which will reduce wasted time * Reordered functions to be in alphabetical order * Updated tools * Enabled file/folder size display in Q-Dir * Switched back to the standard ConEmu (instead of the Cmder build) * Updated scripts for Python 3.6 * This version has a different sys.path so the import code was adjusted * REMOVED Explorer++ * REMOVED HWMonitor * Bugfix: fixed discrepancies between x32 & x64 * Bugfix: relaunching the menu now stays in the current window --- .gitignore | 1 + LICENSE.txt | 2 +- Scripts/functions.py | 1279 +++++++++++------ Scripts/menu.py | 275 +--- System32/Winpeshl.ini | 3 +- System32/menu.cmd | 2 + .../{conemu-maximus5 => ConEmu}/ConEmu.xml | 776 ++++------ WK/amd64/Explorer++/config.xml | 113 -- WK/amd64/HWMonitor/hwmonitorw.ini | 7 - WK/amd64/HWiNFO/HWiNFO64.INI | 5 +- WK/amd64/Q-Dir/Q-Dir.ini | 18 +- WK/x86/{conemu-maximus5 => ConEmu}/ConEmu.xml | 776 ++++------ WK/x86/Explorer++/config.xml | 113 -- WK/x86/HWMonitor/hwmonitorw.ini | 7 - WK/x86/HWiNFO/HWiNFO32.INI | 4 +- WK/x86/Q-Dir/Q-Dir.ini | 18 +- make.cmd | 17 +- 17 files changed, 1564 insertions(+), 1852 deletions(-) create mode 100644 .gitignore create mode 100644 System32/menu.cmd rename WK/amd64/{conemu-maximus5 => ConEmu}/ConEmu.xml (52%) delete mode 100644 WK/amd64/Explorer++/config.xml delete mode 100644 WK/amd64/HWMonitor/hwmonitorw.ini rename WK/x86/{conemu-maximus5 => ConEmu}/ConEmu.xml (52%) delete mode 100644 WK/x86/Explorer++/config.xml delete mode 100644 WK/x86/HWMonitor/hwmonitorw.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ca218ad5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Scripts/__pycache__ diff --git a/LICENSE.txt b/LICENSE.txt index 3d52e4c5..8e17b045 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2016 Alan Mason +Copyright (c) 2017 Alan Mason Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/Scripts/functions.py b/Scripts/functions.py index 3f69b408..e647747e 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -1,10 +1,17 @@ # WK WinPE Functions +# Init import os import re import shutil import subprocess +import sys import time +import winreg +os.chdir(os.path.dirname(os.path.realpath(__file__))) +bin = os.path.abspath('..\\') +sys.path.append(os.getcwd()) +from functions import * import partition_uids # Init @@ -32,6 +39,44 @@ WINDOWS_SERVER = { 'User': 'backup', # Using these credentials in case both the windows source and backup shares are mounted. 'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time. } +WINDOWS_VERSIONS = [ + {'Name': 'Windows 7 Home Basic', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEBASIC', + 'Family': '7'}, + {'Name': 'Windows 7 Home Premium', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEPREMIUM', + 'Family': '7'}, + {'Name': 'Windows 7 Professional', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 PROFESSIONAL', + 'Family': '7'}, + {'Name': 'Windows 7 Ultimate', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 ULTIMATE', + 'Family': '7'}, + + {'Name': 'Windows 8.1', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1', + 'Family': '8', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1 Pro', + 'Family': '8'}, + + {'Name': 'Windows 10 Home', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Home', + 'Family': '10', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Pro', + 'Family': '10'}, +] diskpart_script = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) ## Colors @@ -42,6 +87,20 @@ COLORS = { 'YELLOW': '\033[33m', 'BLUE': '\033[34m'} +class AbortException(Exception): + pass + +class BackupException(Exception): + pass + +class SetupException(Exception): + pass + +def abort_to_main_menu(message='Returning to main menu...'): + print_warning(message) + pause('Press Enter to return to main menu... ') + raise AbortException + def ask(prompt='Kotaero'): answer = None prompt = prompt + ' [Y/N]: ' @@ -53,6 +112,41 @@ def ask(prompt='Kotaero'): answer = False return answer +def assign_volume_letters(): + try: + # Run script + with open(diskpart_script, 'w') as script: + for vol in get_volume_numbers(): + script.write('select volume {number}\n'.format(number=vol)) + script.write('assign\n') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except subprocess.CalledProcessError: + pass + +def backup_partition(bin=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if par is None: + raise Exception('Partition not specified.') + + print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) + if par['Number'] in disk['Bad Partitions']: + print_warning('Skipped.') + else: + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=fast'.format(bin=bin, **par) + if par['Image Exists']: + print_warning('Skipped.') + else: + try: + os.makedirs('{Image Path}'.format(**par), exist_ok=True) + run_program(cmd) + print_success('Complete.') + except subprocess.CalledProcessError as err: + print_error('Failed.') + par['Error'] = err.stderr.decode().splitlines() + raise BackupException + def convert_to_bytes(size): size = str(size) tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) @@ -72,6 +166,402 @@ def convert_to_bytes(size): return size +def is_valid_image(bin=None, filename=None, imagename=None): + # Bail early + if bin is None: + raise Exception('bin not specified.') + if filename is None: + raise Exception('Filename not specified.') + if imagename is None: + raise Exception('Image Name not specified.') + + cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Invalid image: {filename}'.format(filename=filename)) + return False + + return True + +def find_windows_image(bin, windows_version=None): + """Search for a Windows source image file on local drives and network drives (in that order)""" + image = {} + + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + imagefile = windows_version['Image File'] + + # Search local source + process_return = run_program('mountvol') + for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): + for ext in ['esd', 'wim', 'swm']: + filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_valid_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = tmp[0] + break + + # Check for network source (if necessary) + if not any(image): + if not WINDOWS_SERVER['Mounted']: + mount_windows_share() + for ext in ['esd', 'wim', 'swm']: + filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_valid_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = None + break + + # Display image to be used (if any) and return + if any(image): + print_info('Using image: {File}.{Ext}'.format(**image)) + return image + else: + print_error('Failed to find Windows source image for {winver}'.format(winver=windows_version['Name'])) + abort_to_main_menu('Aborting Windows setup') + +def format_gpt(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + print_info('Drive will use a GPT (UEFI) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + script.write('convert gpt\n') + + # System partition + script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives + script.write('format quick fs=fat32 label="System"\n') + script.write('assign letter="S"\n') + + # Microsoft Reserved (MSR) partition + script.write('create partition msr size=128\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery Tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def format_mbr(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + print_info('Drive will use a MBR (legacy) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + + # System partition + script.write('create partition primary size=100\n') + script.write('format fs=ntfs quick label="System Reserved"\n') + script.write('active\n') + script.write('assign letter="S"\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format fs=ntfs quick label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery"\n') + script.write('assign letter="T"\n') + script.write('set id=27\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def get_attached_disk_info(): + """Get details about the attached disks""" + disks = [] + print_info('Getting drive info...') + + # Assign all the letters + assign_volume_letters() + + # Get disks + disks = get_disks() + + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for par in disk['Partitions']: + # Get partition details + par.update(get_partition_details(disk, par)) + + # Done + return disks + +def get_boot_mode(): + boot_mode = 'Legacy' + try: + reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + boot_mode = 'UEFI' + except: + boot_mode = 'Unknown' + + return boot_mode + +def get_disk_details(disk=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('detail disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Set disk name + details['Name'] = tmp[4] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + return details + +def get_disks(): + disks = [] + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('list disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append disk numbers + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + disks.append({'Number': _num, 'Size': _size}) + + return disks + +def get_partition_details(disk=None, par=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Diskpart details + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('select partition {Number}\n'.format(**par)) + script.write('detail partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Get volume letter or RAW status + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) + if tmp: + if tmp.group(1) == 'RAW': + details['FileSystem'] = RAW + else: + details['Letter'] = tmp.group(1) + + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + guid = partition_uids.lookup_guid(details['Type']) + if guid is not None: + details.update({ + 'Description': guid.get('Description', ''), + 'OS': guid.get('OS', '')}) + + if 'Letter' in details: + # Disk usage + tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) + details['Used Space'] = human_readable_size(tmp.used) + + # fsutil details + try: + process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Add "Feature" lines + details['File System Features'] = [s.strip() for s in tmp if ':' not in s] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Set Volume Name + details['Name'] = details.get('Volume Name', '') + + # Set FileSystem Type + if details.get('FileSystem', '') != 'RAW': + details['FileSystem'] = details.get('File System Name', 'Unknown') + + return details + +def get_partitions(disk=None): + partitions = [] + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('list partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append partition numbers + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + partitions.append({'Number': _num, 'Size': _size}) + + return partitions + +def get_table_type(disk=None): + _type = 'Unknown' + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('uniqueid disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return): + _type = 'GPT' + elif re.findall(r'Disk ID: 00000000', process_return): + _type = 'RAW' + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return): + _type = 'MBR' + + return _type + +def get_ticket_id(): + ticket_id = None + while ticket_id is None: + tmp = input('Enter ticket number: ') + if re.match(r'^([0-9]+([\-_]*\w+|))$', tmp): + ticket_id = tmp + + return ticket_id + +def get_volume_numbers(): + vol_nums = [] + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append volume numbers + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): + if tmp[1] == '': + vol_nums.append(tmp[0]) + + return vol_nums + def human_readable_size(size, decimals=0): # Prep string formatting width = 3+decimals @@ -109,417 +599,48 @@ def human_readable_size(size, decimals=0): # Return return tmp -def pause(prompt='Press Enter to continue... '): - input(prompt) - -def print_error(message='Generic error', **kwargs): - print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_info(message='Generic info', **kwargs): - print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_warning(message='Generic warning', **kwargs): - print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_success(message='Generic success', **kwargs): - print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def run_program(cmd=None, args=[], check=True): - if cmd is None: - raise Exception('No program passed.') - - if len(args) > 0: - args = [cmd] + args - process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - else: - process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - - return process_return - -def assign_volume_letters(): - with open(diskpart_script, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - with open(diskpart_script, 'w') as script: - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): - if tmp[1] == '': - script.write('select volume {number}\n'.format(number=tmp[0])) - script.write('assign\n') - try: - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except: - pass - -def remove_volume_letters(keep=None): - with open(diskpart_script, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - with open(diskpart_script, 'w') as script: - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): - if tmp[1] != '' and tmp[1] != keep: - script.write('select volume {number}\n'.format(number=tmp[0])) - script.write('remove\n') - try: - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except: - pass - -def select_minidump_path(): - dumps = [] - - # Assign volume letters first - assign_volume_letters() - - # Search for minidumps - tmp = run_program('mountvol') - tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] - # Remove RAMDisk letter - if 'X' in tmp: - tmp.remove('X') - for drive in tmp: - if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): - dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) - - # Check results before showing menu - if len(dumps) == 0: - print_error(' No BSoD / MiniDump paths found') - time.sleep(2) - return None - - # Menu - selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) - return dumps[int(selection) - 1]['Name'] - -def find_windows_image(filename=None): - """Search for a Windows source image file on local drives and network drives (in that order)""" - image = {} +def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): + """Display options in a menu for user selection""" # Bail early - if filename is None: - raise Exception('Filename not specified.') - - # Search local source - process_return = run_program('mountvol') - for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): - for ext in ['esd', 'wim', 'swm']: - if os.path.isfile('{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename)): - image['Ext'] = ext - image['File'] = '{drive}:\\images\\{filename}'.format(drive=tmp[0], filename=filename) - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = tmp[0] - break - - # Check for network source (if necessary) - if not any(image): - if not WINDOWS_SERVER['Mounted']: - mount_windows_share() - for ext in ['esd', 'wim', 'swm']: - if os.path.isfile('\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER)): - image['Ext'] = ext - image['File'] = '\\\\{IP}\\{Share}\\images\\{filename}'.format(filename=filename, **WINDOWS_SERVER) - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = None - break - - # Display image to be used (if any) and return - if any(image): - print_info('Using image: {File}.{Ext}'.format(**image)) - return image - else: - return None - -def format_gpt(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - print_info('Drive will use a GPT (UEFI) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - script.write('convert gpt\n') - - # Windows RE tools partitions (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('create partition primary size=300\n') - script.write('format quick fs=ntfs label="Windows RE tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') - - # System partition - script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives - script.write('format quick fs=fat32 label="System"\n') - script.write('assign letter="S"\n') - - # Microsoft Reserved (MSR) partition - script.write('create partition msr size=128\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Windows"\n') - script.write('assign letter="W"\n') - - # Run script - print(' Formatting drive...') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def format_mbr(disk=None): - """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - - # Format drive - print_info('Drive will use a MBR (legacy) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - - # System partition - script.write('create partition primary size=100\n') - script.write('format fs=ntfs quick label="System Reserved"\n') - script.write('active\n') - script.write('assign letter=s\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format fs=ntfs quick label="Windows"\n') - script.write('assign letter=w\n') - - # Run script - print(' Formatting drive...') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def get_attached_disk_info(): - """Get details about the attached disks""" - disks = [] - print_info('Getting drive info...') - - # Assign all the letters - assign_volume_letters() - - # Get disk numbers - with open(diskpart_script, 'w') as script: - script.write('list disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return.stdout.decode()): - disks.append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) - - # Get disk details - for disk in disks: - # Get partition style - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('uniqueid disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return.stdout.decode()): - disk['Table'] = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return.stdout.decode()): - disk['Table'] = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return.stdout.decode()): - disk['Table'] = 'MBR' - else: - disk['Table'] = 'Unknown' - - # Get disk name/model and physical details - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('detail disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - tmp = process_return.stdout.decode().strip().splitlines() - # Remove empty lines and those without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.strip() for s in tmp if s.strip() != ''] - # Set disk name - disk['Name'] = tmp[4] - tmp = [s.split(':') for s in tmp if ':' in s] - # Add new key/value pairs to the disks variable - disk.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Get partition info for disk - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('list partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - disk['Partitions'] = [] - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return.stdout.decode().strip()): - disk['Partitions'].append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) - for par in disk['Partitions']: - # Get partition details - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('select partition {Number}\n'.format(**par)) - script.write('detail partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - for tmp in re.findall(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return.stdout.decode().strip()): - if tmp == 'RAW': - par['FileSystem'] = 'RAW' - else: - par['Letter'] = tmp - try: - process_return2 = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**par)) - for line in process_return2.stdout.decode().splitlines(): - line = line.strip() - # Get partition name - match = re.search(r'Volume Name\s+:\s+(.*)$', line) - if match: - par['Name'] = match.group(1).strip() - # Get filesystem type - match = re.search(r'File System Name\s+:\s+(.*)$', line) - if match: - par['FileSystem'] = match.group(1).strip() - usage = shutil.disk_usage('{Letter}:\\'.format(Letter=tmp)) - par['Used Space'] = human_readable_size(usage.used) - except subprocess.CalledProcessError: - par['FileSystem'] = 'Unknown' - # Get MBR type / GPT GUID for extra details on "Unknown" partitions - for tmp in re.findall(r'Type\s+:\s+(\S+)', process_return.stdout.decode().strip()): - par['Type'] = tmp - uid = partition_uids.lookup_guid(tmp) - if uid is not None: - par.update({ - 'Description': uid.get('Description', ''), - 'OS': uid.get('OS', '')}) - # Ensure the Name has been set - if 'Name' not in par: - par['Name'] = '' - if 'FileSystem' not in par: - par['FileSystem'] = 'Unknown' - - # Done - return disks - -def select_disk(prompt='Which disk?'): - """Select a disk from the attached disks""" - disks = get_attached_disk_info() + if (len(main_entries) + len(action_entries) == 0): + raise Exception("MenuError: No items given") # Build menu - disk_options = [] - for disk in disks: - display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if len(disk['Partitions']) > 0: - pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: - # Show unsupported partition(s) in RED - par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): - par_skip = True - if par_skip: - display_name += COLORS['YELLOW'] + menu_splash = '{title}\n\n'.format(title=title) + valid_answers = [] + if (secret_exit): + valid_answers.append('Q') - # Main text - display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) - if par['Name'] != '': - display_name += '\t"{Name}"'.format(**par) + # Add main entries + if (len(main_entries) > 0): + for i in range(len(main_entries)): + entry = main_entries[i] + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(str(i+1)) + menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) + menu_splash += '\n' - # Clear color (if set above) - if par_skip: - display_name += COLORS['CLEAR'] - else: - display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) - disk_options.append({'Name': display_name, 'Disk': disk}) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] + # Add action entries + if (len(action_entries) > 0): + for entry in action_entries: + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(entry['Letter']) + menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) + menu_splash += '\n' - # Menu loop - selection = menu_select(prompt, disk_options, actions) + answer = '' - if (selection.isnumeric()): - return disk_options[int(selection)-1]['Disk'] - elif (selection == 'M'): - return None + while (answer.upper() not in valid_answers): + os.system('cls') + print(menu_splash) + answer = input('{prompt}: '.format(prompt=prompt)) -def select_windows_version(): - versions = [ - {'Name': 'Windows 7 Home Basic', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 HOMEBASIC', - 'Family': '7'}, - {'Name': 'Windows 7 Home Premium', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 HOMEPREMIUM', - 'Family': '7'}, - {'Name': 'Windows 7 Professional', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 PROFESSIONAL', - 'Family': '7'}, - {'Name': 'Windows 7 Ultimate', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 ULTIMATE', - 'Family': '7'}, - - {'Name': 'Windows 8.1', - 'ImageFile': 'Win8', - 'ImageName': 'Windows 8.1', - 'Family': '8', - 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', - 'ImageFile': 'Win8', - 'ImageName': 'Windows 8.1 Pro', - 'Family': '8'}, - - {'Name': 'Windows 10 Home', - 'ImageFile': 'Win10', - 'ImageName': 'Windows 10 Home', - 'Family': '10', - 'CRLF': True}, - {'Name': 'Windows 10 Pro', - 'ImageFile': 'Win10', - 'ImageName': 'Windows 10 Pro', - 'Family': '10'}, - ] - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select('Which version of Windows are we installing?', versions, actions) - - if selection.isnumeric(): - return versions[int(selection)-1] - elif selection == 'M': - return None - -def select_destination(): - # Build menu - dests = [] - for server in BACKUP_SERVERS: - if server['Mounted']: - dests.append(server) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Size check - for dest in dests: - if 'IP' in dest: - dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) - else: - dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) - dest['Free Space'] = human_readable_size(dest['Usage'].free) - dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) - - # Show menu or bail - if len(dests) > 0: - selection = menu_select('Where are we backing up to?', dests, actions) - if selection == 'M': - return None - else: - return dests[int(selection)-1] - else: - print_warning('No backup destinations found.') - return None + return answer.upper() def mount_backup_shares(): """Mount the backup shares for use as destinations for backup image creation""" @@ -566,48 +687,336 @@ def mount_windows_share(): print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) time.sleep(1) -def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): - """Display options in a menu for user selection""" +def pause(prompt='Press Enter to continue... '): + input(prompt) +def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): + disk['Backup Warnings'] = '\n' + disk['Clobber Risk'] = [] + width = len(str(len(disk['Partitions']))) + # Bail early - if (len(main_entries) + len(action_entries) == 0): - raise Exception("MenuError: No items given") + if dest is None: + raise Exception('Destination not provided.') + if disk is None: + raise Exception('Disk not provided.') + if ticket_id is None: + raise Exception('Ticket ID not provided.') + + # Get partition totals + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'])] + disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) + + # Bail if no valid partitions are found (those that can be imaged) + if disk['Valid Partitions'] <= 0: + abort_to_main_menu(' No partitions can be imaged for the selected drive') + + # Prep partitions + for par in disk['Partitions']: + if par['Number'] in disk['Bad Partitions']: + par['Display String'] = '{YELLOW} * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS}){CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + else: + # Update info for WIM capturing + par['Image Name'] = str(par['Name']) + if par['Image Name'] == '': + par['Image Name'] = 'Unknown' + if 'IP' in dest: + par['Image Path'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket_id, **dest) + else: + par['Image Path'] = '{Letter}:\\{ticket}'.format(ticket=ticket_id, **dest) + par['Image File'] = '{Number}_{Image Name}'.format(**par) + par['Image File'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['Image File'])) + + # Check for existing backups + par['Image Exists'] = False + if os.path.exists('{Image Path}\\{Image File}'.format(**par)): + par['Image Exists'] = True + disk['Clobber Risk'].append(par['Number']) + par['Display String'] = '{BLUE} + '.format(**COLORS) + else: + par['Display String'] = '{CLEAR} '.format(**COLORS) + + # Append rest of Display String for valid/clobber partitions + par['Display String'] += 'Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}{CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + + # Set description for bad partitions + if len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup these partitions{CLEAR}'.format(**COLORS) + elif len(disk['Bad Partitions']) == 1: + print_warning(' * Unable to backup this partition') + disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup this partition{CLEAR}'.format(**COLORS) + + # Set description for partitions that would be clobbered + if disk['Clobber Risk'] > 1: + disk['Backup Warnings'] = '\n{BLUE} + These partitions already have backup images on {Display Name}{CLEAR}'.format(**dest, **COLORS) + elif disk['Clobber Risk'] == 1: + disk['Backup Warnings'] = '\n{BLUE} + This partition already has a backup image on {Display Name}{CLEAR}'.format(**dest, **COLORS) + + # Set warning for skipped partitions + if disk['Clobber Risk'] + len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] = '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}'.format(**COLORS) + if disk['Clobber Risk'] + len(disk['Bad Partitions']) == 1: + disk['Backup Warnings'] = '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}'.format(**COLORS) + +def prep_disk_for_formatting(disk=None): + disk['Format Warnings'] = '\n' + width = len(str(len(disk['Partitions']))) + + # Bail early + if disk is None: + raise Exception('Disk not provided.') + + # Confirm drive format + print_warning('All data will be deleted from the following drive:') + print_warning('\t{Size}\t({Table}) {Name}'.format(**disk)) + if (not ask('Is this correct?')): + abort_to_main_menu('Aborting Windows setup') + + # MBR/Legacy or GPT/UEFI? + disk['Use GPT'] = True + if (get_boot_mode() == 'UEFI'): + if (not ask("Setup drive using GPT (UEFI) layout?")): + disk['Use GPT'] = False + else: + if (ask("Setup drive using MBR (legacy) layout?")): + disk['Use GPT'] = False + + # Disk details + disk['Format Warnings'] += ' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk) + if (disk['Use GPT']): + disk['Format Warnings'] += ' Using: \tGPT (UEFI) layout\n' + else: + disk['Format Warnings'] += ' Using: \tMBR (legacy) layout\n' + + # Partition details + if len(disk['Partitions']) == 0: + # Bad color hack that will probably cause (aesthetic) issues in the future + disk['Format Warnings'] += '{YELLOW}\t\tNo partitions found{CLEAR}'.format(**COLORS) + else: + disk['Format Warnings'] += ' ERASING the following partitions:\n' + for par in disk['Partitions']: + if 'Letter' not in par or par['FileSystem'].upper() == 'RAW': + par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + else: + par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + +def print_error(message='Generic error', **kwargs): + print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_info(message='Generic info', **kwargs): + print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_success(message='Generic success', **kwargs): + print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_warning(message='Generic warning', **kwargs): + print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def remove_volume_letters(keep=None): + try: + # Run script + with open(diskpart_script, 'w') as script: + for vol in get_volume_numbers(): + script.write('select volume {number}\n'.format(number=vol)) + script.write('remove\n') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except subprocess.CalledProcessError: + pass + +def run_program(cmd=None, args=[], check=True): + if cmd is None: + raise Exception('No program passed.') + + if len(args) > 0: + args = [cmd] + args + process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + else: + process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + + return process_return + +def select_destination(): + # Build menu + dests = [] + for server in BACKUP_SERVERS: + if server['Mounted']: + dests.append(server) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Size check + for dest in dests: + if 'IP' in dest: + dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) + else: + dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) + dest['Free Space'] = human_readable_size(dest['Usage'].free) + dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) + + # Show menu or bail + if len(dests) > 0: + selection = menu_select('Where are we backing up to?', dests, actions) + if selection == 'M': + return None + else: + return dests[int(selection)-1] + else: + print_warning('No backup destinations found.') + return None + +def select_disk(prompt='Which disk?'): + """Select a disk from the attached disks""" + disks = get_attached_disk_info() # Build menu - menu_splash = '{title}\n\n'.format(title=title) - valid_answers = [] - if (secret_exit): - valid_answers.append('Q') + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + if len(disk['Partitions']) > 0: + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Show unsupported partition(s) in RED + par_skip = False + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): + par_skip = True + if par_skip: + display_name += COLORS['YELLOW'] - # Add main entries - if (len(main_entries) > 0): - for i in range(len(main_entries)): - entry = main_entries[i] - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(str(i+1)) - menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) - menu_splash += '\n' + # Main text + display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) + if par['Name'] != '': + display_name += '\t"{Name}"'.format(**par) - # Add action entries - if (len(action_entries) > 0): - for entry in action_entries: - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(entry['Letter']) - menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) - menu_splash += '\n' + # Clear color (if set above) + if par_skip: + display_name += COLORS['CLEAR'] + else: + display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] - answer = '' + # Menu loop + selection = menu_select(prompt, disk_options, actions) - while (answer.upper() not in valid_answers): - os.system('cls') - print(menu_splash) - answer = input('{prompt}: '.format(prompt=prompt)) + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + abort_to_main_menu() - return answer.upper() +def select_minidump_path(): + dumps = [] + + # Assign volume letters first + assign_volume_letters() + + # Search for minidumps + tmp = run_program('mountvol') + tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] + # Remove RAMDisk letter + if 'X' in tmp: + tmp.remove('X') + for drive in tmp: + if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): + dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) + + # Check results before showing menu + if len(dumps) == 0: + print_error(' No BSoD / MiniDump paths found') + time.sleep(2) + return None + + # Menu + selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) + return dumps[int(selection) - 1]['Name'] + +def select_windows_version(): + actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + + # Menu loop + selection = menu_select('Which version of Windows are we installing?', WINDOWS_VERSIONS, actions) + + if selection.isnumeric(): + return WINDOWS_VERSIONS[int(selection)-1] + elif selection == 'M': + abort_to_main_menu() + +def setup_boot_files(windows_version=None, system_letter='S', windows_letter='W', tools_letter='T'): + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + + # Setup system partition + print(' Creating boot files...') + try: + run_program('bcdboot {win}:\\Windows /s {sys}: /f ALL'.format(win=windows_letter, sys=system_letter)) + except subprocess.CalledProcessError: + print_error('Failed to create boot files.') + raise SetupException + if re.search(r'^(8|10)', windows_version['Family']): + try: + _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) + os.makedirs(_dest, exist_ok=True) + shutil.copy('{win}:\\Windows\\System32\\Recovery\\WinRE.wim', '{dest}\\WinRE.wim'.format(dest=_dest, win=windows_letter)) + run_program('{win}:\\Windows\\System32\\reagentc /setreimage /path {dest} /target {win}:\\Windows'.format(dest=_dest, win=windows_letter)) + except subprocess.CalledProcessError: + print_warning('Failed to setup WindowsRE files.') + raise SetupException + +def setup_windows(bin=None, windows_image=None, windows_version=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if windows_image is None: + raise Exception('Windows image not specified.') + if windows_version is None: + raise Exception('Windows version not specified.') + + # Apply image + print(' Applying image...') + cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Failed to apply Windows image.') + raise SetupException + +def verify_wim_backup(bin=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Verify hiding all output for quicker verification + print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) + cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}\\{Image File}" --nocheck'.format(bin=bin, **par) + if not os.path.exists('{Image Path}\\{Image File}'.format(**par)): + print_error('Missing.') + else: + try: + run_program(cmd) + print_success('OK.') + except subprocess.CalledProcessError as err: + print_error('Damaged.') + par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + raise BackupException if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/menu.py b/Scripts/menu.py index e781c14c..fb352f83 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -1,297 +1,141 @@ # WK WinPE Menu +# Init import os import re import subprocess +import sys import time import traceback -import winreg - -from functions import * - -# Init os.chdir(os.path.dirname(os.path.realpath(__file__))) bin = os.path.abspath('..\\') -## Check bootup type -BOOT_TYPE = 'Legacy' -try: - reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') - reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] - if reg_value == 2: - BOOT_TYPE = 'UEFI' -except: - BOOT_TYPE = 'Unknown' - -class AbortException(Exception): - pass - -def abort_to_main_menu(message='Returning to main menu...'): - print_warning(message) - pause('Press Enter to return to main menu... ') - raise AbortException +sys.path.append(os.getcwd()) +from functions import * def menu_backup_imaging(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" + errors = False # Mount backup shares os.system('cls') mount_backup_shares() - # Set ticket number - ticket = None - while ticket is None: - tmp = input('Enter ticket number: ') - if re.match(r'^([0-9]+([-_]?\w+|))$', tmp): - ticket = tmp - - # Select disk to backup - disk = select_disk('For which drive are we creating backups?') - if disk is None: - abort_to_main_menu() - - # Get list of partitions that can't be imaged - bad_parts = [p['Number'] for p in disk['Partitions'] if 'Letter' not in p or re.search(r'(RAW|Unknown)', p['FileSystem'])] - - # Bail if no partitions are found (that can be imaged) - num_parts = len(disk['Partitions']) - if num_parts == 0 or num_parts == len(bad_parts): - abort_to_main_menu(' No partitions can be imaged for the selected drive') + # Set ticket ID + ticket_id = get_ticket_id() # Select destination dest = select_destination() if dest is None: abort_to_main_menu('Aborting Backup Creation') - # List (and update) partition details for selected drive + # Select disk to backup + disk = select_disk('For which drive are we creating backups?') + if disk is None: + abort_to_main_menu() + prep_disk_for_backup(dest, disk, ticket_id) + + # Display details for backup task os.system('cls') print('Create Backup - Details:\n') print(' Drive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk)) - clobber_risk = 0 - width=len(str(len(disk['Partitions']))) for par in disk['Partitions']: - # Detail each partition - if par['Number'] in bad_parts: - print_warning(' * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - # Update info for WIM capture - par['ImageName'] = str(par['Name']) - if par['ImageName'] == '': - par['ImageName'] = 'Unknown' - if 'IP' in dest: - par['ImagePath'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket, **dest) - else: - par['ImagePath'] = '{Letter}:\\{ticket}'.format(ticket=ticket, **dest) - par['ImageFile'] = '{Number}_{ImageName}'.format(**par) - par['ImageFile'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['ImageFile'])) - - # Check for existing backups - par['ImageExists'] = False - if os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): - par['ImageExists'] = True - clobber_risk += 1 - print_info(' + Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print(' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - print('') # Spacer - - # Add warning about partition(s) that will be skipped - if len(bad_parts) > 1: - print_warning(' * Unable to backup these partitions') - elif len(bad_parts) == 1: - print_warning(' * Unable to backup this partition') - if clobber_risk > 1: - print_info(' + These partitions already have backup images on {Display Name}:'.format(**dest)) - elif clobber_risk == 1: - print_info(' + This partition already has a backup image on {Display Name}:'.format(**dest)) - if clobber_risk + len(bad_parts) > 1: - print_warning('\nIf you continue the partitions marked above will NOT be backed up.\n') - if clobber_risk + len(bad_parts) == 1: - print_warning('\nIf you continue the partition marked above will NOT be backed up.\n') - - # (re)display the destination - print(' Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) + print(par['Display String']) + print(disk['Backup Warnings']) + print('\n Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) # Ask to proceed if (not ask('Proceed with backup?')): abort_to_main_menu('Aborting Backup Creation') - + # Backup partition(s) print('\n\nStarting task.\n') - errors = False for par in disk['Partitions']: - print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) - if par['Number'] in bad_parts: - print_warning('Skipped.') - else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{ImagePath}\\{ImageFile}" "{ImageName}" "{ImageName}" --compress=fast'.format(bin=bin, **par) - if par['ImageExists']: - print_warning('Skipped.') - else: - try: - os.makedirs('{ImagePath}'.format(**par), exist_ok=True) - run_program(cmd) - print_success('Complete.') - except subprocess.CalledProcessError as err: - print_error('Failed.') - errors = True - par['Error'] = err.stderr.decode().splitlines() - + try: + backup_partition(bin, par) + except BackupException: + errors = True + # Verify backup(s) - if len(par) - len(bad_parts) > 1: + if len(disk['Valid Partitions']) > 1: print('\n\n Verifying backups\n') else: print('\n\n Verifying backup\n') for par in disk['Partitions']: - if par['Number'] not in bad_parts: - print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) - cmd = '{bin}\\wimlib\\wimlib-imagex verify "{ImagePath}\\{ImageFile}" --nocheck'.format(bin=bin, **par) - if not os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): - print_error('Missing.') - else: - try: - run_program(cmd) - print_success('OK.') - except subprocess.CalledProcessError as err: - print_error('Damaged.') - errors = True - par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + if par['Number'] in disk['Bad Partitions']: + continue # Skip verification + try: + verify_wim_backup(bin, par) + except BackupException: + errors = True # Print summary if errors: print_warning('\nErrors were encountered and are detailed below.') for par in [p for p in disk['Partitions'] if 'Error' in p]: print(' Partition {Number} Error:'.format(**par)) - for line in par['Error']: - line = line.strip() - if line != '': - print_error('\t{line}'.format(line=line)) - time.sleep(300) + for line in [line.strip() for line in par['Error'] if line.strip() != '']: + print_error('\t{line}'.format(line=line)) + time.sleep(30) else: print_success('\nNo errors were encountered during imaging.') - time.sleep(10) + time.sleep(5) pause('\nPress Enter to return to main menu... ') def menu_windows_setup(): """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" + errors = False # Select the version of Windows to apply os.system('cls') - selected_windows_version = select_windows_version() - if selected_windows_version is None: - abort_to_main_menu('Aborting Windows setup') - + windows_version = select_windows_version() + # Find Windows image - image = find_windows_image(selected_windows_version['ImageFile']) - if not any(image): - print_error('Failed to find Windows source image for {winver}'.format(winver=selected_windows_version['Name'])) - abort_to_main_menu('Aborting Windows setup') + windows_image = find_windows_image(bin, windows_version) # Select drive to use as the OS drive - dest_drive = select_disk('To which drive are we installing Windows?') - if dest_drive is None: - abort_to_main_menu('Aborting Windows setup') - - # Confirm drive format - print_warning('All data will be deleted from the following drive:') - print_warning('\t{Size}\t({Table}) {Name}'.format(**dest_drive)) - if (not ask('Is this correct?')): - abort_to_main_menu('Aborting Windows setup') - - # MBR/Legacy or GPT/UEFI? - use_gpt = True - if (BOOT_TYPE == 'UEFI'): - if (not ask("Setup drive using GPT (UEFI) layout?")): - use_gpt = False - else: - if (ask("Setup drive using MBR (legacy) layout?")): - use_gpt = False + dest_disk = select_disk('To which drive are we installing Windows?') + prep_disk_for_formatting(dest_disk) # Safety check print_warning('SAFETY CHECK\n') - print_error(' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}'.format(**dest_drive)) - if len(dest_drive['Partitions']) > 0: - width=len(str(len(dest_drive['Partitions']))) - for par in dest_drive['Partitions']: - if 'Letter' not in par or re.search(r'(RAW)', par['FileSystem']): - print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print_warning('\t\tNo partitions found') - if (use_gpt): - print(' Using: \tGPT (UEFI) layout') - else: - print(' Using: \tMBR (legacy) layout') - print_info(' Installing:\t{winver}'.format(winver=selected_windows_version['Name'])) + print_error(dest_disk['Format Warnings']) + for par in dest_disk['Partitions']: + print_error(par['Display String']) + print_info('\n Installing:\t{winver}'.format(winver=windows_version['Name'])) if (not ask('\nIs this correct?')): abort_to_main_menu('Aborting Windows setup') # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) - remove_volume_letters(keep=image['Source']) + remove_volume_letters(keep=windows_image['Source']) # Format and partition drive - if (use_gpt): - format_gpt(dest_drive, selected_windows_version['Family']) + if (dest_disk['Use GPT']): + format_gpt(dest_disk, windows_version['Family']) else: - format_mbr(dest_drive) + format_mbr(dest_disk, windows_version['Family']) - # Apply Windows image - errors = False - print(' Applying image...') - cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{ImageName}" W:\\ {Glob}'.format(bin=bin, **image, **selected_windows_version) + # Setup Windows try: - run_program(cmd) - except subprocess.CalledProcessError: + setup_windows(bin, windows_image, windows_version) + setup_boot_files(windows_version) + except SetupException: errors = True - print_error('Failed to apply Windows image.') - - # Create boot files - if not errors: - print(' Creating boot files...'.format(**selected_windows_version)) - try: - run_program('bcdboot W:\\Windows /s S: /f ALL') - except subprocess.CalledProcessError: - errors = True - print_error('Failed to create boot files.') - if re.search(r'^(8|10)', selected_windows_version['Family']): - try: - run_program('W:\\Windows\\System32\\reagentc /setreimage /path T:\\Recovery\\WindowsRE /target W:\\Windows') - except subprocess.CalledProcessError: - # errors = True # Changed to warning. - print_warning('Failed to setup WindowsRE files.') # Print summary if errors: print_warning('\nErrors were encountered during setup.') - time.sleep(300) + time.sleep(30) else: - print_success('\nNo errors were encountered during setup.') - time.sleep(10) + print_success('\nDone.') + time.sleep(5) pause('\nPress Enter to return to main menu... ') def menu_tools(): tools = [ {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, {'Name': 'CPU-Z', 'Folder': 'CPU-Z', 'File': 'cpuz.exe'}, - {'Name': 'Explorer++', 'Folder': 'Explorer++', 'File': 'Explorer++.exe'}, {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, - {'Name': 'HW Monitor', 'Folder': 'HWMonitor', 'File': 'HWMonitor.exe'}, {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, {'Name': 'Notepad2', 'Folder': 'Notepad2', 'File': 'Notepad2-Mod.exe'}, {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, @@ -351,10 +195,9 @@ def menu_main(): print_error('Major exception in: {menu}'.format(menu=menus[int(selection)-1]['Name'])) print_warning(' Please let The Wizard know and he\'ll look into it (Please include the details below).') print(traceback.print_exc()) - print_info(' You can reboot and try again but if this crashes again an alternative approach is required.') - time.sleep(300) - pause('Press Enter to shutdown...') - run_program(['wpeutil', 'shutdown']) + time.sleep(5) + print_info(' You can retry but if this crashes again an alternative approach may be required.') + pause('\nPress enter to return to the main menu') elif (selection == 'C'): run_program(['cmd', '-new_console:n'], check=False) elif (selection == 'R'): @@ -362,7 +205,7 @@ def menu_main(): elif (selection == 'S'): run_program(['wpeutil', 'shutdown']) else: - quit() + sys.exit(0) if __name__ == '__main__': menu_main() \ No newline at end of file diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index cd3d04ab..dc424ce7 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,4 +2,5 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -"%SystemDrive%\WK\conemu-maximus5\ConEmu.exe", /cmd cmd /k python %SystemDrive%\WK\Scripts\menu.py" +cd /d "%SystemDrive%\WK" +"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd cmd /k python "%SystemDrive%\WK\Scripts\menu.py" diff --git a/System32/menu.cmd b/System32/menu.cmd new file mode 100644 index 00000000..771dc372 --- /dev/null +++ b/System32/menu.cmd @@ -0,0 +1,2 @@ +@echo off +python "%SystemDrive%\WK\Scripts\menu.py" \ No newline at end of file diff --git a/WK/amd64/conemu-maximus5/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml similarity index 52% rename from WK/amd64/conemu-maximus5/ConEmu.xml rename to WK/amd64/ConEmu/ConEmu.xml index 9752d747..b8abe846 100644 --- a/WK/amd64/conemu-maximus5/ConEmu.xml +++ b/WK/amd64/ConEmu/ConEmu.xml @@ -1,38 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,108 +52,131 @@ - + - + - - + + + - + - + + + + + + + + + + + + + + + + - - - - - - - + - + + + + + + - - - + + + + - + - + - + + + - + + - - + + - + - - - - - - - + + + + + + + + + - - + + + + @@ -155,14 +185,22 @@ - + + + + + + + + - + + @@ -170,7 +208,10 @@ + + + @@ -186,17 +227,19 @@ - + - + + + @@ -205,39 +248,48 @@ - + + - + - - - - + + + + - + - + + + + + + + + + - + - - - - - + + + + + @@ -248,22 +300,30 @@ + - + + + + + + + - + - + + @@ -271,24 +331,24 @@ - + - + - + - - + + @@ -308,7 +368,7 @@ - + @@ -317,7 +377,7 @@ - + @@ -329,7 +389,9 @@ - + + + @@ -339,348 +401,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - + + + + - + - - - + + + - - + + - - - - + + + + - - - + + + + - - - - - + + + + + @@ -693,31 +467,36 @@ - + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + - + + + + @@ -727,22 +506,23 @@ - - + + + - - - - - - - - - - + + + + + + + + + + @@ -805,40 +585,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/amd64/Explorer++/config.xml b/WK/amd64/Explorer++/config.xml deleted file mode 100644 index add6848f..00000000 --- a/WK/amd64/Explorer++/config.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - - yes - no - yes - yes - no - yes - no - no - - - - - 90 - yes - no - no - no - no - no - no - 0 - yes - 9 - no - 0 - yes - no - ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} - no - 500 - yes - yes - 1 - yes - no - no - no - yes - yes - yes - yes - no - yes - no - yes - yes - yes - no - yes - yes - no - yes - yes - yes - 1 - yes - 1 - yes - no - no - - no - 208 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/amd64/HWMonitor/hwmonitorw.ini b/WK/amd64/HWMonitor/hwmonitorw.ini deleted file mode 100644 index 85f41603..00000000 --- a/WK/amd64/HWMonitor/hwmonitorw.ini +++ /dev/null @@ -1,7 +0,0 @@ -[HWMonitor] -VERSION=1.2.9.0 -USE_ACPI=1 -USE_SMBUS=1 -USE_SMART=1 -USE_DISPLAY=1 -UPDATES=0 diff --git a/WK/amd64/HWiNFO/HWiNFO64.INI b/WK/amd64/HWiNFO/HWiNFO64.INI index 700c5ff6..23133936 100644 --- a/WK/amd64/HWiNFO/HWiNFO64.INI +++ b/WK/amd64/HWiNFO/HWiNFO64.INI @@ -1,4 +1,3 @@ - [LogfileSettings] COMP=1 COMP_SP=1 @@ -172,7 +171,7 @@ PCIdirect=1 OpenSystemSummary=0 RememberPreferences=1 LargeFonts=0 -OpenSensors=1 +OpenSensors=0 MinimalizeMainWnd=0 MinimalizeSensors=0 PersistentDriver=0 @@ -180,7 +179,7 @@ UseHPET=1 AutoUpdate=0 GPUI2CNVAPI=1 GPUI2CADL=0 -SensorsOnly=1 +SensorsOnly=0 AcpiEval=1 CpuClkFromBusClk=1 BusClkPolling=1 diff --git a/WK/amd64/Q-Dir/Q-Dir.ini b/WK/amd64/Q-Dir/Q-Dir.ini index a9bdcb74..f6532f37 100644 --- a/WK/amd64/Q-Dir/Q-Dir.ini +++ b/WK/amd64/Q-Dir/Q-Dir.ini @@ -4,11 +4,11 @@ QDir_Id=0 useColorStart=1 Als=12 designe_mode=2 -WinRC=-1;-29;1441;873 -showCmd=1 +WinRC=66;87;1026;761 +showCmd=3 StartCrash=0 default_tab= -Max=3 +Max=1 show_ext_in_type=1 title_info=1 adresbar_style=1 @@ -56,4 +56,14 @@ Disable=0 [Quick-Links] WK=%systemdrive%/WK [Options] -Start=0 +Start=7 +[X-Size] +mode=1 +dig=0 +fld_size=1 +ths_sep=1 +type=0 +precent=1 +ff_cnt=1 +block_no_focus=1 +nosort_fld_size=1 diff --git a/WK/x86/conemu-maximus5/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml similarity index 52% rename from WK/x86/conemu-maximus5/ConEmu.xml rename to WK/x86/ConEmu/ConEmu.xml index a54f9ab5..b8abe846 100644 --- a/WK/x86/conemu-maximus5/ConEmu.xml +++ b/WK/x86/ConEmu/ConEmu.xml @@ -1,38 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,108 +52,131 @@ - + - + - - + + + - + - + + + + + + + + + + + + + + + + - - - - - - - + - + + + + + + - - - + + + + - + - + - + + + - + + - - + + - + - - - - - - - + + + + + + + + + - + - + + + @@ -155,14 +185,22 @@ - + + + + + + + + - + + @@ -170,7 +208,10 @@ + + + @@ -186,17 +227,19 @@ - + - + + + @@ -205,39 +248,48 @@ - + + - + - - - - + + + + - + - + + + + + + + + + - + - - - - - + + + + + @@ -248,22 +300,30 @@ + - + + + + + + + - + - + + @@ -271,24 +331,24 @@ - + - + - + - - + + @@ -308,7 +368,7 @@ - + @@ -317,7 +377,7 @@ - + @@ -329,7 +389,9 @@ - + + + @@ -339,348 +401,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - + + + + - + - - - + + + - - + + - - - - + + + + - - - + + + + - - - - - + + + + + @@ -693,31 +467,36 @@ - + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + - + + + + @@ -727,22 +506,23 @@ - - + + + - - - - - - - - - - + + + + + + + + + + @@ -805,40 +585,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/x86/Explorer++/config.xml b/WK/x86/Explorer++/config.xml deleted file mode 100644 index add6848f..00000000 --- a/WK/x86/Explorer++/config.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - - yes - no - yes - yes - no - yes - no - no - - - - - 90 - yes - no - no - no - no - no - no - 0 - yes - 9 - no - 0 - yes - no - ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} - no - 500 - yes - yes - 1 - yes - no - no - no - yes - yes - yes - yes - no - yes - no - yes - yes - yes - no - yes - yes - no - yes - yes - yes - 1 - yes - 1 - yes - no - no - - no - 208 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/x86/HWMonitor/hwmonitorw.ini b/WK/x86/HWMonitor/hwmonitorw.ini deleted file mode 100644 index 85f41603..00000000 --- a/WK/x86/HWMonitor/hwmonitorw.ini +++ /dev/null @@ -1,7 +0,0 @@ -[HWMonitor] -VERSION=1.2.9.0 -USE_ACPI=1 -USE_SMBUS=1 -USE_SMART=1 -USE_DISPLAY=1 -UPDATES=0 diff --git a/WK/x86/HWiNFO/HWiNFO32.INI b/WK/x86/HWiNFO/HWiNFO32.INI index ace15fef..74cf2a3e 100644 --- a/WK/x86/HWiNFO/HWiNFO32.INI +++ b/WK/x86/HWiNFO/HWiNFO32.INI @@ -633,7 +633,7 @@ PCIdirect=1 OpenSystemSummary=0 RememberPreferences=1 LargeFonts=0 -OpenSensors=1 +OpenSensors=0 MinimalizeMainWnd=0 MinimalizeSensors=0 PersistentDriver=0 @@ -641,7 +641,7 @@ UseHPET=1 AutoUpdate=0 GPUI2CNVAPI=1 GPUI2CADL=0 -SensorsOnly=1 +SensorsOnly=0 AcpiEval=1 CpuClkFromBusClk=1 BusClkPolling=1 diff --git a/WK/x86/Q-Dir/Q-Dir.ini b/WK/x86/Q-Dir/Q-Dir.ini index a9bdcb74..18f44d38 100644 --- a/WK/x86/Q-Dir/Q-Dir.ini +++ b/WK/x86/Q-Dir/Q-Dir.ini @@ -4,11 +4,11 @@ QDir_Id=0 useColorStart=1 Als=12 designe_mode=2 -WinRC=-1;-29;1441;873 -showCmd=1 +WinRC=8;15;968;689 +showCmd=3 StartCrash=0 default_tab= -Max=3 +Max=1 show_ext_in_type=1 title_info=1 adresbar_style=1 @@ -56,4 +56,14 @@ Disable=0 [Quick-Links] WK=%systemdrive%/WK [Options] -Start=0 +Start=7 +[X-Size] +mode=1 +dig=0 +fld_size=1 +ths_sep=1 +type=0 +precent=1 +ff_cnt=1 +block_no_focus=1 +nosort_fld_size=1 diff --git a/make.cmd b/make.cmd index 1447ecd8..c12fb6d0 100644 --- a/make.cmd +++ b/make.cmd @@ -2,7 +2,7 @@ :Init setlocal EnableDelayedExpansion -title WinPE 10 creation tool +title WK-WinPE creation tool color 1b pushd %~dp0 @@ -125,25 +125,26 @@ for %%a in (amd64 x86) do ( robocopy /s /r:3 /w:0 "!wd!\Scripts" "!mount!\WK\Scripts" rem Add System32 Stuff + copy /y "!wd!\System32\menu.cmd" "!mount!\Windows\System32\menu.cmd" copy /y "!wd!\System32\Winpeshl.ini" "!mount!\Windows\System32\Winpeshl.ini" - rem Background + rem Background takeown /f "!mount!\Windows\System32\winpe.jpg" /a icacls "!mount!\Windows\System32\winpe.jpg" /grant administrators:F copy /y "!wd!\System32\winpe.jpg" "!mount!\Windows\System32\winpe.jpg" - copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\conemu-maximus5\winpe.jpg" + copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\ConEmu\ConEmu.jpg" rem Registry Edits reg load HKLM\WinPE-SW "!mount!\Windows\System32\config\SOFTWARE" reg load HKLM\WinPE-SYS "!mount!\Windows\System32\config\SYSTEM" - rem Add 7-Zip and Python to path + rem Add 7-Zip and Python to path reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip;%%SystemDrive%%\WK\python;%%SystemDrive%%\WK\wimlib" /f - rem Replace Notepad + rem Replace Notepad reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod.exe /z" /f - rem Unload registry hives + rem Unload registry hives reg unload HKLM\WinPE-SW reg unload HKLM\WinPE-SYS @@ -151,8 +152,8 @@ for %%a in (amd64 x86) do ( dism /unmount-image /mountdir:"!mount!" /commit rem Create ISO - del "WinPE-!iso_date!-!arch!.iso" - call makewinpemedia.cmd /iso "!pe_files!" "WinPE-!iso_date!-!arch!-testing.iso" + del "wk-winpe-!iso_date!-!arch!.iso" + call makewinpemedia.cmd /iso "!pe_files!" "wk-winpe-!iso_date!-!arch!.iso" ) goto Done From 1da75165f9f72872a72d47fd48e682c80ad68800 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:09:57 -0800 Subject: [PATCH 12/85] 2017-02: Retroactive Updates * The working dir should now be X:\WK * Useful when quiting out of python to troubleshooting * Safer setup and formatting cleanup * Backup summary is now more detailed * Setup messages now more closely match the backup messages * More checks are done during under format_gpt() and format_mbr() * Setup specific functions have been refactored for easier reading * ConEmu settings update * No longer minimizes to the systray * This helps to prevent locking yourself out of the console * Added new color schemes * Bugfixes and Formatting * Install Windows has been renamed Setup Windows to match function names * Setup Windows summary screen is more detailed now * Setup Windows drive formatting auth questions are now at the end * Also reworded warning * Bugfix: all regex calls now case insensitive. * i.e. You can answer yes with 'y' or 'Y' or 'Yes' now --- .gitignore | 6 +- Scripts/functions.py | 146 ++++++++++++++------------------ Scripts/menu.py | 110 ++++++++++++++++++------ System32/Winpeshl.ini | 2 +- WK/amd64/ConEmu/ConEmu.xml | 169 +++++++++++++++++++++++++++---------- WK/x86/ConEmu/ConEmu.xml | 169 +++++++++++++++++++++++++++---------- 6 files changed, 405 insertions(+), 197 deletions(-) diff --git a/.gitignore b/.gitignore index ca218ad5..8d6f5fbe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -Scripts/__pycache__ +*iso +Scripts/__pycache__ +dism* +mount +pe_files \ No newline at end of file diff --git a/Scripts/functions.py b/Scripts/functions.py index e647747e..6a8f5c66 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -87,28 +87,28 @@ COLORS = { 'YELLOW': '\033[33m', 'BLUE': '\033[34m'} -class AbortException(Exception): +class AbortError(Exception): pass -class BackupException(Exception): +class BackupError(Exception): pass -class SetupException(Exception): +class SetupError(Exception): pass def abort_to_main_menu(message='Returning to main menu...'): print_warning(message) pause('Press Enter to return to main menu... ') - raise AbortException + raise AbortError def ask(prompt='Kotaero'): answer = None prompt = prompt + ' [Y/N]: ' while answer is None: tmp = input(prompt) - if re.search(r'^y(es|)$', tmp): + if re.search(r'^y(es|)$', tmp, re.IGNORECASE): answer = True - elif re.search(r'^n(o|ope|)$', tmp): + elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE): answer = False return answer @@ -123,10 +123,12 @@ def assign_volume_letters(): except subprocess.CalledProcessError: pass -def backup_partition(bin=None, par=None): +def backup_partition(bin=None, disk=None, par=None): # Bail early if bin is None: raise Exception('bin path not specified.') + if disk is None: + raise Exception('Disk not specified.') if par is None: raise Exception('Partition not specified.') @@ -145,7 +147,7 @@ def backup_partition(bin=None, par=None): except subprocess.CalledProcessError as err: print_error('Failed.') par['Error'] = err.stderr.decode().splitlines() - raise BackupException + raise BackupError def convert_to_bytes(size): size = str(size) @@ -240,7 +242,7 @@ def format_gpt(disk=None, windows_family=None): raise Exception('No Windows family provided.') # Format drive - print_info('Drive will use a GPT (UEFI) layout.') + # print_info('Drive will use a GPT (UEFI) layout.') with open(diskpart_script, 'w') as script: # Partition table script.write('select disk {number}\n'.format(number=disk['Number'])) @@ -270,7 +272,6 @@ def format_gpt(disk=None, windows_family=None): script.write('gpt attributes=0x8000000000000001\n') # Run script - print(' Formatting drive...') run_program('diskpart /s {script}'.format(script=diskpart_script)) time.sleep(2) @@ -284,7 +285,7 @@ def format_mbr(disk=None, windows_family=None): raise Exception('No Windows family provided.') # Format drive - print_info('Drive will use a MBR (legacy) layout.') + # print_info('Drive will use a MBR (legacy) layout.') with open(diskpart_script, 'w') as script: # Partition table script.write('select disk {number}\n'.format(number=disk['Number'])) @@ -310,7 +311,6 @@ def format_mbr(disk=None, windows_family=None): script.write('set id=27\n') # Run script - print(' Formatting drive...') run_program('diskpart /s {script}'.format(script=diskpart_script)) time.sleep(2) @@ -430,7 +430,7 @@ def get_partition_details(disk=None, par=None): # Get volume letter or RAW status tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) if tmp: - if tmp.group(1) == 'RAW': + if tmp.group(1).upper() == 'RAW': details['FileSystem'] = RAW else: details['Letter'] = tmp.group(1) @@ -502,7 +502,7 @@ def get_partitions(disk=None): pass else: # Append partition numbers - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return): + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): _num = tmp[0] _size = human_readable_size(tmp[1]) partitions.append({'Number': _num, 'Size': _size}) @@ -525,11 +525,11 @@ def get_table_type(disk=None): except subprocess.CalledProcessError: pass else: - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return): + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): _type = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return): + elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): _type = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return): + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): _type = 'MBR' return _type @@ -704,7 +704,7 @@ def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): raise Exception('Ticket ID not provided.') # Get partition totals - disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'])] + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE)] disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) # Bail if no valid partitions are found (those that can be imaged) @@ -749,22 +749,22 @@ def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): # Set description for bad partitions if len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup these partitions{CLEAR}'.format(**COLORS) + disk['Backup Warnings'] += '{YELLOW} * Unable to backup these partitions{CLEAR}\n'.format(**COLORS) elif len(disk['Bad Partitions']) == 1: print_warning(' * Unable to backup this partition') - disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup this partition{CLEAR}'.format(**COLORS) + disk['Backup Warnings'] += '{YELLOW} * Unable to backup this partition{CLEAR}\n'.format(**COLORS) # Set description for partitions that would be clobbered - if disk['Clobber Risk'] > 1: - disk['Backup Warnings'] = '\n{BLUE} + These partitions already have backup images on {Display Name}{CLEAR}'.format(**dest, **COLORS) - elif disk['Clobber Risk'] == 1: - disk['Backup Warnings'] = '\n{BLUE} + This partition already has a backup image on {Display Name}{CLEAR}'.format(**dest, **COLORS) + if len(disk['Clobber Risk']) > 1: + disk['Backup Warnings'] += '{BLUE} + These partitions already have backup images on {Name}{CLEAR}\n'.format(**dest, **COLORS) + elif len(disk['Clobber Risk']) == 1: + disk['Backup Warnings'] += '{BLUE} + This partition already has a backup image on {Name}{CLEAR}\n'.format(**dest, **COLORS) # Set warning for skipped partitions - if disk['Clobber Risk'] + len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] = '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}'.format(**COLORS) - if disk['Clobber Risk'] + len(disk['Bad Partitions']) == 1: - disk['Backup Warnings'] = '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}'.format(**COLORS) + if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] += '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) + if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) == 1: + disk['Backup Warnings'] += '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) def prep_disk_for_formatting(disk=None): disk['Format Warnings'] = '\n' @@ -774,42 +774,28 @@ def prep_disk_for_formatting(disk=None): if disk is None: raise Exception('Disk not provided.') - # Confirm drive format - print_warning('All data will be deleted from the following drive:') - print_warning('\t{Size}\t({Table}) {Name}'.format(**disk)) - if (not ask('Is this correct?')): - abort_to_main_menu('Aborting Windows setup') - - # MBR/Legacy or GPT/UEFI? + # Set boot method and partition table type disk['Use GPT'] = True if (get_boot_mode() == 'UEFI'): - if (not ask("Setup drive using GPT (UEFI) layout?")): + if (not ask("Setup Windows to use UEFI booting?")): disk['Use GPT'] = False else: - if (ask("Setup drive using MBR (legacy) layout?")): + if (ask("Setup Windows to use BIOS/Legacy booting?")): disk['Use GPT'] = False - - # Disk details - disk['Format Warnings'] += ' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk) - if (disk['Use GPT']): - disk['Format Warnings'] += ' Using: \tGPT (UEFI) layout\n' - else: - disk['Format Warnings'] += ' Using: \tMBR (legacy) layout\n' - # Partition details + # Set Display and Warning Strings if len(disk['Partitions']) == 0: - # Bad color hack that will probably cause (aesthetic) issues in the future - disk['Format Warnings'] += '{YELLOW}\t\tNo partitions found{CLEAR}'.format(**COLORS) - else: - disk['Format Warnings'] += ' ERASING the following partitions:\n' + disk['Format Warnings'] += 'No partitions found\n' for par in disk['Partitions']: - if 'Letter' not in par or par['FileSystem'].upper() == 'RAW': - par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): + # FileSystem not accessible to WinPE. List partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( width=width, q='"' if par['Name'] != '' else '', **par) else: - par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( + # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( width=width, q='"' if par['Name'] != '' else '', **par) @@ -892,7 +878,7 @@ def select_disk(prompt='Which disk?'): for par in disk['Partitions']: # Show unsupported partition(s) in RED par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): par_skip = True if par_skip: display_name += COLORS['YELLOW'] @@ -957,28 +943,6 @@ def select_windows_version(): elif selection == 'M': abort_to_main_menu() -def setup_boot_files(windows_version=None, system_letter='S', windows_letter='W', tools_letter='T'): - # Bail early - if windows_version is None: - raise Exception('Windows version not specified.') - - # Setup system partition - print(' Creating boot files...') - try: - run_program('bcdboot {win}:\\Windows /s {sys}: /f ALL'.format(win=windows_letter, sys=system_letter)) - except subprocess.CalledProcessError: - print_error('Failed to create boot files.') - raise SetupException - if re.search(r'^(8|10)', windows_version['Family']): - try: - _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) - os.makedirs(_dest, exist_ok=True) - shutil.copy('{win}:\\Windows\\System32\\Recovery\\WinRE.wim', '{dest}\\WinRE.wim'.format(dest=_dest, win=windows_letter)) - run_program('{win}:\\Windows\\System32\\reagentc /setreimage /path {dest} /target {win}:\\Windows'.format(dest=_dest, win=windows_letter)) - except subprocess.CalledProcessError: - print_warning('Failed to setup WindowsRE files.') - raise SetupException - def setup_windows(bin=None, windows_image=None, windows_version=None): # Bail early if bin is None: @@ -989,13 +953,31 @@ def setup_windows(bin=None, windows_image=None, windows_version=None): raise Exception('Windows version not specified.') # Apply image - print(' Applying image...') cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) - try: - run_program(cmd) - except subprocess.CalledProcessError: - print_error('Failed to apply Windows image.') - raise SetupException + run_program(cmd) + +def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T'): + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + + _win = '{win}:\\Windows'.format(win=windows_letter) + _winre = '{win}\\System32\\Recovery\\WinRE.wim'.format(win=_win) + _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) + + if re.search(r'^(8|10)', windows_version['Family']): + # Copy WinRE.wim + os.makedirs(_dest, exist_ok=True) + shutil.copy(_winre, '{dest}\\WinRE.wim'.format(dest=_dest)) + + # Set location + run_program('{win}\\System32\\reagentc /setreimage /path {dest} /target {win}'.format(dest=_dest, win=_win)) + else: + # Only supported on Windows 8 and above + raise SetupError + +def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): + run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) def verify_wim_backup(bin=None, par=None): # Bail early @@ -1016,7 +998,7 @@ def verify_wim_backup(bin=None, par=None): except subprocess.CalledProcessError as err: print_error('Damaged.') par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() - raise BackupException + raise BackupError if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/menu.py b/Scripts/menu.py index fb352f83..a834026a 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -16,13 +16,13 @@ def menu_backup_imaging(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" errors = False - # Mount backup shares - os.system('cls') - mount_backup_shares() - # Set ticket ID + os.system('cls') ticket_id = get_ticket_id() + # Mount backup shares + mount_backup_shares() + # Select destination dest = select_destination() if dest is None: @@ -37,11 +37,12 @@ def menu_backup_imaging(): # Display details for backup task os.system('cls') print('Create Backup - Details:\n') - print(' Drive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk)) + print(' Ticket: \t{ticket_id}'.format(ticket_id=ticket_id)) + print(' Source: \t[{Table}] ({Type}) {Name} {Size}\n'.format(**disk)) + print(' Destination:\t{name}'.format(name=dest.get('Display Name', dest['Name']))) for par in disk['Partitions']: print(par['Display String']) print(disk['Backup Warnings']) - print('\n Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) # Ask to proceed if (not ask('Proceed with backup?')): @@ -51,12 +52,12 @@ def menu_backup_imaging(): print('\n\nStarting task.\n') for par in disk['Partitions']: try: - backup_partition(bin, par) - except BackupException: + backup_partition(bin, disk, par) + except BackupError: errors = True # Verify backup(s) - if len(disk['Valid Partitions']) > 1: + if disk['Valid Partitions'] > 1: print('\n\n Verifying backups\n') else: print('\n\n Verifying backup\n') @@ -65,7 +66,7 @@ def menu_backup_imaging(): continue # Skip verification try: verify_wim_backup(bin, par) - except BackupException: + except BackupError: errors = True # Print summary @@ -85,8 +86,11 @@ def menu_windows_setup(): """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" errors = False - # Select the version of Windows to apply + # Set ticket ID os.system('cls') + ticket_id = get_ticket_id() + + # Select the version of Windows to apply windows_version = select_windows_version() # Find Windows image @@ -96,29 +100,81 @@ def menu_windows_setup(): dest_disk = select_disk('To which drive are we installing Windows?') prep_disk_for_formatting(dest_disk) - # Safety check - print_warning('SAFETY CHECK\n') - print_error(dest_disk['Format Warnings']) + # Display details for setup task + os.system('cls') + print('Setup Windows - Details:\n') + print(' Ticket: \t{ticket_id}'.format(ticket_id=ticket_id)) + print(' Installing: \t{winver}'.format(winver=windows_version['Name'])) + print(' Boot Method:\t{_type}'.format( + _type='UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')) + print(' Using Image:\t{File}.{Ext}'.format(**windows_image)) + print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk)) for par in dest_disk['Partitions']: - print_error(par['Display String']) - print_info('\n Installing:\t{winver}'.format(winver=windows_version['Name'])) - if (not ask('\nIs this correct?')): + print_warning(par['Display String']) + print_warning(dest_disk['Format Warnings']) + + if (not ask('Is this correct?')): + abort_to_main_menu('Aborting Windows setup') + + # Safety check + print('\nSAFETY CHECK') + print_warning('All data will be DELETED from the drive and partition(s) listed above.') + print_error('This is irreversible and will lead to DATA LOSS.') + if (not ask('Asking again to confirm, is this correct?')): abort_to_main_menu('Aborting Windows setup') # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) remove_volume_letters(keep=windows_image['Source']) # Format and partition drive - if (dest_disk['Use GPT']): - format_gpt(dest_disk, windows_version['Family']) - else: - format_mbr(dest_disk, windows_version['Family']) + print('\n Formatting Drive...\t\t'.format(**par), end='', flush=True) + try: + if (dest_disk['Use GPT']): + format_gpt(dest_disk, windows_version['Family']) + else: + format_mbr(dest_disk, windows_version['Family']) + print_success('Complete.') + except: + # We need to crash as the drive is in an unknown state + print_error('Failed.') + raise - # Setup Windows + # Apply Image + print(' Applying Image...\t\t'.format(**par), end='', flush=True) try: setup_windows(bin, windows_image, windows_version) - setup_boot_files(windows_version) - except SetupException: + print_success('Complete.') + except subprocess.CalledProcessError: + print_error('Failed.') + errors = True + except: + # We need to crash as the OS is in an unknown state + print_error('Failed.') + raise + + # Create Boot files + print(' Update Boot Partition...\t\t'.format(**par), end='', flush=True) + try: + update_boot_partition() + print_success('Complete.') + except subprocess.CalledProcessError: + # Don't need to crash as this is (potentially) recoverable + print_error('Failed.') + errors = True + except: + print_error('Failed.') + raise + + # Setup WinRE + print(' Update Recovery Tools...\t\t'.format(**par), end='', flush=True) + try: + setup_windows_re(windows_version) + print_success('Complete.') + except SetupError: + print_error('Skipped.') + except: + # Don't need to crash as this is (potentially) recoverable + print_error('Failed.') errors = True # Print summary @@ -126,7 +182,7 @@ def menu_windows_setup(): print_warning('\nErrors were encountered during setup.') time.sleep(30) else: - print_success('\nDone.') + print_success('\nNo errors were encountered during setup.') time.sleep(5) pause('\nPress Enter to return to main menu... ') @@ -173,7 +229,7 @@ def menu_tools(): def menu_main(): menus = [ {'Name': 'Create Backups', 'Menu': menu_backup_imaging}, - {'Name': 'Install Windows', 'Menu': menu_windows_setup}, + {'Name': 'Setup Windows', 'Menu': menu_windows_setup}, {'Name': 'Misc Tools', 'Menu': menu_tools}, ] actions = [ @@ -189,7 +245,7 @@ def menu_main(): if (selection.isnumeric()): try: menus[int(selection)-1]['Menu']() - except AbortException: + except AbortError: pass except: print_error('Major exception in: {menu}'.format(menu=menus[int(selection)-1]['Name'])) diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index dc424ce7..716d7d6e 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -3,4 +3,4 @@ wpeinit wpeutil updatebootinfo cd /d "%SystemDrive%\WK" -"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd cmd /k python "%SystemDrive%\WK\Scripts\menu.py" +"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\WK" & python "%SystemDrive%\WK\Scripts\menu.py" diff --git a/WK/amd64/ConEmu/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml index b8abe846..68fa0f50 100644 --- a/WK/amd64/ConEmu/ConEmu.xml +++ b/WK/amd64/ConEmu/ConEmu.xml @@ -1,7 +1,7 @@ - + @@ -9,37 +9,37 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + - + - + - - + + - + @@ -138,7 +138,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -227,8 +227,8 @@ - - + + @@ -401,7 +401,7 @@ - + @@ -586,9 +586,9 @@ - + - + @@ -597,7 +597,7 @@ - + @@ -606,7 +606,7 @@ - + @@ -615,7 +615,7 @@ - + @@ -625,7 +625,7 @@ - + @@ -634,7 +634,7 @@ - + @@ -643,7 +643,7 @@ - + @@ -652,7 +652,7 @@ - + @@ -661,7 +661,7 @@ - + @@ -671,12 +671,95 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/x86/ConEmu/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml index b8abe846..68fa0f50 100644 --- a/WK/x86/ConEmu/ConEmu.xml +++ b/WK/x86/ConEmu/ConEmu.xml @@ -1,7 +1,7 @@ - + @@ -9,37 +9,37 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + - + - + - - + + - + @@ -138,7 +138,7 @@ - + @@ -155,7 +155,7 @@ - + @@ -227,8 +227,8 @@ - - + + @@ -401,7 +401,7 @@ - + @@ -586,9 +586,9 @@ - + - + @@ -597,7 +597,7 @@ - + @@ -606,7 +606,7 @@ - + @@ -615,7 +615,7 @@ - + @@ -625,7 +625,7 @@ - + @@ -634,7 +634,7 @@ - + @@ -643,7 +643,7 @@ - + @@ -652,7 +652,7 @@ - + @@ -661,7 +661,7 @@ - + @@ -671,12 +671,95 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 827f9bce6a192ed1f57864a21753204135b9ece2 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:11:56 -0800 Subject: [PATCH 13/85] 2017-03: Retroactive Updates Fixed using local windows images * Bugfix: remove_volume_letters() was not preserving the "keep" letter * First issue: if keep==None then it would crash * Second issue: The passed keep value was outdated (See bugfix below) * Bugfix: undesired call of assign_volume_letters() * prep_disk_for_formatting() resets the volume letters thus breaking local installs * By moving find_windows_image() to be called afterwards this is fixed but perhaps another refactor is in order? --- Scripts/functions.py | 24 +++++++++++++----------- Scripts/menu.py | 21 ++++++++++++--------- WK/amd64/ConEmu/ConEmu.xml | 2 +- WK/x86/ConEmu/ConEmu.xml | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Scripts/functions.py b/Scripts/functions.py index 6a8f5c66..9b3b8e9d 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -116,8 +116,8 @@ def assign_volume_letters(): try: # Run script with open(diskpart_script, 'w') as script: - for vol in get_volume_numbers(): - script.write('select volume {number}\n'.format(number=vol)) + for vol in get_volumes(): + script.write('select volume {Number}\n'.format(**vol)) script.write('assign\n') run_program('diskpart /s {script}'.format(script=diskpart_script)) except subprocess.CalledProcessError: @@ -543,8 +543,8 @@ def get_ticket_id(): return ticket_id -def get_volume_numbers(): - vol_nums = [] +def get_volumes(): + vols = [] try: # Run script @@ -557,10 +557,9 @@ def get_volume_numbers(): else: # Append volume numbers for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): - if tmp[1] == '': - vol_nums.append(tmp[0]) + vols.append({'Number': tmp[0], 'Letter': tmp[1]}) - return vol_nums + return vols def human_readable_size(size, decimals=0): # Prep string formatting @@ -812,13 +811,16 @@ def print_success(message='Generic success', **kwargs): def print_warning(message='Generic warning', **kwargs): print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) -def remove_volume_letters(keep=None): +def remove_volume_letters(keep=''): + if keep is None: + keep = '' try: # Run script with open(diskpart_script, 'w') as script: - for vol in get_volume_numbers(): - script.write('select volume {number}\n'.format(number=vol)) - script.write('remove\n') + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('remove noerr\n') run_program('diskpart /s {script}'.format(script=diskpart_script)) except subprocess.CalledProcessError: pass diff --git a/Scripts/menu.py b/Scripts/menu.py index a834026a..d7d010d1 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -92,13 +92,15 @@ def menu_windows_setup(): # Select the version of Windows to apply windows_version = select_windows_version() - - # Find Windows image - windows_image = find_windows_image(bin, windows_version) # Select drive to use as the OS drive dest_disk = select_disk('To which drive are we installing Windows?') prep_disk_for_formatting(dest_disk) + + # Find Windows image + ## NOTE: Needs to happen AFTER select_disk() is called as there's a hidden assign_volume_letters(). + ## This changes the current letters thus preventing installing from a local source. + windows_image = find_windows_image(bin, windows_version) # Display details for setup task os.system('cls') @@ -119,7 +121,8 @@ def menu_windows_setup(): # Safety check print('\nSAFETY CHECK') print_warning('All data will be DELETED from the drive and partition(s) listed above.') - print_error('This is irreversible and will lead to DATA LOSS.') + print_error('This is irreversible and will lead to ', end='', flush=True) + print('DATA LOSS.') if (not ask('Asking again to confirm, is this correct?')): abort_to_main_menu('Aborting Windows setup') @@ -127,7 +130,7 @@ def menu_windows_setup(): remove_volume_letters(keep=windows_image['Source']) # Format and partition drive - print('\n Formatting Drive...\t\t'.format(**par), end='', flush=True) + print('\n Formatting Drive... \t\t', end='', flush=True) try: if (dest_disk['Use GPT']): format_gpt(dest_disk, windows_version['Family']) @@ -140,7 +143,7 @@ def menu_windows_setup(): raise # Apply Image - print(' Applying Image...\t\t'.format(**par), end='', flush=True) + print(' Applying Image... \t\t', end='', flush=True) try: setup_windows(bin, windows_image, windows_version) print_success('Complete.') @@ -153,7 +156,7 @@ def menu_windows_setup(): raise # Create Boot files - print(' Update Boot Partition...\t\t'.format(**par), end='', flush=True) + print(' Update Boot Partition...\t\t', end='', flush=True) try: update_boot_partition() print_success('Complete.') @@ -166,12 +169,12 @@ def menu_windows_setup(): raise # Setup WinRE - print(' Update Recovery Tools...\t\t'.format(**par), end='', flush=True) + print(' Update Recovery Tools...\t\t', end='', flush=True) try: setup_windows_re(windows_version) print_success('Complete.') except SetupError: - print_error('Skipped.') + print('Skipped.') except: # Don't need to crash as this is (potentially) recoverable print_error('Failed.') diff --git a/WK/amd64/ConEmu/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml index 68fa0f50..8a2049b9 100644 --- a/WK/amd64/ConEmu/ConEmu.xml +++ b/WK/amd64/ConEmu/ConEmu.xml @@ -138,7 +138,7 @@ - + diff --git a/WK/x86/ConEmu/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml index 68fa0f50..8a2049b9 100644 --- a/WK/x86/ConEmu/ConEmu.xml +++ b/WK/x86/ConEmu/ConEmu.xml @@ -138,7 +138,7 @@ - + From 50d53beef6ec5a2d2d61e379d4da9a4d716fc562 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:12:54 -0800 Subject: [PATCH 14/85] 2017-04: Retroactive Updates * Adjusted data loss waning --- Scripts/menu.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Scripts/menu.py b/Scripts/menu.py index d7d010d1..eb84d18e 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -12,6 +12,14 @@ bin = os.path.abspath('..\\') sys.path.append(os.getcwd()) from functions import * +## Colors +COLORS = { + 'CLEAR': '\033[0m', + 'RED': '\033[31m', + 'GREEN': '\033[32m', + 'YELLOW': '\033[33m', + 'BLUE': '\033[34m'} + def menu_backup_imaging(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" errors = False @@ -121,8 +129,7 @@ def menu_windows_setup(): # Safety check print('\nSAFETY CHECK') print_warning('All data will be DELETED from the drive and partition(s) listed above.') - print_error('This is irreversible and will lead to ', end='', flush=True) - print('DATA LOSS.') + print_warning('This is irreversible and will lead to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) if (not ask('Asking again to confirm, is this correct?')): abort_to_main_menu('Aborting Windows setup') From 1e02eb44a5251a7cc3c57e51b5ba1d880da9319a Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:13:50 -0800 Subject: [PATCH 15/85] 2017-08: Retroactive Updates * Faster WIM creation * (Removed compression) --- Scripts/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/functions.py b/Scripts/functions.py index 9b3b8e9d..03f03bf3 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -136,7 +136,7 @@ def backup_partition(bin=None, disk=None, par=None): if par['Number'] in disk['Bad Partitions']: print_warning('Skipped.') else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=fast'.format(bin=bin, **par) + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=none'.format(bin=bin, **par) if par['Image Exists']: print_warning('Skipped.') else: From b8a088d3b6710a35137d07581454912cbc348f49 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 24 Nov 2017 21:15:32 -0800 Subject: [PATCH 16/85] 2017-11: Retroactive Updates * Network drivers disabled (for now until the sigs are manually verified) * Replaced Notepad2-Mod with Notepad++ --- Scripts/menu.py | 2 +- WK/amd64/Notepad2/Notepad2.ini | 106 ---------------------------- WK/amd64/NotepadPlusPlus/config.xml | 56 +++++++++++++++ WK/x86/Notepad2/Notepad2.ini | 106 ---------------------------- WK/x86/NotepadPlusPlus/config.xml | 56 +++++++++++++++ make.cmd | 4 +- 6 files changed, 115 insertions(+), 215 deletions(-) delete mode 100644 WK/amd64/Notepad2/Notepad2.ini create mode 100644 WK/amd64/NotepadPlusPlus/config.xml delete mode 100644 WK/x86/Notepad2/Notepad2.ini create mode 100644 WK/x86/NotepadPlusPlus/config.xml diff --git a/Scripts/menu.py b/Scripts/menu.py index eb84d18e..952ec9a4 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -203,7 +203,7 @@ def menu_tools(): {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, - {'Name': 'Notepad2', 'Folder': 'Notepad2', 'File': 'Notepad2-Mod.exe'}, + {'Name': 'Notepad++', 'Folder': 'NotepadPlusPlus', 'File': 'notepadplusplus.exe'}, {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, {'Name': 'Prime95', 'Folder': 'Prime95', 'File': 'prime95.exe'}, {'Name': 'ProduKey', 'Folder': 'ProduKey', 'File': 'ProduKey.exe', 'Args': ['/external', '/ExtractEdition:1']}, diff --git a/WK/amd64/Notepad2/Notepad2.ini b/WK/amd64/Notepad2/Notepad2.ini deleted file mode 100644 index b5c75f87..00000000 --- a/WK/amd64/Notepad2/Notepad2.ini +++ /dev/null @@ -1,106 +0,0 @@ -[Notepad2] -[Settings] -SaveSettings=1 -SaveRecentFiles=0 -SaveFindReplace=0 -CloseFind=0 -CloseReplace=0 -NoFindWrap=0 -OpenWithDir=%SystemDrive%\WK\Tools\.bin\Notepad2 -Favorites=%SystemDrive%\WK\Tools\.bin\Notepad2 -PathNameFormat=2 -WordWrap=1 -WordWrapMode=0 -WordWrapIndent=0 -WordWrapSymbols=22 -ShowWordWrapSymbols=0 -MatchBraces=1 -AutoCloseTags=0 -HighlightCurrentLine=1 -AutoIndent=1 -AutoCompleteWords=0 -ShowIndentGuides=0 -TabsAsSpaces=1 -TabIndents=1 -BackspaceUnindents=1 -TabWidth=4 -IndentWidth=0 -MarkLongLines=1 -LongLinesLimit=80 -LongLineMode=1 -ShowSelectionMargin=0 -ShowLineNumbers=1 -ShowCodeFolding=1 -MarkOccurrences=2 -MarkOccurrencesMatchCase=0 -MarkOccurrencesMatchWholeWords=0 -ViewWhiteSpace=0 -ViewEOLs=0 -DefaultEncoding=3 -SkipUnicodeDetection=0 -LoadASCIIasUTF8=0 -LoadNFOasOEM=1 -NoEncodingTags=0 -DefaultEOLMode=0 -FixLineEndings=0 -FixTrailingBlanks=0 -PrintHeader=1 -PrintFooter=0 -PrintColorMode=3 -PrintZoom=10 -PrintMarginLeft=1000 -PrintMarginTop=1000 -PrintMarginRight=1000 -PrintMarginBottom=1000 -SaveBeforeRunningTools=1 -FileWatchingMode=1 -ResetFileWatching=0 -EscFunction=2 -AlwaysOnTop=0 -MinimizeToTray=0 -TransparentMode=0 -ToolbarButtons=1 2 4 0 5 6 0 7 8 9 0 10 11 0 12 0 24 0 13 14 0 15 0 17 -ShowToolbar=1 -ShowStatusbar=1 -EncodingDlgSizeX=256 -EncodingDlgSizeY=262 -RecodeDlgSizeX=256 -RecodeDlgSizeY=262 -FileMRUDlgSizeX=412 -FileMRUDlgSizeY=376 -OpenWithDlgSizeX=384 -OpenWithDlgSizeY=386 -FavoritesDlgSizeX=334 -FavoritesDlgSizeY=316 -FindReplaceDlgPosX=0 -FindReplaceDlgPosY=0 -[Settings2] -SingleFileInstance=1 -ShellAppUserModelID=Notepad2 -ShellUseSystemMRU=1 -[Recent Files] -[Recent Find] -[Recent Replace] -[Custom Colors] -01=#000000 -02=#0A246A -03=#3A6EA5 -04=#003CE6 -05=#006633 -06=#608020 -07=#648000 -08=#A46000 -09=#FFFFFF -10=#FFFFE2 -11=#FFF1A8 -12=#FFC000 -13=#FF4000 -14=#C80000 -15=#B000B0 -16=#B28B40 -[Styles] -Use2ndDefaultStyle=0 -DefaultScheme=0 -AutoSelect=1 -SelectDlgSizeX=304 -SelectDlgSizeY=324 diff --git a/WK/amd64/NotepadPlusPlus/config.xml b/WK/amd64/NotepadPlusPlus/config.xml new file mode 100644 index 00000000..3a88a83e --- /dev/null +++ b/WK/amd64/NotepadPlusPlus/config.xml @@ -0,0 +1,56 @@ + + + + + + standard + hide + + vertical + hide + + no + yes + no + no + yes + yes + no + yes + + + + + yes + yes + 2 + + + + + + hide + + + + + + + + + + yes + + + + + + + + + + + + + + diff --git a/WK/x86/Notepad2/Notepad2.ini b/WK/x86/Notepad2/Notepad2.ini deleted file mode 100644 index b5c75f87..00000000 --- a/WK/x86/Notepad2/Notepad2.ini +++ /dev/null @@ -1,106 +0,0 @@ -[Notepad2] -[Settings] -SaveSettings=1 -SaveRecentFiles=0 -SaveFindReplace=0 -CloseFind=0 -CloseReplace=0 -NoFindWrap=0 -OpenWithDir=%SystemDrive%\WK\Tools\.bin\Notepad2 -Favorites=%SystemDrive%\WK\Tools\.bin\Notepad2 -PathNameFormat=2 -WordWrap=1 -WordWrapMode=0 -WordWrapIndent=0 -WordWrapSymbols=22 -ShowWordWrapSymbols=0 -MatchBraces=1 -AutoCloseTags=0 -HighlightCurrentLine=1 -AutoIndent=1 -AutoCompleteWords=0 -ShowIndentGuides=0 -TabsAsSpaces=1 -TabIndents=1 -BackspaceUnindents=1 -TabWidth=4 -IndentWidth=0 -MarkLongLines=1 -LongLinesLimit=80 -LongLineMode=1 -ShowSelectionMargin=0 -ShowLineNumbers=1 -ShowCodeFolding=1 -MarkOccurrences=2 -MarkOccurrencesMatchCase=0 -MarkOccurrencesMatchWholeWords=0 -ViewWhiteSpace=0 -ViewEOLs=0 -DefaultEncoding=3 -SkipUnicodeDetection=0 -LoadASCIIasUTF8=0 -LoadNFOasOEM=1 -NoEncodingTags=0 -DefaultEOLMode=0 -FixLineEndings=0 -FixTrailingBlanks=0 -PrintHeader=1 -PrintFooter=0 -PrintColorMode=3 -PrintZoom=10 -PrintMarginLeft=1000 -PrintMarginTop=1000 -PrintMarginRight=1000 -PrintMarginBottom=1000 -SaveBeforeRunningTools=1 -FileWatchingMode=1 -ResetFileWatching=0 -EscFunction=2 -AlwaysOnTop=0 -MinimizeToTray=0 -TransparentMode=0 -ToolbarButtons=1 2 4 0 5 6 0 7 8 9 0 10 11 0 12 0 24 0 13 14 0 15 0 17 -ShowToolbar=1 -ShowStatusbar=1 -EncodingDlgSizeX=256 -EncodingDlgSizeY=262 -RecodeDlgSizeX=256 -RecodeDlgSizeY=262 -FileMRUDlgSizeX=412 -FileMRUDlgSizeY=376 -OpenWithDlgSizeX=384 -OpenWithDlgSizeY=386 -FavoritesDlgSizeX=334 -FavoritesDlgSizeY=316 -FindReplaceDlgPosX=0 -FindReplaceDlgPosY=0 -[Settings2] -SingleFileInstance=1 -ShellAppUserModelID=Notepad2 -ShellUseSystemMRU=1 -[Recent Files] -[Recent Find] -[Recent Replace] -[Custom Colors] -01=#000000 -02=#0A246A -03=#3A6EA5 -04=#003CE6 -05=#006633 -06=#608020 -07=#648000 -08=#A46000 -09=#FFFFFF -10=#FFFFE2 -11=#FFF1A8 -12=#FFC000 -13=#FF4000 -14=#C80000 -15=#B000B0 -16=#B28B40 -[Styles] -Use2ndDefaultStyle=0 -DefaultScheme=0 -AutoSelect=1 -SelectDlgSizeX=304 -SelectDlgSizeY=324 diff --git a/WK/x86/NotepadPlusPlus/config.xml b/WK/x86/NotepadPlusPlus/config.xml new file mode 100644 index 00000000..3a88a83e --- /dev/null +++ b/WK/x86/NotepadPlusPlus/config.xml @@ -0,0 +1,56 @@ + + + + + + standard + hide + + vertical + hide + + no + yes + no + no + yes + yes + no + yes + + + + + yes + yes + 2 + + + + + + hide + + + + + + + + + + yes + + + + + + + + + + + + + + diff --git a/make.cmd b/make.cmd index c12fb6d0..1e47ff46 100644 --- a/make.cmd +++ b/make.cmd @@ -112,7 +112,7 @@ for %%a in (amd64 x86) do ( rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" rem Add Drivers - dism /add-driver /image:"!mount!" /driver:"!drivers!" /recurse /logpath:"dism.log" + REM dism /add-driver /image:"!mount!" /driver:"!drivers!" /recurse /logpath:"dism.log" rem Force RamDisk size to try and avoid capture-image errors dism /image:"!mount!" /set-scratchspace:512 @@ -142,7 +142,7 @@ for %%a in (amd64 x86) do ( reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip;%%SystemDrive%%\WK\python;%%SystemDrive%%\WK\wimlib" /f rem Replace Notepad - reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod.exe /z" /f + reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\NotepadPlusPlus\notepadplusplus.exe /z" /f rem Unload registry hives reg unload HKLM\WinPE-SW From 1e41954f623e9e322ae434da8fb29f34703973d8 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Sun, 26 Nov 2017 14:15:09 -0800 Subject: [PATCH 17/85] Added Build PE.cmd launch script * Checks for elevation and relaunches script if necessary * Checks for WADK installation and loads DandISetEnv.bat * This sets the proper variables * Runs PowerShell in the same window to preserve DandI vars --- .bin/Scripts/build_pe.ps1 | 71 ++++++++++++++++++++++++ .gitignore | 8 ++- Build PE.cmd | 113 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 .bin/Scripts/build_pe.ps1 create mode 100644 Build PE.cmd diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 new file mode 100644 index 00000000..1c819ecb --- /dev/null +++ b/.bin/Scripts/build_pe.ps1 @@ -0,0 +1,71 @@ +# Wizard Kit: Windows PE Build Tool + +## Init ## +#Requires -Version 3.0 +#Requires -RunAsAdministrator +clear +$host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" +$wd = $(Split-Path $MyInvocation.MyCommand.Path) +$bin = (Get-Item $wd -Force).Parent.FullName +$root = (Get-Item $bin -Force).Parent.FullName +$tmp = "{0}\tmp" -f $bin +$errors = 0 +pushd "$wd" +$host.UI.RawUI.BackgroundColor = "black" +$host.UI.RawUI.ForegroundColor = "white" +$progressPreference = 'silentlyContinue' +# clear +foreach ($v in @('SystemDrive', 'USERPROFILE', 'DISMRoot', 'BCDBootRoot', 'ImagingRoot', 'OSCDImgRoot', 'WdsmcastRoot')) { + write-host ('{0}: {1}' -f $v, (gci env:$v).value) +} +write-host "" +write-host ("wd: {0}" -f $wd) +write-host ("bin: {0}" -f $bin) +write-host ("root: {0}" -f $root) +write-host ("tmp: {0}" -f $tmp) +read-host "Bananas?" +exit + +## Functions ## +function download-file { + param ([String]$path, [String]$name, [String]$url) + $outfile = "{0}\{1}" -f $path, $name + + Write-Host ("Downloading: {0}" -f $name) + New-Item -Type Directory $path 2>&1 | Out-Null + try { + invoke-webrequest -uri $url -outfile $outfile + } + catch { + Write-Host (" ERROR: Failed to download file." ) -foregroundcolor "Red" + $errors += 1 + } +} +function find-dynamic-url { + param ([String]$source_page, [String]$regex) + $d_url = "" + + # Get source page + invoke-webrequest -uri $source_page -outfile "tmp_page" + + # Search for real url + $d_url = Get-Content "tmp_page" | Where-Object {$_ -imatch $regex} + $d_url = $d_url -ireplace '.*(a |)href="([^"]+)".*', '$2' + $d_url = $d_url -ireplace ".*(a |)href='([^']+)'.*", '$2' + + # Remove tmp_page + Remove-Item "tmp_page" + + return $d_url +} +function wk_pause { + param([string]$message = "Press Enter to continue... ") + Write-Host $message + $x = read-host +} + +## Build ## +# TODO # + +## Done ## +popd diff --git a/.gitignore b/.gitignore index 8d6f5fbe..28435552 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ -*iso +*.bak +*.iso +.bin/Scripts/__pycache__ +.bin/tmp +Drivers +Logs Scripts/__pycache__ -dism* mount pe_files \ No newline at end of file diff --git a/Build PE.cmd b/Build PE.cmd new file mode 100644 index 00000000..49b04d4a --- /dev/null +++ b/Build PE.cmd @@ -0,0 +1,113 @@ +:: Wizard Kit: Windows PE Build Tool Launcher :: + +@echo off + +:Init +setlocal EnableDelayedExpansion +title Wizard Kit: Windows PE Build Tool +call :CheckFlags %* +call :CheckElevation || goto Exit +call :FindKitsRoot || goto ErrorKitNotFound +set "dandi_set_env=%adk_root%\Deployment Tools\DandISetEnv.bat" +set "ps_script=%~dp0\.bin\Scripts\build_pe.ps1" + +:LaunchPrep +rem Verify scripts exists +if not exist "%dandi_set_env%" (goto ErrorKitNotFound) +if not exist "%ps_script%" (goto ErrorPSScriptMissing) +call "%dandi_set_env%" || goto ErrorUnknown + +:Launch +PowerShell -ExecutionPolicy bypass -File %ps_script%" +goto Exit + +:: Functions :: +:CheckElevation +rem Code based on StackOverflow comments +rem Question: https://stackoverflow.com/q/4051883 +rem Using answer: https://stackoverflow.com/a/21295806 +rem Asked by: https://stackoverflow.com/users/272237/flacs +rem Edited by: https://stackoverflow.com/users/330315/a-horse-with-no-name +rem Answer by: https://stackoverflow.com/users/3198799/and31415 +fsutil dirty query %systemdrive% >nul +if %errorlevel% neq 0 ( + call :RequestElevation + rem reset errorlevel to 1 to abort the current non-elevated script + color 00 +) +@exit /b %errorlevel% + +:CheckFlags +rem Loops through all arguments to check for accepted flags +set DEBUG= +for %%f in (%*) do ( + if /i "%%f" == "/DEBUG" (@echo on & set "DEBUG=/DEBUG") +) +@exit /b 0 + +:FindKitsRoot +set "adk_root=" +set "found=" +set "r_vname=KitsRoot10" + +rem Check registry for WADK +set "r_path=HKLM\Software\Wow6432Node\Microsoft\Windows Kits\Installed Roots" +reg query "%r_path%" /v %r_vname% >nul 2>&1 && set "found=True" +if not defined found ( + rem 32-bit systems? + set "r_path=HKLM\Software\Microsoft\Windows Kits\Installed Roots" + reg query "!r_path!" /v %r_vname% >nul 2>&1 && set "found=True" +) +for /f "skip=2 tokens=2*" %%i in ('reg query "%r_path%" /v %r_vname%') do ( + set adk_root=%%j\Assessment and Deployment Kit +) +rem Set errorlevel if necessary +if not defined adk_root color 00 +if not defined found color 00 +@exit /b %errorlevel% + +:RequestElevation +set "cscript=%systemroot%\system32\cscript.exe" +set "vb_script=.bin\tmp\Elevate.vbs" +mkdir ".bin\tmp" 2>nul + +rem Create VB script +echo Set UAC = CreateObject^("Shell.Application"^) > "%vb_script%" +echo UAC.ShellExecute "%~s0", "", "", "runas", 3 >> "%vb_script%" + +rem Run +"%cscript%" //nologo "%vb_script%" || goto ErrorUnknown +del "%vb_script%" +@exit /b 0 + +:: Errors :: +:ErrorKitNotFound +echo. +echo ERROR: Windows ADK installation not found. +goto Abort + +:ErrorPSScriptMissing +echo. +echo ERROR: build_pe.ps1 script not found. +goto Abort + +:ErrorUnknown +echo. +echo ERROR: Encountered an unknown error. +goto Abort + +:Abort +color 4e +echo Aborted. +echo. +echo Press any key to exit... +pause>nul +color +rem Set errorlevel to 1 by calling color incorrectly +color 00 +goto Exit + +:: Cleanup and exit :: +:Exit +endlocal +exit /b %errorlevel% From 87ac27b5cca080dbaee2d5d79d770f72d2155caa Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Sun, 26 Nov 2017 14:42:27 -0800 Subject: [PATCH 18/85] Moving to a new style guide for PowerShell scripts Using this: https://poshcode.gitbooks.io/powershell-practice-and-style/ --- .bin/Scripts/build_pe.ps1 | 82 +++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 1c819ecb..de687894 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -3,69 +3,69 @@ ## Init ## #Requires -Version 3.0 #Requires -RunAsAdministrator -clear -$host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" -$wd = $(Split-Path $MyInvocation.MyCommand.Path) -$bin = (Get-Item $wd -Force).Parent.FullName -$root = (Get-Item $bin -Force).Parent.FullName -$tmp = "{0}\tmp" -f $bin -$errors = 0 -pushd "$wd" -$host.UI.RawUI.BackgroundColor = "black" -$host.UI.RawUI.ForegroundColor = "white" -$progressPreference = 'silentlyContinue' -# clear -foreach ($v in @('SystemDrive', 'USERPROFILE', 'DISMRoot', 'BCDBootRoot', 'ImagingRoot', 'OSCDImgRoot', 'WdsmcastRoot')) { - write-host ('{0}: {1}' -f $v, (gci env:$v).value) +Clear-Host +$Host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" +$WD = $(Split-Path $MyInvocation.MyCommand.Path) +$Bin = (Get-Item $WD -Force).Parent.FullName +$Root = (Get-Item $Bin -Force).Parent.FullName +$Temp = "{0}\tmp" -f $Bin +$Errors = 0 +Push-Location "$WD" +$Host.UI.RawUI.BackgroundColor = "black" +$Host.UI.RawUI.ForegroundColor = "white" +$ProgressPreference = 'silentlyContinue' +# Clear-Host +foreach ($Var in @('SystemDrive', 'USERPROFILE', 'DISMRoot', 'BCDBootRoot', 'ImagingRoot', 'OSCDImgRoot', 'WdsmcastRoot')) { + Write-Host ('{0}: {1}' -f $Var, (Get-ChildItem Env:$Var).Value) } -write-host "" -write-host ("wd: {0}" -f $wd) -write-host ("bin: {0}" -f $bin) -write-host ("root: {0}" -f $root) -write-host ("tmp: {0}" -f $tmp) -read-host "Bananas?" +Write-Host "" +Write-Host ("wd: {0}" -f $WD) +Write-Host ("bin: {0}" -f $Bin) +Write-Host ("root: {0}" -f $Root) +Write-Host ("tmp: {0}" -f $Temp) +Read-Host "Bananas?" exit ## Functions ## -function download-file { - param ([String]$path, [String]$name, [String]$url) - $outfile = "{0}\{1}" -f $path, $name +function Download-File { + param ([String]$Path, [String]$Name, [String]$Url) + $OutFile = "{0}\{1}" -f $Path, $Name - Write-Host ("Downloading: {0}" -f $name) - New-Item -Type Directory $path 2>&1 | Out-Null + Write-Host ("Downloading: {0}" -f $Name) + New-Item -Type Directory $Path 2>&1 | Out-Null try { - invoke-webrequest -uri $url -outfile $outfile + Invoke-Webrequest -Uri $Url -OutFile $OutFile } catch { - Write-Host (" ERROR: Failed to download file." ) -foregroundcolor "Red" - $errors += 1 + Write-Host (" ERROR: Failed to download file." ) -ForegroundColor "Red" + $Errors += 1 } } -function find-dynamic-url { - param ([String]$source_page, [String]$regex) - $d_url = "" +function Find-DynamicUrl { + param ([String]$SourcePage, [String]$RegEx) + $Url = "" # Get source page - invoke-webrequest -uri $source_page -outfile "tmp_page" + Invoke-Webrequest -Uri $SourcePage -OutFile "tmp_page" # Search for real url - $d_url = Get-Content "tmp_page" | Where-Object {$_ -imatch $regex} - $d_url = $d_url -ireplace '.*(a |)href="([^"]+)".*', '$2' - $d_url = $d_url -ireplace ".*(a |)href='([^']+)'.*", '$2' + $Url = Get-Content "tmp_page" | Where-Object {$_ -imatch $RegEx} + $Url = $Url -ireplace '.*(a |)href="([^"]+)".*', '$2' + $Url = $Url -ireplace ".*(a |)href='([^']+)'.*", '$2' # Remove tmp_page Remove-Item "tmp_page" - return $d_url + return $Url } -function wk_pause { - param([string]$message = "Press Enter to continue... ") - Write-Host $message - $x = read-host +function WK-Pause { + param([string]$Message = "Press Enter to continue... ") + Write-Host $Message + Read-Host } ## Build ## # TODO # ## Done ## -popd +Pop-Location From 7b12a8ca91c6060a45598b4091e18ef4b3e5cc28 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 16:03:51 -0800 Subject: [PATCH 19/85] Merged tool settings Extra files for the tools are now stored in WK\_include and copied into place during the build. --- WK/{amd64 => _include}/CPU-Z/cpuz.ini | 0 WK/{amd64 => _include}/ConEmu/ConEmu.xml | 0 .../HWiNFO/HWiNFO.INI} | 0 .../NotepadPlusPlus/config.xml | 0 WK/_include/NotepadPlusPlus/npp.vbs | 33 + WK/{x86 => _include}/Q-Dir/Q-Dir.ini | 1 - WK/amd64/HWiNFO/HWiNFO64.INI | 209 ----- WK/amd64/Q-Dir/Q-Dir.ini | 69 -- WK/x86/CPU-Z/cpuz.ini | 20 - WK/x86/ConEmu/ConEmu.xml | 765 ------------------ WK/x86/NotepadPlusPlus/config.xml | 56 -- 11 files changed, 33 insertions(+), 1120 deletions(-) rename WK/{amd64 => _include}/CPU-Z/cpuz.ini (100%) rename WK/{amd64 => _include}/ConEmu/ConEmu.xml (100%) rename WK/{x86/HWiNFO/HWiNFO32.INI => _include/HWiNFO/HWiNFO.INI} (100%) rename WK/{amd64 => _include}/NotepadPlusPlus/config.xml (100%) create mode 100644 WK/_include/NotepadPlusPlus/npp.vbs rename WK/{x86 => _include}/Q-Dir/Q-Dir.ini (99%) delete mode 100644 WK/amd64/HWiNFO/HWiNFO64.INI delete mode 100644 WK/amd64/Q-Dir/Q-Dir.ini delete mode 100644 WK/x86/CPU-Z/cpuz.ini delete mode 100644 WK/x86/ConEmu/ConEmu.xml delete mode 100644 WK/x86/NotepadPlusPlus/config.xml diff --git a/WK/amd64/CPU-Z/cpuz.ini b/WK/_include/CPU-Z/cpuz.ini similarity index 100% rename from WK/amd64/CPU-Z/cpuz.ini rename to WK/_include/CPU-Z/cpuz.ini diff --git a/WK/amd64/ConEmu/ConEmu.xml b/WK/_include/ConEmu/ConEmu.xml similarity index 100% rename from WK/amd64/ConEmu/ConEmu.xml rename to WK/_include/ConEmu/ConEmu.xml diff --git a/WK/x86/HWiNFO/HWiNFO32.INI b/WK/_include/HWiNFO/HWiNFO.INI similarity index 100% rename from WK/x86/HWiNFO/HWiNFO32.INI rename to WK/_include/HWiNFO/HWiNFO.INI diff --git a/WK/amd64/NotepadPlusPlus/config.xml b/WK/_include/NotepadPlusPlus/config.xml similarity index 100% rename from WK/amd64/NotepadPlusPlus/config.xml rename to WK/_include/NotepadPlusPlus/config.xml diff --git a/WK/_include/NotepadPlusPlus/npp.vbs b/WK/_include/NotepadPlusPlus/npp.vbs new file mode 100644 index 00000000..3fb12a41 --- /dev/null +++ b/WK/_include/NotepadPlusPlus/npp.vbs @@ -0,0 +1,33 @@ +'// DISCLAIMER +'// THIS COMES WITH NO WARRANTY, IMPLIED OR OTHERWISE. USE AT YOUR OWN RISK +'// IF YOU ARE NOT COMFORTABLE EDITING THE REGISTRY THEN DO NOT USE THIS SCRIPT +'// +'// NOTES: +'// This affects all users. +'// This will prevent ANY executable named notepad.exe from running located anywhere on this computer!! +'// +'// Save this text to your notepad++ folder as a text file named npp.vbs (some AV don't like vbs, get a different AV :-P ) +'// +'// USAGE +'// 1) +'// Navigate to registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ +'// +' // 2) +'// Add new subkey called notepad.exe +'// This step is what tells windows to use the notepad++ exe, to undo simply delete this key +'// +'// 3) +'// Create new Sting Value called Debugger +'// +'// 4) +'// Modify value and enter wscript.exe "path to npp.vbs" e.g. wscript.exe "C:\Program Files\Notepad++\npp.vbs" + +Option Explicit +Dim sCmd, x +sCmd = """" & LeftB(WScript.ScriptFullName, LenB(WScript.ScriptFullName) - LenB(WScript.ScriptName)) & "notepad++.exe" & """ """ +For x = 1 To WScript.Arguments.Count - 1 + sCmd = sCmd & WScript.Arguments(x) & " " +Next +sCmd = sCmd & """" +CreateObject("WScript.Shell").Run sCmd, 1, True +WScript.Quit \ No newline at end of file diff --git a/WK/x86/Q-Dir/Q-Dir.ini b/WK/_include/Q-Dir/Q-Dir.ini similarity index 99% rename from WK/x86/Q-Dir/Q-Dir.ini rename to WK/_include/Q-Dir/Q-Dir.ini index 18f44d38..ac926a8c 100644 --- a/WK/x86/Q-Dir/Q-Dir.ini +++ b/WK/_include/Q-Dir/Q-Dir.ini @@ -4,7 +4,6 @@ QDir_Id=0 useColorStart=1 Als=12 designe_mode=2 -WinRC=8;15;968;689 showCmd=3 StartCrash=0 default_tab= diff --git a/WK/amd64/HWiNFO/HWiNFO64.INI b/WK/amd64/HWiNFO/HWiNFO64.INI deleted file mode 100644 index 23133936..00000000 --- a/WK/amd64/HWiNFO/HWiNFO64.INI +++ /dev/null @@ -1,209 +0,0 @@ -[LogfileSettings] -COMP=1 -COMP_SP=1 -COMP_Name=1 -COMP_Os=1 -COMP_User=0 -CPU=1 -CPU_Name=1 -CPU_ID=1 -CPU_Vendor=1 -CPU_Stepping=1 -CPU_Type=1 -CPU_BrandID=1 -CPU_PN=1 -CPU_Clock=1 -CPU_MaxFreq=1 -CPU_CacheL1=1 -CPU_CacheL2=1 -CPU_TLB_I=1 -CPU_TLB_D=1 -CPU_Features=1 -CPU_PIROM=1 -MEM=1 -MEM_TotalSize=1 -MEM_Timing=1 -MEM_Row=1 -MEM_Row_Size=1 -MEM_Row_Type=1 -MEM_Row_Speed=1 -MEM_Row_Model=1 -MEM_Row_ECC=1 -MEM_Row_Date=1 -MEM_Row_SN=1 -MEM_Row_Cfg=1 -MEM_Row_Latency=1 -MEM_Row_Features=1 -MEM_Row_iFeatures=1 -BUS=1 -BUS_PCI=1 -BUS_PCI_DevName=1 -BUS_PCI_DevNumber=1 -BUS_PCI_Resources=1 -BUS_PCI_Features=1 -BUS_PCI_DevSpecific=1 -BUS_PCIX_Features=1 -BUS_PCIe_Features=1 -BUS_PCI_DRV_INFO=1 -BUS_EISA=1 -DMI=1 -DMI_0=1 -DMI_1=1 -DMI_2=1 -DMI_3=1 -DMI_4=1 -DMI_5=1 -DMI_6=1 -DMI_7=1 -DMI_8=1 -DMI_9=1 -DMI_10=1 -DMI_11=1 -DMI_12=1 -DMI_13=1 -DMI_14=1 -DMI_15=1 -DMI_16=1 -DMI_17=1 -DMI_18=1 -DMI_19=1 -DMI_20=1 -DMI_21=1 -DMI_22=1 -DMI_23=1 -DMI_24=1 -DMI_25=1 -DMI_26=1 -DMI_27=1 -DMI_28=1 -DMI_29=1 -DMI_30=1 -DMI_31=1 -DMI_32=1 -DMI_33=1 -DMI_34=1 -DMI_35=1 -DMI_36=1 -DMI_37=1 -DMI_38=1 -DMI_39=1 -DMI_129=1 -DMI_130=1 -DMI_131=1 -VIDEO=1 -VIDEO_Chipset=1 -VIDEO_Memory=1 -VIDEO_Card=1 -VIDEO_Bus=1 -VIDEO_RAMDAC=1 -VIDEO_BIOSver=1 -VIDEO_Clock=1 -VIDEO_HWID=1 -VIDEO_DRV_INFO=1 -VIDEO_DirectX=1 -MON=1 -MON_Name=1 -MON_SN=1 -MON_Date=1 -MON_Dimensions=1 -MON_DisplayType=1 -MON_InputSignal=1 -MON_Gamma=1 -MON_DPMSinput=1 -MON_DPMSmodes=1 -MOBO=1 -MOBO_Model=1 -MOBO_Chipset=1 -MOBO_CompName=1 -MOBO_MachineType=1 -MOBO_Slots=1 -MOBO_BIOS_Manuf=1 -MOBO_BIOS_Date=1 -MOBO_PNP_Devs=1 -MOBO_PNP_Nodes=1 -MOBO_ACPI_Devs=1 -MOBO_ACPI_Enum=1 -DRIVE=1 -DRIVE_IDE=1 -DRIVE_IDE_Ctrller=1 -DRIVE_IDE_Channel=1 -DRIVE_IDE_Model=1 -DRIVE_IDE_Rev=1 -DRIVE_IDE_SN=1 -DRIVE_IDE_Capacity=1 -DRIVE_IDE_Geometry=1 -DRIVE_IDE_Cache=1 -DRIVE_IDE_Xfer=1 -DRIVE_IDE_BasicCapab=1 -DRIVE_IDE_ATA2Capab=1 -DRIVE_IDE_SMART=1 -DRIVE_SCSI=1 -DRIVE_SCSI_ID=1 -DRIVE_SCSI_Desc=1 -DRIVE_SCSI_Class=1 -DRIVE_Floppy=1 -NETWORK=1 -NETWORK_HWID=1 -NETWORK_DRV_INFO=1 -AUDIO=1 -AUDIO_DRV_INFO=1 -AUDIO_HWID=1 -PORTS=1 -BUS_USB=1 -BUS_USB_DRV_INFO=1 -BATTERY=1 -SENSORS=1 - -[Settings] -HighestIdeAddress=0 -AcpiEnum=0 -SWSMI=1 -DebugMode=0 -SMBus=1 -TempScale=C -AC97CodecID=1 -SkipProblematicPciDev=0 -GPUI2C=1 -LPC=1 -DefReportType=5 -TPM=0 -PCIdirect=1 -OpenSystemSummary=0 -RememberPreferences=1 -LargeFonts=0 -OpenSensors=0 -MinimalizeMainWnd=0 -MinimalizeSensors=0 -PersistentDriver=0 -UseHPET=1 -AutoUpdate=0 -GPUI2CNVAPI=1 -GPUI2CADL=0 -SensorsOnly=0 -AcpiEval=1 -CpuClkFromBusClk=1 -BusClkPolling=1 -SMBusAdrExclude=11111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 -GPUI2CBusExclude=00000000 -SensorsSM=1 -IoctlKernel=0 -SummaryOnly=0 -WakeGPUs=1 -KeepTheme=0 -FlushBuffers=1 -iMEsupport=1 -GPUI2Ccaching=1 -CSMI_SAS_Support=1 -DebugDirect=1 -MinimalizeSensorsClose=0 -WakeGPUsExt=0 -PollSleepingGPUs=0 -ShowWelcomeAndProgress=1 -EnablePchTherm=0 -ReorderGPUs=1 -NvmlSupport=1 -DecimalSeparator=. -ThousandsSeparator=, -CsvSeparator=, -MinimizeGraphs=1 -TextButtons=0 diff --git a/WK/amd64/Q-Dir/Q-Dir.ini b/WK/amd64/Q-Dir/Q-Dir.ini deleted file mode 100644 index f6532f37..00000000 --- a/WK/amd64/Q-Dir/Q-Dir.ini +++ /dev/null @@ -1,69 +0,0 @@ -[Start] -m_lang_id=1 -QDir_Id=0 -useColorStart=1 -Als=12 -designe_mode=2 -WinRC=66;87;1026;761 -showCmd=3 -StartCrash=0 -default_tab= -Max=1 -show_ext_in_type=1 -title_info=1 -adresbar_style=1 -useTreeColor=1 -useColor=1 -[Favoriten] -Ordner=.\Favoriten\ -[Q] -Link=.\Favoriten\Quick-Link\ -[Q-Dir] -Lizenz=1 - - - - - -[Vorschau] -Filter=*.avi;*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.mp*;*.pdf;*.png;*.wm*; -[Filter2] -0=#Hidden=1=-1=1=1=-1=0 -1=*.zip;*.rar;*.gz;*.7z;=1=00AA00=-1=1=-1=0 -2=*.mp*;*.avi;*.wma;=1=DD0058=-1=1=-1=0 -3=#DIR=1=008800=-1=1=-1=0 -4=*.jpg;*.jpeg;*.png,*.gif;*.bmp;*.ico=1=BB00BB=-1=1=-1=0 -5=*.html;*.htm;*.url=1=456789=-1=1=-1=0 -6=*.pl;*.cgi;*.php;*.pdf;*.doc;*.rtf;*.xls=1=BB8844=-1=1=-1=0 -7=*.cpp;*.hpp;*.h=1=DD0058=-1=1=-1=0 -8=*.exe;*.dll;*.bat=1=FF0000=-1=1=-1=0 -9=*=1=0000BB=-1=1=-1=0 -10=#BG=1=-1=-1=1=-1=0 -11=#BG-A=1=-1=-1=1=-1=0 -[Ordner] -Filter= -[Column_OS_6.1_Ploder1] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -Spatlen_291=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%00%00%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%EE%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0E%00%00%00%69%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%91%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0C%00%00%00%46%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%00%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-563719693|772 -[Column_OS_6.1_Ploder2] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Column_OS_6.1_Ploder3] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Column_OS_6.1_Ploder4] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Programs_State] -Disable=0 -[Quick-Links] -WK=%systemdrive%/WK -[Options] -Start=7 -[X-Size] -mode=1 -dig=0 -fld_size=1 -ths_sep=1 -type=0 -precent=1 -ff_cnt=1 -block_no_focus=1 -nosort_fld_size=1 diff --git a/WK/x86/CPU-Z/cpuz.ini b/WK/x86/CPU-Z/cpuz.ini deleted file mode 100644 index e10ce749..00000000 --- a/WK/x86/CPU-Z/cpuz.ini +++ /dev/null @@ -1,20 +0,0 @@ -[CPU-Z] -VERSION=1.7.7.0 -TextFontName= -TextFontSize=14 -TextFontColor=000080 -LabelFontName= -LabelFontSize=14 -ACPI=1 -PCI=1 -MaxPCIBus=256 -DMI=1 -Sensor=1 -SMBus=1 -Display=1 -UseDisplayAPI=1 -BusClock=1 -Chipset=1 -SPD=1 -XOC=0 -CheckUpdates=0 diff --git a/WK/x86/ConEmu/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml deleted file mode 100644 index 8a2049b9..00000000 --- a/WK/x86/ConEmu/ConEmu.xml +++ /dev/null @@ -1,765 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/x86/NotepadPlusPlus/config.xml b/WK/x86/NotepadPlusPlus/config.xml deleted file mode 100644 index 3a88a83e..00000000 --- a/WK/x86/NotepadPlusPlus/config.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - standard - hide - - vertical - hide - - no - yes - no - no - yes - yes - no - yes - - - - - yes - yes - 2 - - - - - - hide - - - - - - - - - - yes - - - - - - - - - - - - - - From 44514b2fefc843a91ca04ef47675db7e963aad92 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 16:05:44 -0800 Subject: [PATCH 20/85] Initial PowerShell rewrite done. --- .bin/Scripts/build_pe.ps1 | 229 +++++++++++++++++++++++++++++++++----- .gitignore | 2 +- 2 files changed, 201 insertions(+), 30 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index de687894..4d1570b8 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -2,33 +2,87 @@ ## Init ## #Requires -Version 3.0 -#Requires -RunAsAdministrator -Clear-Host +#Requires -RunAsAdministrator $Host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName $Root = (Get-Item $Bin -Force).Parent.FullName $Temp = "{0}\tmp" -f $Bin -$Errors = 0 -Push-Location "$WD" -$Host.UI.RawUI.BackgroundColor = "black" -$Host.UI.RawUI.ForegroundColor = "white" +$Host.UI.RawUI.BackgroundColor = "Black" +$Host.UI.RawUI.ForegroundColor = "White" $ProgressPreference = 'silentlyContinue' -# Clear-Host -foreach ($Var in @('SystemDrive', 'USERPROFILE', 'DISMRoot', 'BCDBootRoot', 'ImagingRoot', 'OSCDImgRoot', 'WdsmcastRoot')) { - Write-Host ('{0}: {1}' -f $Var, (Get-ChildItem Env:$Var).Value) -} -Write-Host "" -Write-Host ("wd: {0}" -f $WD) -Write-Host ("bin: {0}" -f $Bin) -Write-Host ("root: {0}" -f $Root) -Write-Host ("tmp: {0}" -f $Temp) -Read-Host "Bananas?" -exit +$SplitWindow = @() +$DISM = "{0}\DISM.exe" -f $Env:DISMRoot +$WinPEPackages = @( + "WinPE-EnhancedStorage.cab", + "WinPE-FMAPI.cab", + "WinPE-WMI.cab", + "WinPE-EnhancedStorage_en-us.cab", + "WinPE-WMI_en-us.cab" +) + # Install WinPE-WMI before you install WinPE-NetFX. + # "WinPE-NetFx.cab", + # "WinPE-NetFx_en-us.cab", + + # Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. + # "WinPE-Scripting.cab", + # "WinPE-Scripting_en-us.cab", + + # Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. + # "WinPE-PowerShell.cab", + # "WinPE-PowerShell_en-us.cab", + + # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. + # "WinPE-DismCmdlets.cab", + # "WinPE-DismCmdlets_en-us.cab", + + # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. + # "WinPE-SecureBootCmdlets.cab", + + # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. + # "WinPE-StorageWMI.cab", + # "WinPE-StorageWMI_en-us.cab", ## Functions ## -function Download-File { - param ([String]$Path, [String]$Name, [String]$Url) +function Ask-User ($text = "Kotaero") { + $text += " [Y/N]" + while ($true) { + $answer = read-host $text + if ($answer -imatch '^(y|yes)$') { + $answer = $true + break + } elseif ($answer -imatch '^(n|no|nope)$') { + $answer = $false + break + } + } + $answer +} +function Abort { + Write-Host -ForegroundColor "Red" "`nAborted." + WKPause "Press Enter to exit... " + exit +} +function MakeClean { + $Folders = @( + "$Root\Mount", + "$Root\PEFiles") + $Clean = $false + foreach ($f in $Folders) { + if (Test-Path $f) { + Write-Host -ForegroundColor "Yellow" ("Found: {0}" -f $f) + $Clean = $true + } + } + if (($Clean) -and (Ask-User "Delete the above folder(s)?")) { + foreach ($f in $Folders) { + if (Test-Path $f) { + Remove-Item -Path $f -Recurse -Force + } + } + } +} +function DownloadFile ($Path, $Name, $Url) { $OutFile = "{0}\{1}" -f $Path, $Name Write-Host ("Downloading: {0}" -f $Name) @@ -38,11 +92,9 @@ function Download-File { } catch { Write-Host (" ERROR: Failed to download file." ) -ForegroundColor "Red" - $Errors += 1 } } -function Find-DynamicUrl { - param ([String]$SourcePage, [String]$RegEx) +function FindDynamicUrl ($SourcePage, $RegEx) { $Url = "" # Get source page @@ -58,14 +110,133 @@ function Find-DynamicUrl { return $Url } -function WK-Pause { - param([string]$Message = "Press Enter to continue... ") - Write-Host $Message +function WKPause ($Message = "Press Enter to continue... ") { + Write-Host $Message -NoNewLine Read-Host } +function WKRun ($Cmd, $ArgumentList, [switch]$SplitWindow=$false) { + if (Test-Path Env:\ConEmuBuild) { + $ArgumentList += "-new_console:ns33V" + } + Start-Process $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait +} -## Build ## -# TODO # +## PowerShell equivalent of Python's "if __name__ == '__main__'" +# Code based on StackOverflow comments +# Question: https://stackoverflow.com/q/4693947 +# Using answer: https://stackoverflow.com/a/5582692 +# Asked by: https://stackoverflow.com/users/65164/mark-mascolino +# Answer by: https://stackoverflow.com/users/696808/bacon-bits +if ($MyInvocation.InvocationName -ne '.') { + Clear-Host + Write-Host "Wizard Kit: Windows PE Build Tool`n" + + ## Prep ## + Push-Location "$WD" + $Date = Get-Date -UFormat "%Y-%m-%d" + MakeClean + + ## Build ## + foreach ($Arch in @("amd64", "x86")) { + $Drivers = "$Root\Drivers\%arch" + $Mount = "$Root\Mount" + $PEFiles = "$Root\PEFiles\$arch" + + # Copy WinPE files + Write-Host "Copying files..." + $Cmd = ("{0}\copype.cmd" -f $Env:WinPERoot) + WKRun -Cmd $Cmd -ArgumentList @($Arch, $PEFiles) -SplitWindow + + # Remove unwanted items + foreach ($SubDir in @("media", "media\Boot", "media\EFI\Microsoft\Boot")) { + foreach ($Item in Get-ChildItem "$PEFiles\$SubDir") { + if ($Item.Name -inotmatch '^(boot|efi|en-us|sources|fonts|resources|bcd|memtest)') { + Remove-Item -Path $Item.FullName -Recurse -Force + } + } + } + + # Mount image + Write-Host "Mounting image..." + $ArgumentList = @( + "/Mount-Image", + "/ImageFile:'$PEFiles\media\sources\boot.wim'", + "/Index:1", + "/MountDir:'$Mount'" + ) + WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + + # Add packages + Write-Host "Adding packages..." + foreach ($Package in $WinPEPackages) { + $PackagePath = "{0}\{1}\WinPE_OCs" -f $Env:WinPERoot, $Arch + $ArgumentList = @( + "/Add-Package", + "/Image:'$Mount'", + "/PackagePath:'$PackagePath'" + ) + WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + } + + # Set RamDisk size + $ArgumentList = @("/Image:'$Mount'", "/Set-ScratchSpace:512") + WKRun -Cmd $DISM -ArgumentList $ArgumentList + + # Add WK tools + Write-Host "Copying tools..." + Copy-Item -Path "$Root\WK\$Arch" -Destination "$Mount\WK" -Recurse -Force + Copy-Item -Path "$Root\WK\_include\*" -Destination "$Mount\WK" -Recurse -Force + if ($Arch -eq "amd64") { + $DestIni = "$Mount\WK\HWiNFO\HWiNFO64.INI" + } else { + $DestIni = "$Mount\WK\HWiNFO\HWiNFO32.INI" + } + Move-Item -Path "$Root\WK\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force + Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\WK\ConEmu\ConEmu.jpg" -Recurse -Force + Copy-Item -Path "$Root\Scripts" -Destination "$Mount\WK\Scripts" -Recurse -Force + + # Add System32 items + Copy-Item -Path "$Root\System32" -Destination "$Mount\Windows\System32" -Recurse -Force + $ArgumentList = @("/f", "$Mount\Windows\System32\winpe.jpg", "/a") + WKRun -Cmd "C:\Windows\System32\takeown.exe" -ArgumentList $ArgumentList + $ArgumentList = @("$Mount\Windows\System32\winpe.jpg", "/grant", "Administrators:F") + WKRun -Cmd "C:\Windows\System32\icacls.exe" -ArgumentList $ArgumentList + Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force + + # Update registry + Write-Host "Updating Registry..." + $Reg = "C:\Windows\System32\reg.exe" + WKRun -Cmd $Reg -ArgumentList @("load", "HKLM\WinPE-SW", "$Mount\Windows\System32\config\SOFTWARE") + WKRun -Cmd $Reg -ArgumentList @("load", "HKLM\WinPE-SYS", "$Mount\Windows\System32\config\SYSTEM") + + # Add 7-Zip and Python to path + $RegPath = "HKLM:\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" + $RegKey = Get-ItemProperty -Path $RegPath + $NewValue = "{0};%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" -f $RegKey.Path + Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force + + # Replace Notepad + $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" + $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' + New-Item -Path $RegPath -Force + New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force -## Done ## -Pop-Location + # Unload registry hives + Start-Sleep -Seconds 1 + WKRun -Cmd $Reg -ArgumentList @("unload", "HKLM\WinPE-SW") + WKRun -Cmd $Reg -ArgumentList @("unload", "HKLM\WinPE-SYS") + + # Unmount image + Write-Host "Dismounting image..." + $ArgumentList = @("/Unmount-Image", "/MountDir:'$Mount'", "/Commit") + WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + + # Create ISO + $ArgumentList = @("/iso", $PEFiles, "wk-winpe-$Date-$Arch.iso") + $Cmd = "{0}\MakeWinPEMedia.cmd" -f $Env:WinPERoot + WKRun -Cmd $Cmd -ArgumentList $ArgumentList -SplitWindow + } + + ## Done ## + Pop-Location +} diff --git a/.gitignore b/.gitignore index 28435552..c9141162 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,6 @@ .bin/tmp Drivers Logs +PEFiles/ Scripts/__pycache__ mount -pe_files \ No newline at end of file From 23b7dc89ca09900c898b04d6a1e1a339257a4474 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 18:09:30 -0800 Subject: [PATCH 21/85] Updated build_pe.ps1 --- .bin/Scripts/build_pe.ps1 | 58 ++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 4d1570b8..fff02e3d 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -3,6 +3,9 @@ ## Init ## #Requires -Version 3.0 #Requires -RunAsAdministrator +if (Test-Path Env:\DEBUG) { + Set-PSDebug -Trace 1 +} $Host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName @@ -10,7 +13,7 @@ $Root = (Get-Item $Bin -Force).Parent.FullName $Temp = "{0}\tmp" -f $Bin $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" -$ProgressPreference = 'silentlyContinue' +$ProgressPreference = "silentlyContinue" $SplitWindow = @() $DISM = "{0}\DISM.exe" -f $Env:DISMRoot $WinPEPackages = @( @@ -48,10 +51,10 @@ function Ask-User ($text = "Kotaero") { $text += " [Y/N]" while ($true) { $answer = read-host $text - if ($answer -imatch '^(y|yes)$') { + if ($answer -imatch "^(y|yes)$") { $answer = $true break - } elseif ($answer -imatch '^(n|no|nope)$') { + } elseif ($answer -imatch "^(n|no|nope)$") { $answer = $false break } @@ -102,8 +105,8 @@ function FindDynamicUrl ($SourcePage, $RegEx) { # Search for real url $Url = Get-Content "tmp_page" | Where-Object {$_ -imatch $RegEx} - $Url = $Url -ireplace '.*(a |)href="([^"]+)".*', '$2' - $Url = $Url -ireplace ".*(a |)href='([^']+)'.*", '$2' + $Url = $Url -ireplace '.*(a |)href="([^"]+)".*', "$2" + $Url = $Url -ireplace ".*(a |)href='([^']+)'.*", "$2" # Remove tmp_page Remove-Item "tmp_page" @@ -114,11 +117,15 @@ function WKPause ($Message = "Press Enter to continue... ") { Write-Host $Message -NoNewLine Read-Host } -function WKRun ($Cmd, $ArgumentList, [switch]$SplitWindow=$false) { - if (Test-Path Env:\ConEmuBuild) { - $ArgumentList += "-new_console:ns33V" - } +function WKRun ($Cmd, $ArgumentList) { Start-Process $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait + # Write-Host ("Cmd: == {0} ==" -f $Cmd) + # Write-Host ("ArgumentList:") + # foreach ($a in $ArgumentList) { + # Write-Host ("`t == {0} ==" -f $a) + # } + # Write-Host ("Check: == {0} ==" -f $Check) + # Write-Host ("SplitWindow: == {0} ==" -f $SplitWindow) } ## PowerShell equivalent of Python's "if __name__ == '__main__'" @@ -127,7 +134,7 @@ function WKRun ($Cmd, $ArgumentList, [switch]$SplitWindow=$false) { # Using answer: https://stackoverflow.com/a/5582692 # Asked by: https://stackoverflow.com/users/65164/mark-mascolino # Answer by: https://stackoverflow.com/users/696808/bacon-bits -if ($MyInvocation.InvocationName -ne '.') { +if ($MyInvocation.InvocationName -ne ".") { Clear-Host Write-Host "Wizard Kit: Windows PE Build Tool`n" @@ -145,12 +152,12 @@ if ($MyInvocation.InvocationName -ne '.') { # Copy WinPE files Write-Host "Copying files..." $Cmd = ("{0}\copype.cmd" -f $Env:WinPERoot) - WKRun -Cmd $Cmd -ArgumentList @($Arch, $PEFiles) -SplitWindow + WKRun -Cmd $Cmd -ArgumentList @($Arch, $PEFiles) # Remove unwanted items foreach ($SubDir in @("media", "media\Boot", "media\EFI\Microsoft\Boot")) { foreach ($Item in Get-ChildItem "$PEFiles\$SubDir") { - if ($Item.Name -inotmatch '^(boot|efi|en-us|sources|fonts|resources|bcd|memtest)') { + if ($Item.Name -inotmatch "^(boot|efi|en-us|sources|fonts|resources|bcd|memtest)") { Remove-Item -Path $Item.FullName -Recurse -Force } } @@ -158,13 +165,14 @@ if ($MyInvocation.InvocationName -ne '.') { # Mount image Write-Host "Mounting image..." + New-Item -Path $Mount -ItemType "directory" -Force | Out-Null $ArgumentList = @( "/Mount-Image", - "/ImageFile:'$PEFiles\media\sources\boot.wim'", + ('/ImageFile:"{0}\media\sources\boot.wim"' -f $PEFiles), "/Index:1", - "/MountDir:'$Mount'" + ('/MountDir:"{0}"' -f $Mount) ) - WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + WKRun -Cmd $DISM -ArgumentList $ArgumentList # Add packages Write-Host "Adding packages..." @@ -172,14 +180,17 @@ if ($MyInvocation.InvocationName -ne '.') { $PackagePath = "{0}\{1}\WinPE_OCs" -f $Env:WinPERoot, $Arch $ArgumentList = @( "/Add-Package", - "/Image:'$Mount'", - "/PackagePath:'$PackagePath'" + ('/Image:"{0}"' -f $Mount), + ('/PackagePath:"{0}"' -f $PackagePath) ) - WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + WKRun -Cmd $DISM -ArgumentList $ArgumentList } # Set RamDisk size - $ArgumentList = @("/Image:'$Mount'", "/Set-ScratchSpace:512") + $ArgumentList = @( + ('/Image:"{0}"' -f $Mount), + "/Set-ScratchSpace:512" + ) WKRun -Cmd $DISM -ArgumentList $ArgumentList # Add WK tools @@ -228,13 +239,16 @@ if ($MyInvocation.InvocationName -ne '.') { # Unmount image Write-Host "Dismounting image..." - $ArgumentList = @("/Unmount-Image", "/MountDir:'$Mount'", "/Commit") - WKRun -Cmd $DISM -ArgumentList $ArgumentList -SplitWindow + $ArgumentList = @( + "/Unmount-Image", + ('/MountDir:"{0}"' -f $Mount), + "/Commit") + WKRun -Cmd $DISM -ArgumentList $ArgumentList # Create ISO $ArgumentList = @("/iso", $PEFiles, "wk-winpe-$Date-$Arch.iso") $Cmd = "{0}\MakeWinPEMedia.cmd" -f $Env:WinPERoot - WKRun -Cmd $Cmd -ArgumentList $ArgumentList -SplitWindow + WKRun -Cmd $Cmd -ArgumentList $ArgumentList } ## Done ## From 613f4eee376b1b1f42ba02041e33a16b401aa28c Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 20:24:04 -0800 Subject: [PATCH 22/85] build_pe.ps1 updated and working --- .bin/Scripts/build_pe.ps1 | 120 ++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index fff02e3d..621097f2 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -1,4 +1,4 @@ -# Wizard Kit: Windows PE Build Tool +# Wizard Kit: Windows PE Build Tool ## Init ## #Requires -Version 3.0 @@ -13,38 +13,55 @@ $Root = (Get-Item $Bin -Force).Parent.FullName $Temp = "{0}\tmp" -f $Bin $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" -$ProgressPreference = "silentlyContinue" +# $ProgressPreference = "silentlyContinue" $SplitWindow = @() -$DISM = "{0}\DISM.exe" -f $Env:DISMRoot $WinPEPackages = @( "WinPE-EnhancedStorage.cab", + "en-us\WinPE-EnhancedStorage_en-us.cab", "WinPE-FMAPI.cab", "WinPE-WMI.cab", - "WinPE-EnhancedStorage_en-us.cab", - "WinPE-WMI_en-us.cab" + "en-us\WinPE-WMI_en-us.cab" ) # Install WinPE-WMI before you install WinPE-NetFX. # "WinPE-NetFx.cab", - # "WinPE-NetFx_en-us.cab", + # "en-us\WinPE-NetFx_en-us.cab", # Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. # "WinPE-Scripting.cab", - # "WinPE-Scripting_en-us.cab", + # "en-us\WinPE-Scripting_en-us.cab", # Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. # "WinPE-PowerShell.cab", - # "WinPE-PowerShell_en-us.cab", + # "en-us\WinPE-PowerShell_en-us.cab", # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. # "WinPE-DismCmdlets.cab", - # "WinPE-DismCmdlets_en-us.cab", + # "en-us\WinPE-DismCmdlets_en-us.cab", # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. # "WinPE-SecureBootCmdlets.cab", # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. # "WinPE-StorageWMI.cab", - # "WinPE-StorageWMI_en-us.cab", + # "en-us\WinPE-StorageWMI_en-us.cab", + +## Fake DandISetEnv.bat ## +# $DVars = @( + # @("DISMRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM"), + # @("BCDBootRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\BCDBoot"), + # @("OSCDImgRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"), + # @("WdsmcastRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Wdsmcast"), + # @("HelpIndexerRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\HelpIndexer"), + # @("WSIMRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\WSIM"), + # @("WinPERoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment") +# ) +# foreach ($d in $DVars) { + # $varName = $d[0] + # $varValue = $d[1] + # Set-Item -Path Env:$varName -Value $varValue + # Set-Item -Path Env:PATH -Value ($Env:PATH + ";$varValue") +# } +$DISM = "{0}\DISM.exe" -f $Env:DISMRoot ## Functions ## function Ask-User ($text = "Kotaero") { @@ -117,16 +134,6 @@ function WKPause ($Message = "Press Enter to continue... ") { Write-Host $Message -NoNewLine Read-Host } -function WKRun ($Cmd, $ArgumentList) { - Start-Process $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait - # Write-Host ("Cmd: == {0} ==" -f $Cmd) - # Write-Host ("ArgumentList:") - # foreach ($a in $ArgumentList) { - # Write-Host ("`t == {0} ==" -f $a) - # } - # Write-Host ("Check: == {0} ==" -f $Check) - # Write-Host ("SplitWindow: == {0} ==" -f $SplitWindow) -} ## PowerShell equivalent of Python's "if __name__ == '__main__'" # Code based on StackOverflow comments @@ -135,10 +142,17 @@ function WKRun ($Cmd, $ArgumentList) { # Asked by: https://stackoverflow.com/users/65164/mark-mascolino # Answer by: https://stackoverflow.com/users/696808/bacon-bits if ($MyInvocation.InvocationName -ne ".") { - Clear-Host + # Clear-Host Write-Host "Wizard Kit: Windows PE Build Tool`n" ## Prep ## + try { + Import-Module -Name $Env:DISMRoot -ErrorAction "stop" + } + catch { + Write-Host -ForegroundColor "Red" "ERROR: Failed to load DISM CmdLet" + Abort + } Push-Location "$WD" $Date = Get-Date -UFormat "%Y-%m-%d" MakeClean @@ -152,7 +166,7 @@ if ($MyInvocation.InvocationName -ne ".") { # Copy WinPE files Write-Host "Copying files..." $Cmd = ("{0}\copype.cmd" -f $Env:WinPERoot) - WKRun -Cmd $Cmd -ArgumentList @($Arch, $PEFiles) + Start-Process $Cmd -ArgumentList @($Arch, $PEFiles) -NoNewWindow -Wait # Remove unwanted items foreach ($SubDir in @("media", "media\Boot", "media\EFI\Microsoft\Boot")) { @@ -166,24 +180,14 @@ if ($MyInvocation.InvocationName -ne ".") { # Mount image Write-Host "Mounting image..." New-Item -Path $Mount -ItemType "directory" -Force | Out-Null - $ArgumentList = @( - "/Mount-Image", - ('/ImageFile:"{0}\media\sources\boot.wim"' -f $PEFiles), - "/Index:1", - ('/MountDir:"{0}"' -f $Mount) - ) - WKRun -Cmd $DISM -ArgumentList $ArgumentList + Mount-WindowsImage -Path $Mount -ImagePath "$PEFiles\media\sources\boot.wim" -Index 1 | Out-Null # Add packages - Write-Host "Adding packages..." + Write-Host "Adding packages:" foreach ($Package in $WinPEPackages) { - $PackagePath = "{0}\{1}\WinPE_OCs" -f $Env:WinPERoot, $Arch - $ArgumentList = @( - "/Add-Package", - ('/Image:"{0}"' -f $Mount), - ('/PackagePath:"{0}"' -f $PackagePath) - ) - WKRun -Cmd $DISM -ArgumentList $ArgumentList + $PackagePath = ("{0}\{1}\WinPE_OCs\{2}" -f $Env:WinPERoot, $Arch, $Package) + Write-Host " $Package..." + Add-WindowsPackage –PackagePath $PackagePath –Path $Mount | Out-Null } # Set RamDisk size @@ -191,7 +195,7 @@ if ($MyInvocation.InvocationName -ne ".") { ('/Image:"{0}"' -f $Mount), "/Set-ScratchSpace:512" ) - WKRun -Cmd $DISM -ArgumentList $ArgumentList + Start-Process $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait # Add WK tools Write-Host "Copying tools..." @@ -202,55 +206,57 @@ if ($MyInvocation.InvocationName -ne ".") { } else { $DestIni = "$Mount\WK\HWiNFO\HWiNFO32.INI" } - Move-Item -Path "$Root\WK\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force + Move-Item -Path "$Mount\WK\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\WK\ConEmu\ConEmu.jpg" -Recurse -Force Copy-Item -Path "$Root\Scripts" -Destination "$Mount\WK\Scripts" -Recurse -Force # Add System32 items - Copy-Item -Path "$Root\System32" -Destination "$Mount\Windows\System32" -Recurse -Force + Copy-Item -Path "$Root\System32\*" -Destination "$Mount\Windows\System32" -Recurse -Force $ArgumentList = @("/f", "$Mount\Windows\System32\winpe.jpg", "/a") - WKRun -Cmd "C:\Windows\System32\takeown.exe" -ArgumentList $ArgumentList + Start-Process "C:\Windows\System32\takeown.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @("$Mount\Windows\System32\winpe.jpg", "/grant", "Administrators:F") - WKRun -Cmd "C:\Windows\System32\icacls.exe" -ArgumentList $ArgumentList + Start-Process "C:\Windows\System32\icacls.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force # Update registry Write-Host "Updating Registry..." $Reg = "C:\Windows\System32\reg.exe" - WKRun -Cmd $Reg -ArgumentList @("load", "HKLM\WinPE-SW", "$Mount\Windows\System32\config\SOFTWARE") - WKRun -Cmd $Reg -ArgumentList @("load", "HKLM\WinPE-SYS", "$Mount\Windows\System32\config\SYSTEM") + Start-Process $Reg -ArgumentList @("load", "HKLM\WinPE-SW", "$Mount\Windows\System32\config\SOFTWARE") -NoNewWindow -Wait + Start-Process $Reg -ArgumentList @("load", "HKLM\WinPE-SYS", "$Mount\Windows\System32\config\SYSTEM") -NoNewWindow -Wait # Add 7-Zip and Python to path $RegPath = "HKLM:\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" $RegKey = Get-ItemProperty -Path $RegPath $NewValue = "{0};%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" -f $RegKey.Path - Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force + Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force | Out-Null # Replace Notepad $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' - New-Item -Path $RegPath -Force - New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force + New-Item -Path $RegPath -Force | Out-Null + New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null + + # Run garbage collection to release potential stale handles + ## Credit: https://jrich523.wordpress.com/2012/03/06/powershell-loading-and-unloading-registry-hives/ + Start-Sleep -Seconds 2 + [gc]::collect() # Unload registry hives - Start-Sleep -Seconds 1 - WKRun -Cmd $Reg -ArgumentList @("unload", "HKLM\WinPE-SW") - WKRun -Cmd $Reg -ArgumentList @("unload", "HKLM\WinPE-SYS") + Start-Sleep -Seconds 2 + Start-Process $Reg -ArgumentList @("unload", "HKLM\WinPE-SW") -NoNewWindow -Wait + Start-Process $Reg -ArgumentList @("unload", "HKLM\WinPE-SYS") -NoNewWindow -Wait # Unmount image Write-Host "Dismounting image..." - $ArgumentList = @( - "/Unmount-Image", - ('/MountDir:"{0}"' -f $Mount), - "/Commit") - WKRun -Cmd $DISM -ArgumentList $ArgumentList + Dismount-WindowsImage -Path $Mount -Save # Create ISO - $ArgumentList = @("/iso", $PEFiles, "wk-winpe-$Date-$Arch.iso") + $ArgumentList = @("/iso", $PEFiles, "$Root\wk-winpe-$Date-$Arch.iso") $Cmd = "{0}\MakeWinPEMedia.cmd" -f $Env:WinPERoot - WKRun -Cmd $Cmd -ArgumentList $ArgumentList + Start-Process $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait } ## Done ## Pop-Location + WKPause "Press Enter to exit... " } From 3ca0ab2079c1fa7bc75dbeb858bfc09123e5f292 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 20:24:17 -0800 Subject: [PATCH 23/85] Added WinPE.jpg --- WinPE.jpg | Bin 0 -> 171809 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 WinPE.jpg diff --git a/WinPE.jpg b/WinPE.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51eeb3c8a48ae80018235a8f2f058ed3fe2fc183 GIT binary patch literal 171809 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%0AJSE%1!n5d`N%E`&!@1p$J7euxYy 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�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

Nv&N+`nd&>6MFAWg_6e4sF44AjAU0%? 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 Date: Mon, 27 Nov 2017 20:41:53 -0800 Subject: [PATCH 24/85] Removed make.cmd --- .bin/Scripts/build_pe.ps1 | 2 +- make.cmd | 177 -------------------------------------- 2 files changed, 1 insertion(+), 178 deletions(-) delete mode 100644 make.cmd diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 621097f2..4a08a1b4 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -11,6 +11,7 @@ $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName $Root = (Get-Item $Bin -Force).Parent.FullName $Temp = "{0}\tmp" -f $Bin +$Date = Get-Date -UFormat "%Y-%m-%d" $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" # $ProgressPreference = "silentlyContinue" @@ -154,7 +155,6 @@ if ($MyInvocation.InvocationName -ne ".") { Abort } Push-Location "$WD" - $Date = Get-Date -UFormat "%Y-%m-%d" MakeClean ## Build ## diff --git a/make.cmd b/make.cmd deleted file mode 100644 index 1e47ff46..00000000 --- a/make.cmd +++ /dev/null @@ -1,177 +0,0 @@ -@echo off - -:Init -setlocal EnableDelayedExpansion -title WK-WinPE creation tool -color 1b -pushd %~dp0 - -:Flags -for %%f in (%*) do ( - if /i "%%f" == "/DEBUG" (@echo on) -) - -:GetDate -:: Credit to SS64.com Code taken from http://ss64.com/nt/syntax-getdate.html -:: Use WMIC to retrieve date and time in ISO 8601 format. -FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO ( -IF "%%~L"=="" goto s_done - Set _yyyy=%%L - Set _mm=00%%J - Set _dd=00%%G - Set _hour=00%%H - SET _minute=00%%I -) -:s_done -:: Pad digits with leading zeros -Set _mm=%_mm:~-2% -Set _dd=%_dd:~-2% -Set _hour=%_hour:~-2% -Set _minute=%_minute:~-2% -Set iso_date=%_yyyy%-%_mm%-%_dd% - -:Variables -set "wd=%cd%" -set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment" -set "pe_out=!wd!\pe_out" - -:CheckForCleanup -echo Scanning for old build folders... -set "found_old=" -if exist "!wd!\mount" ( - echo. Found: "!wd!\mount" - set "found_old=true" -) -if exist "!wd!\pe_files" ( - echo. Found: "!wd!\pe_files" - set "found_old=true" -) -if defined found_old ( - goto Cleanup -) else ( - echo. No build folders found. -) -goto :BuildBoth - -:Cleanup -echo. -choice /t 30 /c YN /d N /m "Delete the above folders?" -if %errorlevel% neq 1 goto Abort -rmdir /s /q "!wd!\mount" -rmdir /s /q "!wd!\pe_files" - -:BuildBoth -for %%a in (amd64 x86) do ( - rem set vars - set "arch=%%a" - set "drivers=!wd!\Drivers\!arch!" - set "mount=!wd!\mount\!arch!" - set "pe_files=!wd!\pe_files\!arch!" - set "winpe_ocs=%programfiles(x86)%\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment\!arch!\WinPE_OCs" - - rem Copy main files - call copype.cmd !arch! "!pe_files!" - for %%t in (bg-bg cs-cz da-dk de-de el-gr en-gb es-es es-mx et-ee fi-fi fr-ca fr-fr hr-hr hu-hu it-it ja-jp ko-kr lt-lt lv-lv nb-no nl-nl pl-pl pt-br pt-pt ro-ro ru-ru sk-sk sl-si sr-latn-cs sr-latn-rs sv-se tr-tr uk-ua zh-cn zh-hk zh-tw) do ( - rmdir /s /q "!pe_files!\media\%%t" - rmdir /s /q "!pe_files!\media\Boot\%%t" - rmdir /s /q "!pe_files!\media\EFI\Microsoft\Boot\%%t" - ) - - rem Mount Image - mkdir "!mount!" - dism /mount-image /imagefile:"!pe_files!\media\sources\boot.wim" /index:1 /mountdir:"!mount!" /logpath:"dism.log" - - rem Add Packages - More info: https://msdn.microsoft.com/en-us/library/windows/hardware/dn938382.aspx - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-EnhancedStorage.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-FMAPI.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-WMI.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-EnhancedStorage_en-us.cab" /logpath:"dism.log" - dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-WMI_en-us.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI before you install WinPE-NetFX. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-NetFx.cab" /logpath:"dism.log" - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-NetFx_en-us.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-Scripting.cab" /logpath:"dism.log" - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-Scripting_en-us.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-PowerShell.cab" /logpath:"dism.log" - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-PowerShell_en-us.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-DismCmdlets.cab" /logpath:"dism.log" - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-DismCmdlets_en-us.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. - rem rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-SecureBootCmdlets.cab" /logpath:"dism.log" - - rem rem Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\WinPE-StorageWMI.cab" /logpath:"dism.log" - rem dism /add-package /image:"!mount!" /packagepath:"!winpe_ocs!\en-us\WinPE-StorageWMI_en-us.cab" /logpath:"dism.log" - - rem Add Drivers - REM dism /add-driver /image:"!mount!" /driver:"!drivers!" /recurse /logpath:"dism.log" - - rem Force RamDisk size to try and avoid capture-image errors - dism /image:"!mount!" /set-scratchspace:512 - - rem Add WK Stuff - del "!wd!\WK\Scripts\WK.log" - mkdir "!mount!\WK" - robocopy /s /r:3 /w:0 "!wd!\WK\!arch!" "!mount!\WK" - mkdir "!mount!\WK\Scripts" - robocopy /s /r:3 /w:0 "!wd!\Scripts" "!mount!\WK\Scripts" - - rem Add System32 Stuff - copy /y "!wd!\System32\menu.cmd" "!mount!\Windows\System32\menu.cmd" - copy /y "!wd!\System32\Winpeshl.ini" "!mount!\Windows\System32\Winpeshl.ini" - - rem Background - takeown /f "!mount!\Windows\System32\winpe.jpg" /a - icacls "!mount!\Windows\System32\winpe.jpg" /grant administrators:F - copy /y "!wd!\System32\winpe.jpg" "!mount!\Windows\System32\winpe.jpg" - copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\ConEmu\ConEmu.jpg" - - rem Registry Edits - reg load HKLM\WinPE-SW "!mount!\Windows\System32\config\SOFTWARE" - reg load HKLM\WinPE-SYS "!mount!\Windows\System32\config\SYSTEM" - - rem Add 7-Zip and Python to path - reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip;%%SystemDrive%%\WK\python;%%SystemDrive%%\WK\wimlib" /f - - rem Replace Notepad - reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\NotepadPlusPlus\notepadplusplus.exe /z" /f - - rem Unload registry hives - reg unload HKLM\WinPE-SW - reg unload HKLM\WinPE-SYS - - rem Unmount Image - dism /unmount-image /mountdir:"!mount!" /commit - - rem Create ISO - del "wk-winpe-!iso_date!-!arch!.iso" - call makewinpemedia.cmd /iso "!pe_files!" "wk-winpe-!iso_date!-!arch!.iso" -) -goto Done - -:Abort -color 4e -echo. -echo Aborted. -goto Exit - -:Done -echo. -echo Done. -goto Exit - -:Exit -echo. -echo Press any key to exit... -pause>nul -popd -color -endlocal \ No newline at end of file From 97319df29e6758b9313788a3cc5594bb23c8a02a Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 20:42:44 -0800 Subject: [PATCH 25/85] Updated .gitignore --- .gitignore | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 8d6f5fbe..4ee6ed6a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ *iso Scripts/__pycache__ -dism* -mount -pe_files \ No newline at end of file +Mount +PEFiles \ No newline at end of file From 15c9839beca9f31c6a1493f41be1d7aa008e4e17 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Mon, 27 Nov 2017 23:42:15 -0800 Subject: [PATCH 26/85] Added update section * Needs testing --- .bin/Scripts/build_pe.ps1 | 205 ++++++++++++++++++++++++++++++++------ 1 file changed, 174 insertions(+), 31 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 4a08a1b4..abcf3537 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -10,7 +10,7 @@ $Host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName $Root = (Get-Item $Bin -Force).Parent.FullName -$Temp = "{0}\tmp" -f $Bin +$Temp = "$Bin\tmp" $Date = Get-Date -UFormat "%Y-%m-%d" $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" @@ -106,30 +106,29 @@ function MakeClean { function DownloadFile ($Path, $Name, $Url) { $OutFile = "{0}\{1}" -f $Path, $Name - Write-Host ("Downloading: {0}" -f $Name) + Write-Host ("Downloading: $Name") New-Item -Type Directory $Path 2>&1 | Out-Null try { - Invoke-Webrequest -Uri $Url -OutFile $OutFile + Invoke-WebRequest -Uri $Url -OutFile $OutFile } catch { Write-Host (" ERROR: Failed to download file." ) -ForegroundColor "Red" + $DownloadErrors += 1 } } function FindDynamicUrl ($SourcePage, $RegEx) { - $Url = "" - # Get source page Invoke-Webrequest -Uri $SourcePage -OutFile "tmp_page" # Search for real url $Url = Get-Content "tmp_page" | Where-Object {$_ -imatch $RegEx} - $Url = $Url -ireplace '.*(a |)href="([^"]+)".*', "$2" - $Url = $Url -ireplace ".*(a |)href='([^']+)'.*", "$2" + $Url = $Url -ireplace '.*(a |)href="([^"]+)".*', '$2' + $Url = $Url -ireplace ".*(a |)href='([^']+)'.*", '$2' # Remove tmp_page Remove-Item "tmp_page" - return $Url + $Url | Select-Object -First 1 } function WKPause ($Message = "Press Enter to continue... ") { Write-Host $Message -NoNewLine @@ -143,7 +142,7 @@ function WKPause ($Message = "Press Enter to continue... ") { # Asked by: https://stackoverflow.com/users/65164/mark-mascolino # Answer by: https://stackoverflow.com/users/696808/bacon-bits if ($MyInvocation.InvocationName -ne ".") { - # Clear-Host + Clear-Host Write-Host "Wizard Kit: Windows PE Build Tool`n" ## Prep ## @@ -157,6 +156,147 @@ if ($MyInvocation.InvocationName -ne ".") { Push-Location "$WD" MakeClean + if (Ask-User "Update Tools?") { + $DownloadErrors = 0 + $Path = $Temp + + ## Download Tools ## + # 7-Zip + DownloadFile -Path $Path -Name "7z-installer.msi" -Url "http://www.7-zip.org/a/7z1701.msi" + DownloadFile -Path $Path -Name "7z-extra.7z" -Url "http://www.7-zip.org/a/7z1701-extra.7z" + + # ConEmu + $Url = "https://github.com/Maximus5/ConEmu/releases/download/v17.11.09/ConEmuPack.171109.7z" + DownloadFile -Path $Path -Name "ConEmuPack.7z" -Url $Url + + # Notepad++ + $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.x64.7z" + DownloadFile -Path $Path -Name "nppamd64.7z" -Url $Url + $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.7z" + DownloadFile -Path $Path -Name "nppx86.7z" -Url $Url + + # Python + $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-win32.zip" + DownloadFile -Path $Path -Name "python32.zip" -Url $Url + $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-amd64.zip" + DownloadFile -Path $Path -Name "python64.zip" -Url $Url + + # Python: psutil + $DownloadPage = "https://pypi.python.org/pypi/psutil" + $RegEx = "href=.*-cp36-cp36m-win32.whl" + $Url = FindDynamicUrl $DownloadPage $RegEx + DownloadFile -Path $Path -Name "psutil32.whl" -Url $Url + $RegEx = "href=.*-cp36-cp36m-win_amd64.whl" + $Url = FindDynamicUrl $DownloadPage $RegEx + DownloadFile -Path $Path -Name "psutil64.whl" -Url $Url + + ## Bail ## + # If errors were encountered during downloads + if ($DownloadErrors -gt 0) { + Abort + } + + ## Extract ## + # 7-Zip + Write-Host "Extracting: 7-Zip" + try { + $ArgumentList = @("/a", "$Temp\7z-installer.msi", "TARGETDIR=$Temp\7zi", "/qn") + Start-Process -FilePath "$System32\msiexec.exe" -ArgumentList $ArgumentList -Wait + $SevenZip = "$Temp\7zi\Files\7-Zip\7z.exe" + $ArgumentList = @( + "e", "$Temp\7z-extra.7z", "-o$Root\WK\amd64\7-Zip", + "-aoa", "-bso0", "-bse0", "-bsp0", + "x64\7za.exe", "*.txt") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "e", "$Temp\7z-extra.7z", "-o$Root\WK\x86\7-Zip", + "-aoa", "-bso0", "-bse0", "-bsp0", + "7za.exe", "*.txt") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\7z*" -Recurse + $SevenZip = "$Root\WK\x86\7-Zip\7za.exe" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Notepad++ + Write-Host "Extracting: Notepad++" + try { + $ArgumentList = @( + "x", "$Temp\nppamd64.7z", "-o$Root\WK\amd64\NotepadPlusPlus", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\nppx86.7z", "-o$Root\WK\x86\NotepadPlusPlus", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\npp*.7z" + Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" + Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # ConEmu + Write-Host "Extracting: ConEmu" + try { + $ArgumentList = @( + "x", "$Temp\ConEmuPack.7z", "-o$Root\WK\amd64\ConEmu", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.exe" + Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.map" + Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.exe" "$Root\WK\amd64\ConEmu\ConEmu.exe" + Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.map" "$Root\WK\amd64\ConEmu\ConEmu.map" + $ArgumentList = @( + "x", "$Temp\ConEmuPack.7z", "-o$Root\WK\x86\ConEmu", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.exe" + Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.map" + Remove-Item "$Temp\ConEmuPack.7z" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Python + Write-Host "Extracting: Python" + try { + $ArgumentList = @( + "x", "$Temp\python64.zip", "-o$Root\WK\amd64\python", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\python32.zip", "-o$Root\WK\x86\python", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\python*.zip" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Python: psutil + Write-Host "Extracting: Python" + try { + $ArgumentList = @( + "x", "$Temp\psutil64.whl", "-o$Root\WK\amd64\python", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\psutil32.whl", "-o$Root\WK\x86\python", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\*.whl" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + } + ## Build ## foreach ($Arch in @("amd64", "x86")) { $Drivers = "$Root\Drivers\%arch" @@ -166,7 +306,7 @@ if ($MyInvocation.InvocationName -ne ".") { # Copy WinPE files Write-Host "Copying files..." $Cmd = ("{0}\copype.cmd" -f $Env:WinPERoot) - Start-Process $Cmd -ArgumentList @($Arch, $PEFiles) -NoNewWindow -Wait + Start-Process -FilePath $Cmd -ArgumentList @($Arch, $PEFiles) -NoNewWindow -Wait # Remove unwanted items foreach ($SubDir in @("media", "media\Boot", "media\EFI\Microsoft\Boot")) { @@ -195,7 +335,7 @@ if ($MyInvocation.InvocationName -ne ".") { ('/Image:"{0}"' -f $Mount), "/Set-ScratchSpace:512" ) - Start-Process $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait + Start-Process -FilePath $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait # Add WK tools Write-Host "Copying tools..." @@ -211,30 +351,33 @@ if ($MyInvocation.InvocationName -ne ".") { Copy-Item -Path "$Root\Scripts" -Destination "$Mount\WK\Scripts" -Recurse -Force # Add System32 items + $HostSystem32 = "{0}\System32" -f $Env:SystemRoot Copy-Item -Path "$Root\System32\*" -Destination "$Mount\Windows\System32" -Recurse -Force $ArgumentList = @("/f", "$Mount\Windows\System32\winpe.jpg", "/a") - Start-Process "C:\Windows\System32\takeown.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait + Start-Process -FilePath "$HostSystem32\takeown.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @("$Mount\Windows\System32\winpe.jpg", "/grant", "Administrators:F") - Start-Process "C:\Windows\System32\icacls.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait + Start-Process -FilePath "$HostSystem32\icacls.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force - # Update registry + # Load registry hives Write-Host "Updating Registry..." - $Reg = "C:\Windows\System32\reg.exe" - Start-Process $Reg -ArgumentList @("load", "HKLM\WinPE-SW", "$Mount\Windows\System32\config\SOFTWARE") -NoNewWindow -Wait - Start-Process $Reg -ArgumentList @("load", "HKLM\WinPE-SYS", "$Mount\Windows\System32\config\SYSTEM") -NoNewWindow -Wait + $Reg = "$HostSystem32\reg.exe" + $ArgumentList = @("load", "HKLM\WinPE-SW", "$Mount\Windows\System32\config\SOFTWARE") + Start-Process -FilePath $Reg -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @("load", "HKLM\WinPE-SYS", "$Mount\Windows\System32\config\SYSTEM") + Start-Process -FilePath $Reg -ArgumentList $ArgumentList -NoNewWindow -Wait - # Add 7-Zip and Python to path - $RegPath = "HKLM:\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" - $RegKey = Get-ItemProperty -Path $RegPath - $NewValue = "{0};%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" -f $RegKey.Path - Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force | Out-Null - - # Replace Notepad - $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" - $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' - New-Item -Path $RegPath -Force | Out-Null - New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null + # Add tools to path + $RegPath = "HKLM:\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" + $RegKey = Get-ItemProperty -Path $RegPath + $NewValue = "{0};%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" -f $RegKey.Path + Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force | Out-Null + + # Replace Notepad + $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" + $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' + New-Item -Path $RegPath -Force | Out-Null + New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null # Run garbage collection to release potential stale handles ## Credit: https://jrich523.wordpress.com/2012/03/06/powershell-loading-and-unloading-registry-hives/ @@ -243,8 +386,8 @@ if ($MyInvocation.InvocationName -ne ".") { # Unload registry hives Start-Sleep -Seconds 2 - Start-Process $Reg -ArgumentList @("unload", "HKLM\WinPE-SW") -NoNewWindow -Wait - Start-Process $Reg -ArgumentList @("unload", "HKLM\WinPE-SYS") -NoNewWindow -Wait + Start-Process -FilePath $Reg -ArgumentList @("unload", "HKLM\WinPE-SW") -NoNewWindow -Wait + Start-Process -FilePath $Reg -ArgumentList @("unload", "HKLM\WinPE-SYS") -NoNewWindow -Wait # Unmount image Write-Host "Dismounting image..." @@ -253,7 +396,7 @@ if ($MyInvocation.InvocationName -ne ".") { # Create ISO $ArgumentList = @("/iso", $PEFiles, "$Root\wk-winpe-$Date-$Arch.iso") $Cmd = "{0}\MakeWinPEMedia.cmd" -f $Env:WinPERoot - Start-Process $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait + Start-Process -FilePath $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait } ## Done ## From 7048696367a5b193e7ef2956f5dfd8fc592501f4 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 01:16:40 -0800 Subject: [PATCH 27/85] Added the rest of the tools --- .bin/Scripts/build_pe.ps1 | 251 +++++++++++++++++++++++++++++++++----- Scripts/menu.py | 1 - 2 files changed, 223 insertions(+), 29 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index abcf3537..09471a00 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -15,7 +15,7 @@ $Date = Get-Date -UFormat "%Y-%m-%d" $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" # $ProgressPreference = "silentlyContinue" -$SplitWindow = @() +$HostSystem32 = "{0}\System32" -f $Env:SystemRoot $WinPEPackages = @( "WinPE-EnhancedStorage.cab", "en-us\WinPE-EnhancedStorage_en-us.cab", @@ -143,7 +143,7 @@ function WKPause ($Message = "Press Enter to continue... ") { # Answer by: https://stackoverflow.com/users/696808/bacon-bits if ($MyInvocation.InvocationName -ne ".") { Clear-Host - Write-Host "Wizard Kit: Windows PE Build Tool`n" + Write-Host "Wizard Kit: Windows PE Build Tool`n`n`n`n`n" ## Prep ## try { @@ -165,31 +165,77 @@ if ($MyInvocation.InvocationName -ne ".") { DownloadFile -Path $Path -Name "7z-installer.msi" -Url "http://www.7-zip.org/a/7z1701.msi" DownloadFile -Path $Path -Name "7z-extra.7z" -Url "http://www.7-zip.org/a/7z1701-extra.7z" + # Blue Screen View + $Url = "http://www.nirsoft.net/utils/bluescreenview-x64.zip" + DownloadFile -Path $Path -Name "bluescreenview64.zip" -Url $Url + $Url = "http://www.nirsoft.net/utils/bluescreenview.zip" + DownloadFile -Path $Path -Name "bluescreenview32.zip" -Url $Url + # ConEmu $Url = "https://github.com/Maximus5/ConEmu/releases/download/v17.11.09/ConEmuPack.171109.7z" DownloadFile -Path $Path -Name "ConEmuPack.7z" -Url $Url + # Fast Copy + $Url = "http://ftp.vector.co.jp/69/28/2323/FastCopy332_x64.zip" + DownloadFile -Path $Path -Name "fastcopy64.zip" -Url $Url + $Url = "http://ftp.vector.co.jp/69/28/2323/FastCopy332.zip" + DownloadFile -Path $Path -Name "fastcopy32.zip" -Url $Url + + # HWiNFO + $Url = "http://app.oldfoss.com:81/download/HWiNFO/hw64_560.zip" + DownloadFile -Path $Path -Name "hwinfo64.zip" -Url $Url + $Url = "http://app.oldfoss.com:81/download/HWiNFO/hw32_560.zip" + DownloadFile -Path $Path -Name "hwinfo32.zip" -Url $Url + # Notepad++ $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.x64.7z" - DownloadFile -Path $Path -Name "nppamd64.7z" -Url $Url + DownloadFile -Path $Path -Name "npp_amd64.7z" -Url $Url $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.7z" - DownloadFile -Path $Path -Name "nppx86.7z" -Url $Url + DownloadFile -Path $Path -Name "npp_x86.7z" -Url $Url + # NT Password Editor + $Url = "http://cdslow.org.ru/files/ntpwedit/ntpwed07.zip" + DownloadFile -Path $Path -Name "ntpwed.zip" -Url $Url + + # Prime95 + $Url = "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win64.zip" + DownloadFile -Path $Path -Name "prime95_64.zip" -Url $Url + $Url = "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win32.zip" + DownloadFile -Path $Path -Name "prime95_32.zip" -Url $Url + + # ProduKey + $Url = "http://www.nirsoft.net/utils/produkey-x64.zip" + DownloadFile -Path $Path -Name "produkey64.zip" -Url $Url + $Url = "http://www.nirsoft.net/utils/produkey.zip" + DownloadFile -Path $Path -Name "produkey32.zip" -Url $Url + # Python - $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-win32.zip" - DownloadFile -Path $Path -Name "python32.zip" -Url $Url $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-amd64.zip" DownloadFile -Path $Path -Name "python64.zip" -Url $Url + $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-win32.zip" + DownloadFile -Path $Path -Name "python32.zip" -Url $Url # Python: psutil + $RegEx = "href=.*-cp36-cp36m-win_amd64.whl" + $Url = FindDynamicUrl $DownloadPage $RegEx + DownloadFile -Path $Path -Name "psutil64.whl" -Url $Url $DownloadPage = "https://pypi.python.org/pypi/psutil" $RegEx = "href=.*-cp36-cp36m-win32.whl" $Url = FindDynamicUrl $DownloadPage $RegEx DownloadFile -Path $Path -Name "psutil32.whl" -Url $Url - $RegEx = "href=.*-cp36-cp36m-win_amd64.whl" - $Url = FindDynamicUrl $DownloadPage $RegEx - DownloadFile -Path $Path -Name "psutil64.whl" -Url $Url - + + # Q-Dir + $Url = "https://www.softwareok.com/Download/Q-Dir_Portable_x64.zip" + DownloadFile -Path $Path -Name "qdir64.zip" -Url $Url + $Url = "https://www.softwareok.com/Download/Q-Dir_Portable.zip" + DownloadFile -Path $Path -Name "qdir32.zip" -Url $Url + + # TestDisk / PhotoRec + $Url = "https://www.cgsecurity.org/testdisk-7.1-WIP.win64.zip" + DownloadFile -Path $Path -Name "testdisk64.zip" -Url $Url + $Url = "https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip" + DownloadFile -Path $Path -Name "testdisk32.zip" -Url $Url + ## Bail ## # If errors were encountered during downloads if ($DownloadErrors -gt 0) { @@ -201,7 +247,7 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: 7-Zip" try { $ArgumentList = @("/a", "$Temp\7z-installer.msi", "TARGETDIR=$Temp\7zi", "/qn") - Start-Process -FilePath "$System32\msiexec.exe" -ArgumentList $ArgumentList -Wait + Start-Process -FilePath "$HostSystem32\msiexec.exe" -ArgumentList $ArgumentList -Wait $SevenZip = "$Temp\7zi\Files\7-Zip\7z.exe" $ArgumentList = @( "e", "$Temp\7z-extra.7z", "-o$Root\WK\amd64\7-Zip", @@ -220,25 +266,23 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } - # Notepad++ - Write-Host "Extracting: Notepad++" + # Blue Screen View + Write-Host "Extracting: BlueScreenView" try { $ArgumentList = @( - "x", "$Temp\nppamd64.7z", "-o$Root\WK\amd64\NotepadPlusPlus", + "x", "$Temp\bluescreenview64.zip", "-o$Root\WK\amd64\BlueScreenView", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\nppx86.7z", "-o$Root\WK\x86\NotepadPlusPlus", + "x", "$Temp\bluescreenview32.zip", "-o$Root\WK\x86\BlueScreenView", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Remove-Item "$Temp\npp*.7z" - Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" - Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" + Remove-Item "$Temp\bluescreenview*" } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } - + # ConEmu Write-Host "Extracting: ConEmu" try { @@ -256,47 +300,198 @@ if ($MyInvocation.InvocationName -ne ".") { Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.exe" Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.map" - Remove-Item "$Temp\ConEmuPack.7z" + Remove-Item "$Temp\ConEmuPack*" } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } - # Python - Write-Host "Extracting: Python" + # Fast Copy + Write-Host "Extracting: FastCopy" + try { + $ArgumentList = @( + "x", "$Temp\fastcopy64.zip", "-o$Root\WK\amd64\FastCopy", + "-aoa", "-bso0", "-bse0", "-bsp0", + "-x!setup.exe", "-x!*.dll") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "e", "$Temp\fastcopy32.zip", "-o$Root\WK\x86\FastCopy", + "-aoa", "-bso0", "-bse0", "-bsp0", + "-x!setup.exe", "-x!*.dll") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\fastcopy*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # HWiNFO + Write-Host "Extracting: HWiNFO" + try { + $ArgumentList = @( + "e", "$Temp\hwinfo64.zip", "-o$Root\WK\amd64\HWiNFO", + "-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO64.exe") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "e", "$Temp\hwinfo32.zip", "-o$Root\WK\x86\HWiNFO", + "-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO32.exe") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\hwinfo*" + Move-Item "$Root\WK\amd64\HWiNFO\HWiNFO64.exe" "$Root\WK\amd64\HWiNFO\HWiNFO.exe" + Move-Item "$Root\WK\x86\HWiNFO\HWiNFO32.exe" "$Root\WK\x86\HWiNFO\HWiNFO.exe" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Notepad++ + Write-Host "Extracting: Notepad++" + try { + $ArgumentList = @( + "x", "$Temp\npp_amd64.7z", "-o$Root\WK\amd64\NotepadPlusPlus", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\npp_x86.7z", "-o$Root\WK\x86\NotepadPlusPlus", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\npp*" + Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" + Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # NT Password Editor + Write-Host "Extracting: NT Password Editor" + try { + $ArgumentList = @( + "e", "$Temp\ntpwed.zip", ('-o"{0}\WK\amd64\NT Password Editor"' -f $Root), + "-aoa", "-bso0", "-bse0", "-bsp0", + "ntpwedit64.exe", "*.txt") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Move-Item "$Root\WK\amd64\NT Password Editor\ntpwedit64.exe" "$Root\WK\amd64\NT Password Editor\ntpwedit.exe" + $ArgumentList = @( + "e", "$Temp\ntpwed.zip", ('-o"{0}\WK\x86\NT Password Editor"' -f $Root), + "-aoa", "-bso0", "-bse0", "-bsp0", + "ntpwedit.exe", "*.txt") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\ntpwed*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # PhotoRec / TestDisk + Write-Host "Extracting: PhotoRec / TestDisk" + try { + $ArgumentList = @( + "x", "$Temp\testdisk64.zip", "-o$Root\WK\amd64\TestDisk", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Move-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\amd64\TestDisk" -Force + Remove-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP" -Recurse -Force + $ArgumentList = @( + "x", "$Temp\testdisk32.zip", "-o$Root\WK\x86\TestDisk", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Move-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\x86\TestDisk" -Force + Remove-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP" -Recurse -Force + Remove-Item "$Temp\testdisk*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Prime95 + Write-Host "Extracting: Prime95" + try { + $ArgumentList = @( + "x", "$Temp\prime95_64.zip", "-o$Root\WK\amd64\Prime95", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\prime95_32.zip", "-o$Root\WK\x86\Prime95", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\prime95*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # ProduKey + try { + $ArgumentList = @( + "x", "$Temp\produkey64.zip", "-o$Root\WK\amd64\ProduKey", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\produkey32.zip", "-o$Root\WK\x86\ProduKey", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\produkey*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + + # Python (x64) + Write-Host "Extracting: Python (x64)" try { $ArgumentList = @( "x", "$Temp\python64.zip", "-o$Root\WK\amd64\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\python32.zip", "-o$Root\WK\x86\python", + "x", "$Temp\psutil64.whl", "-o$Root\WK\amd64\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Remove-Item "$Temp\python*.zip" + } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } - # Python: psutil - Write-Host "Extracting: Python" + # Python (x32) + Write-Host "Extracting: Python (x32)" try { $ArgumentList = @( - "x", "$Temp\psutil64.whl", "-o$Root\WK\amd64\python", + "x", "$Temp\python32.zip", "-o$Root\WK\x86\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( "x", "$Temp\psutil32.whl", "-o$Root\WK\x86\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Remove-Item "$Temp\*.whl" + } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } + Remove-Item "$Temp\python*" + Remove-Item "$Temp\*.whl" } + # Q-Dir + Write-Host "Extracting: Q-Dir" + try { + $ArgumentList = @( + "e", "$Temp\qdir64.zip", "-o$Root\WK\amd64\Q-Dir", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "e", "$Temp\qdir32.zip", "-o$Root\WK\x86\Q-Dir", + "-aoa", "-bso0", "-bse0", "-bsp0", + "Q-Dir.*") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\qdir*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + ## Build ## foreach ($Arch in @("amd64", "x86")) { $Drivers = "$Root\Drivers\%arch" diff --git a/Scripts/menu.py b/Scripts/menu.py index 952ec9a4..7a72f729 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -199,7 +199,6 @@ def menu_windows_setup(): def menu_tools(): tools = [ {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, - {'Name': 'CPU-Z', 'Folder': 'CPU-Z', 'File': 'cpuz.exe'}, {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, From 7ad26a6182f9a3a37ea0d611700d731a97988139 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 01:55:55 -0800 Subject: [PATCH 28/85] Fix Q-Dir extraction --- .bin/Scripts/build_pe.ps1 | 7 +++---- .gitignore | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 09471a00..253e7c3a 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -478,13 +478,12 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Q-Dir" try { $ArgumentList = @( - "e", "$Temp\qdir64.zip", "-o$Root\WK\amd64\Q-Dir", + "x", "$Temp\qdir64.zip", "-o$Root\WK\amd64", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "e", "$Temp\qdir32.zip", "-o$Root\WK\x86\Q-Dir", - "-aoa", "-bso0", "-bse0", "-bsp0", - "Q-Dir.*") + "x", "$Temp\qdir32.zip", "-o$Root\WK\x86", + "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\qdir*" } diff --git a/.gitignore b/.gitignore index 661aa0d4..ed8a9f58 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ Logs Mount PEFiles Scripts/__pycache__ +WK/amd64/ +WK/x86/ From bc33a7fcb398b584304f5c9c66fb0047bf0010a7 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 01:56:27 -0800 Subject: [PATCH 29/85] Disable notepad replacement for now --- .bin/Scripts/build_pe.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 253e7c3a..41683f3e 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -568,10 +568,11 @@ if ($MyInvocation.InvocationName -ne ".") { Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force | Out-Null # Replace Notepad - $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" - $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' - New-Item -Path $RegPath -Force | Out-Null - New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null + ## Currently broken ## + # $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" + # $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' + # New-Item -Path $RegPath -Force | Out-Null + # New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null # Run garbage collection to release potential stale handles ## Credit: https://jrich523.wordpress.com/2012/03/06/powershell-loading-and-unloading-registry-hives/ From 675ff57f669bd2385f609715c1fd5b2665b63948 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 14:39:33 -0800 Subject: [PATCH 30/85] Simplified WinPE package installation --- .bin/Scripts/build_pe.ps1 | 58 ++++++++------------------------------- 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 41683f3e..01209359 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -16,52 +16,6 @@ $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" # $ProgressPreference = "silentlyContinue" $HostSystem32 = "{0}\System32" -f $Env:SystemRoot -$WinPEPackages = @( - "WinPE-EnhancedStorage.cab", - "en-us\WinPE-EnhancedStorage_en-us.cab", - "WinPE-FMAPI.cab", - "WinPE-WMI.cab", - "en-us\WinPE-WMI_en-us.cab" -) - # Install WinPE-WMI before you install WinPE-NetFX. - # "WinPE-NetFx.cab", - # "en-us\WinPE-NetFx_en-us.cab", - - # Install WinPE-WMI and WinPE-NetFX before you install WinPE-Scripting. - # "WinPE-Scripting.cab", - # "en-us\WinPE-Scripting_en-us.cab", - - # Install WinPE-WMI, WinPE-NetFX, and WinPE-Scripting before you install WinPE-PowerShell. - # "WinPE-PowerShell.cab", - # "en-us\WinPE-PowerShell_en-us.cab", - - # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-DismCmdlets. - # "WinPE-DismCmdlets.cab", - # "en-us\WinPE-DismCmdlets_en-us.cab", - - # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-SecureBootCmdlets. - # "WinPE-SecureBootCmdlets.cab", - - # Install WinPE-WMI, WinPE-NetFX, WinPE-Scripting, and WinPE-PowerShell before you install WinPE-StorageWMI. - # "WinPE-StorageWMI.cab", - # "en-us\WinPE-StorageWMI_en-us.cab", - -## Fake DandISetEnv.bat ## -# $DVars = @( - # @("DISMRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\DISM"), - # @("BCDBootRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\BCDBoot"), - # @("OSCDImgRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg"), - # @("WdsmcastRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Wdsmcast"), - # @("HelpIndexerRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\HelpIndexer"), - # @("WSIMRoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\WSIM"), - # @("WinPERoot", "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Windows Preinstallation Environment") -# ) -# foreach ($d in $DVars) { - # $varName = $d[0] - # $varValue = $d[1] - # Set-Item -Path Env:$varName -Value $varValue - # Set-Item -Path Env:PATH -Value ($Env:PATH + ";$varValue") -# } $DISM = "{0}\DISM.exe" -f $Env:DISMRoot ## Functions ## @@ -518,10 +472,20 @@ if ($MyInvocation.InvocationName -ne ".") { # Add packages Write-Host "Adding packages:" + $WinPEPackages = @( + "WinPE-EnhancedStorage", + "WinPE-FMAPI", + "WinPE-WMI", + "WinPE-SecureStartup" + ) foreach ($Package in $WinPEPackages) { - $PackagePath = ("{0}\{1}\WinPE_OCs\{2}" -f $Env:WinPERoot, $Arch, $Package) + $PackagePath = ("{0}\{1}\WinPE_OCs\{2}.cab" -f $Env:WinPERoot, $Arch, $Package) Write-Host " $Package..." Add-WindowsPackage –PackagePath $PackagePath –Path $Mount | Out-Null + $LangPackagePath = ("{0}\{1}\WinPE_OCs\en-us\{2}_en-us.cab" -f $Env:WinPERoot, $Arch, $Package) + if (Test-Path $LangPackagePath) { + Add-WindowsPackage –PackagePath $LangPackagePath –Path $Mount | Out-Null + } } # Set RamDisk size From 330b24641fea85433a4d4dd4161bf6d81d50729c Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 14:40:43 -0800 Subject: [PATCH 31/85] Bugfix: REG_EXPAND_SZ keys now handled correctly --- .bin/Scripts/build_pe.ps1 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 01209359..5c97b997 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -526,10 +526,18 @@ if ($MyInvocation.InvocationName -ne ".") { Start-Process -FilePath $Reg -ArgumentList $ArgumentList -NoNewWindow -Wait # Add tools to path - $RegPath = "HKLM:\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" - $RegKey = Get-ItemProperty -Path $RegPath - $NewValue = "{0};%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" -f $RegKey.Path - Set-ItemProperty -Path $RegPath -Name "Path" -Value $NewValue -Force | Out-Null + ## .NET code to properly handle REG_EXPAND_SZ values + ## Credit: https://www.sepago.com/blog/2013/08/22/reading-and-writing-regexpandsz-data-with-powershell + ## By: Marius Gawenda + $Hive = [Microsoft.Win32.Registry]::LocalMachine + $RegPath = "WinPE-SYS\ControlSet001\Control\Session Manager\Environment" + $RegKey = $Hive.OpenSubKey($RegPath) + $CurValue = $RegKey.GetValue( + "Path", $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) + $NewValue = "$CurValue;%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" + Set-ItemProperty -Path "HKLM:\$RegPath" -Name "Path" -Value $NewValue -Force | Out-Null + $Hive.close() + $RegKey.close() # Replace Notepad ## Currently broken ## @@ -560,5 +568,6 @@ if ($MyInvocation.InvocationName -ne ".") { ## Done ## Pop-Location + Write-Host "`nDone." WKPause "Press Enter to exit... " } From 7a58e6e85936c71b047f7841db0d4f5c6a66e173 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 14:42:42 -0800 Subject: [PATCH 32/85] Simplified tool downloads --- .bin/Scripts/build_pe.ps1 | 124 +++++++++++++++----------------------- 1 file changed, 49 insertions(+), 75 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 41683f3e..7506f9ed 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -161,80 +161,54 @@ if ($MyInvocation.InvocationName -ne ".") { $Path = $Temp ## Download Tools ## - # 7-Zip - DownloadFile -Path $Path -Name "7z-installer.msi" -Url "http://www.7-zip.org/a/7z1701.msi" - DownloadFile -Path $Path -Name "7z-extra.7z" -Url "http://www.7-zip.org/a/7z1701-extra.7z" - - # Blue Screen View - $Url = "http://www.nirsoft.net/utils/bluescreenview-x64.zip" - DownloadFile -Path $Path -Name "bluescreenview64.zip" -Url $Url - $Url = "http://www.nirsoft.net/utils/bluescreenview.zip" - DownloadFile -Path $Path -Name "bluescreenview32.zip" -Url $Url - - # ConEmu - $Url = "https://github.com/Maximus5/ConEmu/releases/download/v17.11.09/ConEmuPack.171109.7z" - DownloadFile -Path $Path -Name "ConEmuPack.7z" -Url $Url - - # Fast Copy - $Url = "http://ftp.vector.co.jp/69/28/2323/FastCopy332_x64.zip" - DownloadFile -Path $Path -Name "fastcopy64.zip" -Url $Url - $Url = "http://ftp.vector.co.jp/69/28/2323/FastCopy332.zip" - DownloadFile -Path $Path -Name "fastcopy32.zip" -Url $Url - - # HWiNFO - $Url = "http://app.oldfoss.com:81/download/HWiNFO/hw64_560.zip" - DownloadFile -Path $Path -Name "hwinfo64.zip" -Url $Url - $Url = "http://app.oldfoss.com:81/download/HWiNFO/hw32_560.zip" - DownloadFile -Path $Path -Name "hwinfo32.zip" -Url $Url - - # Notepad++ - $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.x64.7z" - DownloadFile -Path $Path -Name "npp_amd64.7z" -Url $Url - $Url = "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.7z" - DownloadFile -Path $Path -Name "npp_x86.7z" -Url $Url - - # NT Password Editor - $Url = "http://cdslow.org.ru/files/ntpwedit/ntpwed07.zip" - DownloadFile -Path $Path -Name "ntpwed.zip" -Url $Url - - # Prime95 - $Url = "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win64.zip" - DownloadFile -Path $Path -Name "prime95_64.zip" -Url $Url - $Url = "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win32.zip" - DownloadFile -Path $Path -Name "prime95_32.zip" -Url $Url - - # ProduKey - $Url = "http://www.nirsoft.net/utils/produkey-x64.zip" - DownloadFile -Path $Path -Name "produkey64.zip" -Url $Url - $Url = "http://www.nirsoft.net/utils/produkey.zip" - DownloadFile -Path $Path -Name "produkey32.zip" -Url $Url - - # Python - $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-amd64.zip" - DownloadFile -Path $Path -Name "python64.zip" -Url $Url - $Url = "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-win32.zip" - DownloadFile -Path $Path -Name "python32.zip" -Url $Url - - # Python: psutil - $RegEx = "href=.*-cp36-cp36m-win_amd64.whl" - $Url = FindDynamicUrl $DownloadPage $RegEx - DownloadFile -Path $Path -Name "psutil64.whl" -Url $Url - $DownloadPage = "https://pypi.python.org/pypi/psutil" - $RegEx = "href=.*-cp36-cp36m-win32.whl" - $Url = FindDynamicUrl $DownloadPage $RegEx - DownloadFile -Path $Path -Name "psutil32.whl" -Url $Url - - # Q-Dir - $Url = "https://www.softwareok.com/Download/Q-Dir_Portable_x64.zip" - DownloadFile -Path $Path -Name "qdir64.zip" -Url $Url - $Url = "https://www.softwareok.com/Download/Q-Dir_Portable.zip" - DownloadFile -Path $Path -Name "qdir32.zip" -Url $Url - - # TestDisk / PhotoRec - $Url = "https://www.cgsecurity.org/testdisk-7.1-WIP.win64.zip" - DownloadFile -Path $Path -Name "testdisk64.zip" -Url $Url - $Url = "https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip" - DownloadFile -Path $Path -Name "testdisk32.zip" -Url $Url + $ToolSources = @( + # 7-Zip + @("7z-installer.msi", "http://www.7-zip.org/a/7z1701.msi"), + @("7z-extra.7z", "http://www.7-zip.org/a/7z1701-extra.7z"), + # Blue Screen View + @("bluescreenview64.zip", "http://www.nirsoft.net/utils/bluescreenview-x64.zip"), + @("bluescreenview32.zip", "http://www.nirsoft.net/utils/bluescreenview.zip"), + # ConEmu + @("ConEmuPack.7z", "https://github.com/Maximus5/ConEmu/releases/download/v17.11.09/ConEmuPack.171109.7z"), + # Fast Copy + @("fastcopy64.zip", "http://ftp.vector.co.jp/69/28/2323/FastCopy332_x64.zip"), + @("fastcopy32.zip", "http://ftp.vector.co.jp/69/28/2323/FastCopy332.zip"), + # HWiNFO + @("hwinfo64.zip", "http://app.oldfoss.com:81/download/HWiNFO/hw64_560.zip"), + @("hwinfo32.zip", "http://app.oldfoss.com:81/download/HWiNFO/hw32_560.zip"), + # Notepad++ + @("npp_amd64.7z", "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.x64.7z"), + @("npp_x86.7z", "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.7z"), + # NT Password Editor + @("ntpwed.zip", "http://cdslow.org.ru/files/ntpwedit/ntpwed07.zip"), + # Prime95 + @("prime95_64.zip", "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win64.zip"), + @("prime95_32.zip", "http://www.mersenne.org/ftp_root/gimps/p95v294b5.win32.zip"), + # ProduKey + @("produkey64.zip", "http://www.nirsoft.net/utils/produkey-x64.zip"), + @("produkey32.zip", "http://www.nirsoft.net/utils/produkey.zip"), + # Python + @("python64.zip", "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-amd64.zip"), + @("python32.zip", "https://www.python.org/ftp/python/3.6.3/python-3.6.3-embed-win32.zip"), + # Python: psutil + @( + "psutil64.whl", + (FindDynamicUrl "https://pypi.python.org/pypi/psutil" "href=.*-cp36-cp36m-win_amd64.whl") + ), + @( + "psutil32.whl", + (FindDynamicUrl "https://pypi.python.org/pypi/psutil" "href=.*-cp36-cp36m-win32.whl") + ), + # Q-Dir + @("qdir64.zip", "https://www.softwareok.com/Download/Q-Dir_Portable_x64.zip"), + @("qdir32.zip", "https://www.softwareok.com/Download/Q-Dir_Portable.zip"), + # TestDisk / PhotoRec + @("testdisk64.zip", "https://www.cgsecurity.org/testdisk-7.1-WIP.win64.zip"), + @("testdisk32.zip", "https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip") + ) + foreach ($Tool in $ToolSources) { + DownloadFile -Path $Temp -Name $Tool[0] -Url $Tool[1] + } ## Bail ## # If errors were encountered during downloads @@ -472,7 +446,6 @@ if ($MyInvocation.InvocationName -ne ".") { } Remove-Item "$Temp\python*" Remove-Item "$Temp\*.whl" - } # Q-Dir Write-Host "Extracting: Q-Dir" @@ -490,6 +463,7 @@ if ($MyInvocation.InvocationName -ne ".") { catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } + } ## Build ## foreach ($Arch in @("amd64", "x86")) { From 3e63a50f92a0a7e6103d9ef63d8d9593a21debc6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 17:48:52 -0800 Subject: [PATCH 33/85] Drivers and Killer Drivers * Add-WindowsDriver section to include extra drivers in WinPE * Added Killer Network Driver to the download list * Bugfix: $Drivers was not set properly --- .bin/Scripts/build_pe.ps1 | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 7506f9ed..4f5fd432 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -158,7 +158,6 @@ if ($MyInvocation.InvocationName -ne ".") { if (Ask-User "Update Tools?") { $DownloadErrors = 0 - $Path = $Temp ## Download Tools ## $ToolSources = @( @@ -176,6 +175,11 @@ if ($MyInvocation.InvocationName -ne ".") { # HWiNFO @("hwinfo64.zip", "http://app.oldfoss.com:81/download/HWiNFO/hw64_560.zip"), @("hwinfo32.zip", "http://app.oldfoss.com:81/download/HWiNFO/hw32_560.zip"), + # Killer Network Drivers + @( + "killerinf.zip", + ("http://www.killernetworking.com"+(FindDynamicUrl "http://www.killernetworking.com/driver-downloads/item/killer-drivers-inf" "Download Killer-Ethernet").replace('&', '&')) + ), # Notepad++ @("npp_amd64.7z", "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.x64.7z"), @("npp_x86.7z", "https://notepad-plus-plus.org/repository/7.x/7.5.2/npp.7.5.2.bin.minimalist.7z"), @@ -299,6 +303,25 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } + # Killer Network Driver + Write-Host "Extracting: Killer Network Driver" + try { + $ArgumentList = @( + "e", "$Temp\killerinf.zip", "-o$Root\Drivers\amd64\Killer", + "-aoa", "-bso0", "-bse0", "-bsp0", + "Production\Windows10-x64\Eth\*") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "e", "$Temp\killerinf.zip", "-o$Root\Drivers\x86\Killer", + "-aoa", "-bso0", "-bse0", "-bsp0", + "Production\Windows10-x86\Eth\*") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\killerinf*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } + # HWiNFO Write-Host "Extracting: HWiNFO" try { @@ -467,9 +490,9 @@ if ($MyInvocation.InvocationName -ne ".") { ## Build ## foreach ($Arch in @("amd64", "x86")) { - $Drivers = "$Root\Drivers\%arch" + $Drivers = "$Root\Drivers\$Arch" $Mount = "$Root\Mount" - $PEFiles = "$Root\PEFiles\$arch" + $PEFiles = "$Root\PEFiles\$Arch" # Copy WinPE files Write-Host "Copying files..." @@ -490,6 +513,9 @@ if ($MyInvocation.InvocationName -ne ".") { New-Item -Path $Mount -ItemType "directory" -Force | Out-Null Mount-WindowsImage -Path $Mount -ImagePath "$PEFiles\media\sources\boot.wim" -Index 1 | Out-Null + # Add drivers + Add-WindowsDriver -Path $Mount -Driver $Drivers -Recurse | Out-Null + # Add packages Write-Host "Adding packages:" foreach ($Package in $WinPEPackages) { From b689c33c962b44c700b8d1a0352d29b2bdaf508c Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Tue, 28 Nov 2017 17:49:24 -0800 Subject: [PATCH 34/85] Bugfix: Updating over current tools is working --- .bin/Scripts/build_pe.ps1 | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 4f5fd432..c467aefc 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -270,8 +270,8 @@ if ($MyInvocation.InvocationName -ne ".") { Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.exe" Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.map" - Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.exe" "$Root\WK\amd64\ConEmu\ConEmu.exe" - Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.map" "$Root\WK\amd64\ConEmu\ConEmu.map" + Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.exe" "$Root\WK\amd64\ConEmu\ConEmu.exe" -Force + Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.map" "$Root\WK\amd64\ConEmu\ConEmu.map" -Force $ArgumentList = @( "x", "$Temp\ConEmuPack.7z", "-o$Root\WK\x86\ConEmu", "-aoa", "-bso0", "-bse0", "-bsp0") @@ -334,8 +334,8 @@ if ($MyInvocation.InvocationName -ne ".") { "-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO32.exe") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\hwinfo*" - Move-Item "$Root\WK\amd64\HWiNFO\HWiNFO64.exe" "$Root\WK\amd64\HWiNFO\HWiNFO.exe" - Move-Item "$Root\WK\x86\HWiNFO\HWiNFO32.exe" "$Root\WK\x86\HWiNFO\HWiNFO.exe" + Move-Item "$Root\WK\amd64\HWiNFO\HWiNFO64.exe" "$Root\WK\amd64\HWiNFO\HWiNFO.exe" -Force + Move-Item "$Root\WK\x86\HWiNFO\HWiNFO32.exe" "$Root\WK\x86\HWiNFO\HWiNFO.exe" -Force } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" @@ -353,8 +353,8 @@ if ($MyInvocation.InvocationName -ne ".") { "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\npp*" - Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" - Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" + Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" -Force + Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" -Force } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" @@ -368,7 +368,7 @@ if ($MyInvocation.InvocationName -ne ".") { "-aoa", "-bso0", "-bse0", "-bsp0", "ntpwedit64.exe", "*.txt") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Move-Item "$Root\WK\amd64\NT Password Editor\ntpwedit64.exe" "$Root\WK\amd64\NT Password Editor\ntpwedit.exe" + Move-Item "$Root\WK\amd64\NT Password Editor\ntpwedit64.exe" "$Root\WK\amd64\NT Password Editor\ntpwedit.exe" -Force $ArgumentList = @( "e", "$Temp\ntpwed.zip", ('-o"{0}\WK\x86\NT Password Editor"' -f $Root), "-aoa", "-bso0", "-bse0", "-bsp0", @@ -386,12 +386,16 @@ if ($MyInvocation.InvocationName -ne ".") { $ArgumentList = @( "x", "$Temp\testdisk64.zip", "-o$Root\WK\amd64\TestDisk", "-aoa", "-bso0", "-bse0", "-bsp0") + # Remove destination since Move-Item -Force can't handle this recursive merge + Remove-Item "$Root\WK\amd64\TestDisk" -Recurse -Force Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Move-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\amd64\TestDisk" -Force Remove-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP" -Recurse -Force $ArgumentList = @( "x", "$Temp\testdisk32.zip", "-o$Root\WK\x86\TestDisk", "-aoa", "-bso0", "-bse0", "-bsp0") + # Remove destination since Move-Item -Force can't handle this recursive merge + Remove-Item "$Root\WK\x86\TestDisk" -Recurse -Force Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Move-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\x86\TestDisk" -Force Remove-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP" -Recurse -Force From 446867b611216a58ed256caef7e331e4aff023f2 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 13:39:00 -0800 Subject: [PATCH 35/85] Started Python refactoring # Plan * Use current WizardKit scripts as the new base * Split functions into multiple files under Scripts\functions\ * Review menus and menu-flow * Log everything and open log at end of menu-flows * (before returning to the root/main menu) --- .gitignore | 3 +- Scripts/functions.py | 1006 ----------------- Scripts/functions/backup.py | 486 ++++++++ Scripts/functions/common.py | 682 +++++++++++ Scripts/functions/data.py | 607 ++++++++++ Scripts/{ => functions}/partition_uids.py | 2 +- Scripts/functions/windows_setup.py | 273 +++++ Scripts/{menu.py => functions/winpe_menus.py} | 208 ++-- Scripts/settings/main.py | 68 ++ Scripts/settings/tools.py | 55 + Scripts/winpe_root_menu.py | 21 + 11 files changed, 2317 insertions(+), 1094 deletions(-) delete mode 100644 Scripts/functions.py create mode 100644 Scripts/functions/backup.py create mode 100644 Scripts/functions/common.py create mode 100644 Scripts/functions/data.py rename Scripts/{ => functions}/partition_uids.py (98%) create mode 100644 Scripts/functions/windows_setup.py rename Scripts/{menu.py => functions/winpe_menus.py} (66%) create mode 100644 Scripts/settings/main.py create mode 100644 Scripts/settings/tools.py create mode 100644 Scripts/winpe_root_menu.py diff --git a/.gitignore b/.gitignore index ed8a9f58..6e041ca5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,10 @@ +**/__pycache__/* *.bak *.iso -.bin/Scripts/__pycache__ .bin/tmp Drivers Logs Mount PEFiles -Scripts/__pycache__ WK/amd64/ WK/x86/ diff --git a/Scripts/functions.py b/Scripts/functions.py deleted file mode 100644 index 03f03bf3..00000000 --- a/Scripts/functions.py +++ /dev/null @@ -1,1006 +0,0 @@ -# WK WinPE Functions - -# Init -import os -import re -import shutil -import subprocess -import sys -import time -import winreg -os.chdir(os.path.dirname(os.path.realpath(__file__))) -bin = os.path.abspath('..\\') -sys.path.append(os.getcwd()) -from functions import * -import partition_uids - -# Init -BACKUP_SERVERS = [ - { 'IP': '10.0.0.10', - 'Mounted': False, - 'Name': 'ServerOne', - 'Share': 'Backups', - 'User': 'backup', - 'Pass': 'Abracadabra', - }, - { 'IP': '10.0.0.11', - 'Name': 'ServerTwo', - 'Mounted': False, - 'Share': 'Backups', - 'User': 'backup', - 'Pass': 'Abracadabra', - }, -] -WINDOWS_SERVER = { - 'IP': '10.0.0.10', - 'Name': 'ServerOne', - 'Mounted': False, - 'Share': 'Windows', - 'User': 'backup', # Using these credentials in case both the windows source and backup shares are mounted. - 'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time. -} -WINDOWS_VERSIONS = [ - {'Name': 'Windows 7 Home Basic', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEBASIC', - 'Family': '7'}, - {'Name': 'Windows 7 Home Premium', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEPREMIUM', - 'Family': '7'}, - {'Name': 'Windows 7 Professional', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 PROFESSIONAL', - 'Family': '7'}, - {'Name': 'Windows 7 Ultimate', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 ULTIMATE', - 'Family': '7'}, - - {'Name': 'Windows 8.1', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1', - 'Family': '8', - 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1 Pro', - 'Family': '8'}, - - {'Name': 'Windows 10 Home', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Home', - 'Family': '10', - 'CRLF': True}, - {'Name': 'Windows 10 Pro', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Pro', - 'Family': '10'}, -] -diskpart_script = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) - -## Colors -COLORS = { - 'CLEAR': '\033[0m', - 'RED': '\033[31m', - 'GREEN': '\033[32m', - 'YELLOW': '\033[33m', - 'BLUE': '\033[34m'} - -class AbortError(Exception): - pass - -class BackupError(Exception): - pass - -class SetupError(Exception): - pass - -def abort_to_main_menu(message='Returning to main menu...'): - print_warning(message) - pause('Press Enter to return to main menu... ') - raise AbortError - -def ask(prompt='Kotaero'): - answer = None - prompt = prompt + ' [Y/N]: ' - while answer is None: - tmp = input(prompt) - if re.search(r'^y(es|)$', tmp, re.IGNORECASE): - answer = True - elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE): - answer = False - return answer - -def assign_volume_letters(): - try: - # Run script - with open(diskpart_script, 'w') as script: - for vol in get_volumes(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('assign\n') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except subprocess.CalledProcessError: - pass - -def backup_partition(bin=None, disk=None, par=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if disk is None: - raise Exception('Disk not specified.') - if par is None: - raise Exception('Partition not specified.') - - print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) - if par['Number'] in disk['Bad Partitions']: - print_warning('Skipped.') - else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=none'.format(bin=bin, **par) - if par['Image Exists']: - print_warning('Skipped.') - else: - try: - os.makedirs('{Image Path}'.format(**par), exist_ok=True) - run_program(cmd) - print_success('Complete.') - except subprocess.CalledProcessError as err: - print_error('Failed.') - par['Error'] = err.stderr.decode().splitlines() - raise BackupError - -def convert_to_bytes(size): - size = str(size) - tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) - if tmp: - size = int(tmp.group(1)) - units = tmp.group(2) - if units == 'TB': - size *= 1099511627776 - elif units == 'GB': - size *= 1073741824 - elif units == 'MB': - size *= 1048576 - elif units == 'KB': - size *= 1024 - else: - return -1 - - return size - -def is_valid_image(bin=None, filename=None, imagename=None): - # Bail early - if bin is None: - raise Exception('bin not specified.') - if filename is None: - raise Exception('Filename not specified.') - if imagename is None: - raise Exception('Image Name not specified.') - - cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) - try: - run_program(cmd) - except subprocess.CalledProcessError: - print_error('Invalid image: {filename}'.format(filename=filename)) - return False - - return True - -def find_windows_image(bin, windows_version=None): - """Search for a Windows source image file on local drives and network drives (in that order)""" - image = {} - - # Bail early - if windows_version is None: - raise Exception('Windows version not specified.') - imagefile = windows_version['Image File'] - - # Search local source - process_return = run_program('mountvol') - for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): - for ext in ['esd', 'wim', 'swm']: - filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) - filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) - if os.path.isfile(filename_ext): - if is_valid_image(bin, filename_ext, windows_version['Image Name']): - image['Ext'] = ext - image['File'] = filename - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = tmp[0] - break - - # Check for network source (if necessary) - if not any(image): - if not WINDOWS_SERVER['Mounted']: - mount_windows_share() - for ext in ['esd', 'wim', 'swm']: - filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) - filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) - if os.path.isfile(filename_ext): - if is_valid_image(bin, filename_ext, windows_version['Image Name']): - image['Ext'] = ext - image['File'] = filename - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = None - break - - # Display image to be used (if any) and return - if any(image): - print_info('Using image: {File}.{Ext}'.format(**image)) - return image - else: - print_error('Failed to find Windows source image for {winver}'.format(winver=windows_version['Name'])) - abort_to_main_menu('Aborting Windows setup') - -def format_gpt(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - # print_info('Drive will use a GPT (UEFI) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - script.write('convert gpt\n') - - # System partition - script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives - script.write('format quick fs=fat32 label="System"\n') - script.write('assign letter="S"\n') - - # Microsoft Reserved (MSR) partition - script.write('create partition msr size=128\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Windows"\n') - script.write('assign letter="W"\n') - - # Recovery Tools partition (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery Tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') - - # Run script - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def format_mbr(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - # print_info('Drive will use a MBR (legacy) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - - # System partition - script.write('create partition primary size=100\n') - script.write('format fs=ntfs quick label="System Reserved"\n') - script.write('active\n') - script.write('assign letter="S"\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format fs=ntfs quick label="Windows"\n') - script.write('assign letter="W"\n') - - # Recovery Tools partition (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery"\n') - script.write('assign letter="T"\n') - script.write('set id=27\n') - - # Run script - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def get_attached_disk_info(): - """Get details about the attached disks""" - disks = [] - print_info('Getting drive info...') - - # Assign all the letters - assign_volume_letters() - - # Get disks - disks = get_disks() - - # Get disk details - for disk in disks: - # Get partition style - disk['Table'] = get_table_type(disk) - - # Get disk name/model and physical details - disk.update(get_disk_details(disk)) - - # Get partition info for disk - disk['Partitions'] = get_partitions(disk) - - for par in disk['Partitions']: - # Get partition details - par.update(get_partition_details(disk, par)) - - # Done - return disks - -def get_boot_mode(): - boot_mode = 'Legacy' - try: - reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') - reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] - if reg_value == 2: - boot_mode = 'UEFI' - except: - boot_mode = 'Unknown' - - return boot_mode - -def get_disk_details(disk=None): - details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - # Run script - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('detail disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Set disk name - details['Name'] = tmp[4] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - return details - -def get_disks(): - disks = [] - - try: - # Run script - with open(diskpart_script, 'w') as script: - script.write('list disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append disk numbers - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - disks.append({'Number': _num, 'Size': _size}) - - return disks - -def get_partition_details(disk=None, par=None): - details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - if par is None: - raise Exception('Partition not specified.') - - # Diskpart details - try: - # Run script - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('select partition {Number}\n'.format(**par)) - script.write('detail partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Get volume letter or RAW status - tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) - if tmp: - if tmp.group(1).upper() == 'RAW': - details['FileSystem'] = RAW - else: - details['Letter'] = tmp.group(1) - - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Get MBR type / GPT GUID for extra details on "Unknown" partitions - guid = partition_uids.lookup_guid(details['Type']) - if guid is not None: - details.update({ - 'Description': guid.get('Description', ''), - 'OS': guid.get('OS', '')}) - - if 'Letter' in details: - # Disk usage - tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) - details['Used Space'] = human_readable_size(tmp.used) - - # fsutil details - try: - process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Add "Feature" lines - details['File System Features'] = [s.strip() for s in tmp if ':' not in s] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Set Volume Name - details['Name'] = details.get('Volume Name', '') - - # Set FileSystem Type - if details.get('FileSystem', '') != 'RAW': - details['FileSystem'] = details.get('File System Name', 'Unknown') - - return details - -def get_partitions(disk=None): - partitions = [] - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - # Run script - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('list partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append partition numbers - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - partitions.append({'Number': _num, 'Size': _size}) - - return partitions - -def get_table_type(disk=None): - _type = 'Unknown' - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('uniqueid disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): - _type = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): - _type = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): - _type = 'MBR' - - return _type - -def get_ticket_id(): - ticket_id = None - while ticket_id is None: - tmp = input('Enter ticket number: ') - if re.match(r'^([0-9]+([\-_]*\w+|))$', tmp): - ticket_id = tmp - - return ticket_id - -def get_volumes(): - vols = [] - - try: - # Run script - with open(diskpart_script, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append volume numbers - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): - vols.append({'Number': tmp[0], 'Letter': tmp[1]}) - - return vols - -def human_readable_size(size, decimals=0): - # Prep string formatting - width = 3+decimals - if decimals > 0: - width += 1 - human_format = '>{width}.{decimals}f'.format(width=width, decimals=decimals) - tmp = '' - - # Convert size to int - try: - size = int(size) - except ValueError: - size = convert_to_bytes(size) - - # Verify we have a valid size - if size <= 0: - return '{size:>{width}} b'.format(size='???', width=width) - - # Format string - if size >= 1099511627776: - size /= 1099511627776 - tmp = '{size:{human_format}} Tb'.format(size=size, human_format=human_format) - elif size >= 1073741824: - size /= 1073741824 - tmp = '{size:{human_format}} Gb'.format(size=size, human_format=human_format) - elif size >= 1048576: - size /= 1048576 - tmp = '{size:{human_format}} Mb'.format(size=size, human_format=human_format) - elif size >= 1024: - size /= 1024 - tmp = '{size:{human_format}} Kb'.format(size=size, human_format=human_format) - else: - tmp = '{size:{human_format}} b'.format(size=size, human_format=human_format) - - # Return - return tmp - -def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): - """Display options in a menu for user selection""" - - # Bail early - if (len(main_entries) + len(action_entries) == 0): - raise Exception("MenuError: No items given") - - # Build menu - menu_splash = '{title}\n\n'.format(title=title) - valid_answers = [] - if (secret_exit): - valid_answers.append('Q') - - # Add main entries - if (len(main_entries) > 0): - for i in range(len(main_entries)): - entry = main_entries[i] - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(str(i+1)) - menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) - menu_splash += '\n' - - # Add action entries - if (len(action_entries) > 0): - for entry in action_entries: - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(entry['Letter']) - menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) - menu_splash += '\n' - - answer = '' - - while (answer.upper() not in valid_answers): - os.system('cls') - print(menu_splash) - answer = input('{prompt}: '.format(prompt=prompt)) - - return answer.upper() - -def mount_backup_shares(): - """Mount the backup shares for use as destinations for backup image creation""" - - # Attempt to mount share(s) - for server in BACKUP_SERVERS: - # Blindly skip if we mounted earlier - if server['Mounted']: - continue - else: - try: - # Test connection - run_program('ping -w 800 -n 2 {IP}'.format(**server)) - - # Mount - run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**server)) - print_info('Mounted {Name}'.format(**server)) - server['Mounted'] = True - except subprocess.CalledProcessError: - print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**server)) - time.sleep(1) - except: - print_warning('Failed to mount \\\\{Name}\\{Share} ({IP})'.format(**server)) - time.sleep(1) - -def mount_windows_share(): - """Mount the Windows images share for use in Windows setup""" - - # Blindly skip if we mounted earlier - if WINDOWS_SERVER['Mounted']: - return None - else: - try: - # Test connection - run_program('ping -w 800 -n 2 {IP}'.format(**WINDOWS_SERVER)) - # Mount - run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**WINDOWS_SERVER)) - print_info('Mounted {Name}'.format(**WINDOWS_SERVER)) - WINDOWS_SERVER['Mounted'] = True - except subprocess.CalledProcessError: - print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**WINDOWS_SERVER)) - time.sleep(1) - except: - print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) - time.sleep(1) - -def pause(prompt='Press Enter to continue... '): - input(prompt) - -def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): - disk['Backup Warnings'] = '\n' - disk['Clobber Risk'] = [] - width = len(str(len(disk['Partitions']))) - - # Bail early - if dest is None: - raise Exception('Destination not provided.') - if disk is None: - raise Exception('Disk not provided.') - if ticket_id is None: - raise Exception('Ticket ID not provided.') - - # Get partition totals - disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE)] - disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) - - # Bail if no valid partitions are found (those that can be imaged) - if disk['Valid Partitions'] <= 0: - abort_to_main_menu(' No partitions can be imaged for the selected drive') - - # Prep partitions - for par in disk['Partitions']: - if par['Number'] in disk['Bad Partitions']: - par['Display String'] = '{YELLOW} * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS}){CLEAR}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par, - **COLORS) - else: - # Update info for WIM capturing - par['Image Name'] = str(par['Name']) - if par['Image Name'] == '': - par['Image Name'] = 'Unknown' - if 'IP' in dest: - par['Image Path'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket_id, **dest) - else: - par['Image Path'] = '{Letter}:\\{ticket}'.format(ticket=ticket_id, **dest) - par['Image File'] = '{Number}_{Image Name}'.format(**par) - par['Image File'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['Image File'])) - - # Check for existing backups - par['Image Exists'] = False - if os.path.exists('{Image Path}\\{Image File}'.format(**par)): - par['Image Exists'] = True - disk['Clobber Risk'].append(par['Number']) - par['Display String'] = '{BLUE} + '.format(**COLORS) - else: - par['Display String'] = '{CLEAR} '.format(**COLORS) - - # Append rest of Display String for valid/clobber partitions - par['Display String'] += 'Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}{CLEAR}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par, - **COLORS) - - # Set description for bad partitions - if len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] += '{YELLOW} * Unable to backup these partitions{CLEAR}\n'.format(**COLORS) - elif len(disk['Bad Partitions']) == 1: - print_warning(' * Unable to backup this partition') - disk['Backup Warnings'] += '{YELLOW} * Unable to backup this partition{CLEAR}\n'.format(**COLORS) - - # Set description for partitions that would be clobbered - if len(disk['Clobber Risk']) > 1: - disk['Backup Warnings'] += '{BLUE} + These partitions already have backup images on {Name}{CLEAR}\n'.format(**dest, **COLORS) - elif len(disk['Clobber Risk']) == 1: - disk['Backup Warnings'] += '{BLUE} + This partition already has a backup image on {Name}{CLEAR}\n'.format(**dest, **COLORS) - - # Set warning for skipped partitions - if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] += '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) - if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) == 1: - disk['Backup Warnings'] += '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) - -def prep_disk_for_formatting(disk=None): - disk['Format Warnings'] = '\n' - width = len(str(len(disk['Partitions']))) - - # Bail early - if disk is None: - raise Exception('Disk not provided.') - - # Set boot method and partition table type - disk['Use GPT'] = True - if (get_boot_mode() == 'UEFI'): - if (not ask("Setup Windows to use UEFI booting?")): - disk['Use GPT'] = False - else: - if (ask("Setup Windows to use BIOS/Legacy booting?")): - disk['Use GPT'] = False - - # Set Display and Warning Strings - if len(disk['Partitions']) == 0: - disk['Format Warnings'] += 'No partitions found\n' - for par in disk['Partitions']: - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - # FileSystem not accessible to WinPE. List partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) - else: - # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) - -def print_error(message='Generic error', **kwargs): - print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_info(message='Generic info', **kwargs): - print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_success(message='Generic success', **kwargs): - print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_warning(message='Generic warning', **kwargs): - print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def remove_volume_letters(keep=''): - if keep is None: - keep = '' - try: - # Run script - with open(diskpart_script, 'w') as script: - for vol in get_volumes(): - if vol['Letter'].upper() != keep.upper(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('remove noerr\n') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except subprocess.CalledProcessError: - pass - -def run_program(cmd=None, args=[], check=True): - if cmd is None: - raise Exception('No program passed.') - - if len(args) > 0: - args = [cmd] + args - process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - else: - process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - - return process_return - -def select_destination(): - # Build menu - dests = [] - for server in BACKUP_SERVERS: - if server['Mounted']: - dests.append(server) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Size check - for dest in dests: - if 'IP' in dest: - dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) - else: - dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) - dest['Free Space'] = human_readable_size(dest['Usage'].free) - dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) - - # Show menu or bail - if len(dests) > 0: - selection = menu_select('Where are we backing up to?', dests, actions) - if selection == 'M': - return None - else: - return dests[int(selection)-1] - else: - print_warning('No backup destinations found.') - return None - -def select_disk(prompt='Which disk?'): - """Select a disk from the attached disks""" - disks = get_attached_disk_info() - - # Build menu - disk_options = [] - for disk in disks: - display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if len(disk['Partitions']) > 0: - pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: - # Show unsupported partition(s) in RED - par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - par_skip = True - if par_skip: - display_name += COLORS['YELLOW'] - - # Main text - display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) - if par['Name'] != '': - display_name += '\t"{Name}"'.format(**par) - - # Clear color (if set above) - if par_skip: - display_name += COLORS['CLEAR'] - else: - display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) - disk_options.append({'Name': display_name, 'Disk': disk}) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select(prompt, disk_options, actions) - - if (selection.isnumeric()): - return disk_options[int(selection)-1]['Disk'] - elif (selection == 'M'): - abort_to_main_menu() - -def select_minidump_path(): - dumps = [] - - # Assign volume letters first - assign_volume_letters() - - # Search for minidumps - tmp = run_program('mountvol') - tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] - # Remove RAMDisk letter - if 'X' in tmp: - tmp.remove('X') - for drive in tmp: - if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): - dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) - - # Check results before showing menu - if len(dumps) == 0: - print_error(' No BSoD / MiniDump paths found') - time.sleep(2) - return None - - # Menu - selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) - return dumps[int(selection) - 1]['Name'] - -def select_windows_version(): - actions = [{'Name': 'Main Menu', 'Letter': 'M'},] - - # Menu loop - selection = menu_select('Which version of Windows are we installing?', WINDOWS_VERSIONS, actions) - - if selection.isnumeric(): - return WINDOWS_VERSIONS[int(selection)-1] - elif selection == 'M': - abort_to_main_menu() - -def setup_windows(bin=None, windows_image=None, windows_version=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if windows_image is None: - raise Exception('Windows image not specified.') - if windows_version is None: - raise Exception('Windows version not specified.') - - # Apply image - cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) - run_program(cmd) - -def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T'): - # Bail early - if windows_version is None: - raise Exception('Windows version not specified.') - - _win = '{win}:\\Windows'.format(win=windows_letter) - _winre = '{win}\\System32\\Recovery\\WinRE.wim'.format(win=_win) - _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) - - if re.search(r'^(8|10)', windows_version['Family']): - # Copy WinRE.wim - os.makedirs(_dest, exist_ok=True) - shutil.copy(_winre, '{dest}\\WinRE.wim'.format(dest=_dest)) - - # Set location - run_program('{win}\\System32\\reagentc /setreimage /path {dest} /target {win}'.format(dest=_dest, win=_win)) - else: - # Only supported on Windows 8 and above - raise SetupError - -def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): - run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) - -def verify_wim_backup(bin=None, par=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if par is None: - raise Exception('Partition not specified.') - - # Verify hiding all output for quicker verification - print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) - cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}\\{Image File}" --nocheck'.format(bin=bin, **par) - if not os.path.exists('{Image Path}\\{Image File}'.format(**par)): - print_error('Missing.') - else: - try: - run_program(cmd) - print_success('OK.') - except subprocess.CalledProcessError as err: - print_error('Damaged.') - par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() - raise BackupError - -if __name__ == '__main__': - print("This file is not meant to be called directly.") diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py new file mode 100644 index 00000000..94f3b103 --- /dev/null +++ b/Scripts/functions/backup.py @@ -0,0 +1,486 @@ +# Wizard Kit PE: Functions - Backup + +from functions.common import * +import partition_uids + +def assign_volume_letters(): + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('assign\n') + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + except subprocess.CalledProcessError: + pass + +def backup_partition(bin=None, disk=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if disk is None: + raise Exception('Disk not specified.') + if par is None: + raise Exception('Partition not specified.') + + print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) + if par['Number'] in disk['Bad Partitions']: + print_warning('Skipped.') + else: + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=none'.format(bin=bin, **par) + if par['Image Exists']: + print_warning('Skipped.') + else: + try: + os.makedirs('{Image Path}'.format(**par), exist_ok=True) + run_program(cmd) + print_success('Complete.') + except subprocess.CalledProcessError as err: + print_error('Failed.') + par['Error'] = err.stderr.decode().splitlines() + raise BackupError + +def get_attached_disk_info(): + """Get details about the attached disks""" + disks = [] + print_info('Getting drive info...') + + # Assign all the letters + assign_volume_letters() + + # Get disks + disks = get_disks() + + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for par in disk['Partitions']: + # Get partition details + par.update(get_partition_details(disk, par)) + + # Done + return disks + +def get_disk_details(disk=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('detail disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Set disk name + details['Name'] = tmp[4] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + return details + +def get_disks(): + disks = [] + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append disk numbers + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + disks.append({'Number': _num, 'Size': _size}) + + return disks + +def get_partition_details(disk=None, par=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Diskpart details + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('select partition {Number}\n'.format(**par)) + script.write('detail partition\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Get volume letter or RAW status + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) + if tmp: + if tmp.group(1).upper() == 'RAW': + details['FileSystem'] = RAW + else: + details['Letter'] = tmp.group(1) + + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + guid = partition_uids.lookup_guid(details['Type']) + if guid is not None: + details.update({ + 'Description': guid.get('Description', ''), + 'OS': guid.get('OS', '')}) + + if 'Letter' in details: + # Disk usage + tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) + details['Used Space'] = human_readable_size(tmp.used) + + # fsutil details + try: + process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Add "Feature" lines + details['File System Features'] = [s.strip() for s in tmp if ':' not in s] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Set Volume Name + details['Name'] = details.get('Volume Name', '') + + # Set FileSystem Type + if details.get('FileSystem', '') != 'RAW': + details['FileSystem'] = details.get('File System Name', 'Unknown') + + return details + +def get_partitions(disk=None): + partitions = [] + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('list partition\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append partition numbers + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + partitions.append({'Number': _num, 'Size': _size}) + + return partitions + +def get_table_type(disk=None): + _type = 'Unknown' + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('uniqueid disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): + _type = 'GPT' + elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): + _type = 'RAW' + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): + _type = 'MBR' + + return _type + +def get_volumes(): + vols = [] + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append volume numbers + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): + vols.append({'Number': tmp[0], 'Letter': tmp[1]}) + + return vols + +def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): + disk['Backup Warnings'] = '\n' + disk['Clobber Risk'] = [] + width = len(str(len(disk['Partitions']))) + + # Bail early + if dest is None: + raise Exception('Destination not provided.') + if disk is None: + raise Exception('Disk not provided.') + if ticket_id is None: + raise Exception('Ticket ID not provided.') + + # Get partition totals + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE)] + disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) + + # Bail if no valid partitions are found (those that can be imaged) + if disk['Valid Partitions'] <= 0: + abort_to_main_menu(' No partitions can be imaged for the selected drive') + + # Prep partitions + for par in disk['Partitions']: + if par['Number'] in disk['Bad Partitions']: + par['Display String'] = '{YELLOW} * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS}){CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + else: + # Update info for WIM capturing + par['Image Name'] = str(par['Name']) + if par['Image Name'] == '': + par['Image Name'] = 'Unknown' + if 'IP' in dest: + par['Image Path'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket_id, **dest) + else: + par['Image Path'] = '{Letter}:\\{ticket}'.format(ticket=ticket_id, **dest) + par['Image File'] = '{Number}_{Image Name}'.format(**par) + par['Image File'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['Image File'])) + + # Check for existing backups + par['Image Exists'] = False + if os.path.exists('{Image Path}\\{Image File}'.format(**par)): + par['Image Exists'] = True + disk['Clobber Risk'].append(par['Number']) + par['Display String'] = '{BLUE} + '.format(**COLORS) + else: + par['Display String'] = '{CLEAR} '.format(**COLORS) + + # Append rest of Display String for valid/clobber partitions + par['Display String'] += 'Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}{CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + + # Set description for bad partitions + if len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] += '{YELLOW} * Unable to backup these partitions{CLEAR}\n'.format(**COLORS) + elif len(disk['Bad Partitions']) == 1: + print_warning(' * Unable to backup this partition') + disk['Backup Warnings'] += '{YELLOW} * Unable to backup this partition{CLEAR}\n'.format(**COLORS) + + # Set description for partitions that would be clobbered + if len(disk['Clobber Risk']) > 1: + disk['Backup Warnings'] += '{BLUE} + These partitions already have backup images on {Name}{CLEAR}\n'.format(**dest, **COLORS) + elif len(disk['Clobber Risk']) == 1: + disk['Backup Warnings'] += '{BLUE} + This partition already has a backup image on {Name}{CLEAR}\n'.format(**dest, **COLORS) + + # Set warning for skipped partitions + if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] += '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) + if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) == 1: + disk['Backup Warnings'] += '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) + +def prep_disk_for_formatting(disk=None): + disk['Format Warnings'] = '\n' + width = len(str(len(disk['Partitions']))) + + # Bail early + if disk is None: + raise Exception('Disk not provided.') + + # Set boot method and partition table type + disk['Use GPT'] = True + if (get_boot_mode() == 'UEFI'): + if (not ask("Setup Windows to use UEFI booting?")): + disk['Use GPT'] = False + else: + if (ask("Setup Windows to use BIOS/Legacy booting?")): + disk['Use GPT'] = False + + # Set Display and Warning Strings + if len(disk['Partitions']) == 0: + disk['Format Warnings'] += 'No partitions found\n' + for par in disk['Partitions']: + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): + # FileSystem not accessible to WinPE. List partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + else: + # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + +def remove_volume_letters(keep=''): + if keep is None: + keep = '' + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('remove noerr\n') + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + except subprocess.CalledProcessError: + pass + +def select_backup_destination(): + # Build menu + dests = [] + for server in BACKUP_SERVERS: + if server['Mounted']: + dests.append(server) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Size check + for dest in dests: + if 'IP' in dest: + dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) + else: + dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) + dest['Free Space'] = human_readable_size(dest['Usage'].free) + dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) + + # Show menu or bail + if len(dests) > 0: + selection = menu_select('Where are we backing up to?', dests, actions) + if selection == 'M': + return None + else: + return dests[int(selection)-1] + else: + print_warning('No backup destinations found.') + return None + +def select_disk(prompt='Which disk?'): + """Select a disk from the attached disks""" + disks = get_attached_disk_info() + + # Build menu + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + if len(disk['Partitions']) > 0: + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Show unsupported partition(s) in RED + par_skip = False + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): + par_skip = True + if par_skip: + display_name += COLORS['YELLOW'] + + # Main text + display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) + if par['Name'] != '': + display_name += '\t"{Name}"'.format(**par) + + # Clear color (if set above) + if par_skip: + display_name += COLORS['CLEAR'] + else: + display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select(prompt, disk_options, actions) + + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + abort_to_main_menu() + +def verify_wim_backup(bin=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Verify hiding all output for quicker verification + print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) + cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}\\{Image File}" --nocheck'.format(bin=bin, **par) + if not os.path.exists('{Image Path}\\{Image File}'.format(**par)): + print_error('Missing.') + else: + try: + run_program(cmd) + print_success('OK.') + except subprocess.CalledProcessError as err: + print_error('Damaged.') + par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + raise BackupError + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py new file mode 100644 index 00000000..a0453a95 --- /dev/null +++ b/Scripts/functions/common.py @@ -0,0 +1,682 @@ +# Wizard Kit PE: Functions - Common + +import os +import psutil +import re +import shutil +import subprocess +import sys +import time +import traceback +import winreg + +from subprocess import CalledProcessError + +from settings.main import * +from settings.tools import * + +# Global variables +global_vars = {} + +# STATIC VARIABLES +COLORS = { + 'CLEAR': '\033[0m', + 'RED': '\033[31m', + 'GREEN': '\033[32m', + 'YELLOW': '\033[33m', + 'BLUE': '\033[34m' +} +HKU = winreg.HKEY_USERS +HKCU = winreg.HKEY_CURRENT_USER +HKLM = winreg.HKEY_LOCAL_MACHINE + +# Error Classes +class BIOSKeyNotFoundError(Exception): + pass + +class BinNotFoundError(Exception): + pass + +class GenericError(Exception): + pass + +class GenericRepair(Exception): + pass + +class MultipleInstallationsError(Exception): + pass + +class NotInstalledError(Exception): + pass + +class NoProfilesError(Exception): + pass + +class PathNotFoundException(Exception): + pass + +class UnsupportedOSError(Exception): + pass + +# General functions +def abort(): + """Abort script.""" + print_warning('Aborted.') + sleep(5) + exit_script() + +def ask(prompt='Kotaero!'): + """Prompt the user with a Y/N question, log answer, and return a bool.""" + answer = None + prompt = '{} [Y/N]: '.format(prompt) + while answer is None: + tmp = input(prompt) + if re.search(r'^y(es|)$', tmp, re.IGNORECASE): + answer = True + elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE): + answer = False + message = '{prompt}{answer_text}'.format( + prompt = prompt, + answer_text = 'Yes' if answer else 'No') + print_log(message=message) + return answer + +def convert_to_bytes(size): + """Convert human-readable size str to bytes and return an int.""" + size = str(size) + tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) + if tmp: + size = int(tmp.group(1)) + units = tmp.group(2) + if units == 'TB': + size *= 1099511627776 + elif units == 'GB': + size *= 1073741824 + elif units == 'MB': + size *= 1048576 + elif units == 'KB': + size *= 1024 + else: + return -1 + + return size + +def exit_script(return_value=0): + """Exits the script after some cleanup and opens the log (if set).""" + # Remove dirs (if empty) + for dir in ['BackupDir', 'LogDir', 'TmpDir']: + try: + dir = global_vars[dir] + os.rmdir(dir) + except Exception: + pass + + # Open Log (if it exists) + log = global_vars.get('LogFile', '') + if log and os.path.exists(log): + try: + extract_item('NotepadPlusPlus', silent=True) + popen_program( + [global_vars['Tools']['NotepadPlusPlus'], + global_vars['LogFile']]) + except Exception: + print_error('ERROR: Failed to extract Notepad++ and open log.') + pause('Press Enter to exit...') + + # Kill Caffeine if still running + kill_process('caffeine.exe') + + # Exit + sys.exit(return_value) + +def extract_item(item, filter='', silent=False): + """Extract item from .cbin into .bin.""" + cmd = [ + global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0', + '-p{ArchivePassword}'.format(**global_vars), + r'-o{BinDir}\{item}'.format(item=item, **global_vars), + r'{CBinDir}\{item}.7z'.format(item=item, **global_vars), + filter] + if not silent: + print_standard('Extracting "{item}"...'.format(item=item)) + try: + run_program(cmd) + except subprocess.CalledProcessError: + if not silent: + print_warning('WARNING: Errors encountered while exctracting data') + +def get_ticket_number(): + """Get TicketNumber from user, save in LogDir, and return as str.""" + ticket_number = None + while ticket_number is None: + _input = input('Enter ticket number: ') + if re.match(r'^([0-9]+([-_]?\w+|))$', _input): + ticket_number = _input + with open(r'{LogDir}\TicketNumber'.format(**global_vars), 'w') as f: + f.write(ticket_number) + return ticket_number + +def human_readable_size(size, decimals=0): + """Convert size in bytes to a human-readable format and return a str.""" + # Prep string formatting + width = 3+decimals + if decimals > 0: + width += 1 + + # Convert size to int + try: + size = int(size) + except ValueError: + size = convert_to_bytes(size) + + # Verify we have a valid size + if size <= 0: + return '{size:>{width}} b'.format(size='???', width=width) + + # Convert to sensible units + if size >= 1099511627776: + size /= 1099511627776 + units = 'Tb' + elif size >= 1073741824: + size /= 1073741824 + units = 'Gb' + elif size >= 1048576: + size /= 1048576 + units = 'Mb' + elif size >= 1024: + size /= 1024 + units = 'Kb' + else: + units = ' b' + + # Return + return '{size:>{width}.{decimals}f} {units}'.format( + size=size, width=width, decimals=decimals, units=units) + +def kill_process(name): + """Kill any running caffeine.exe processes.""" + for proc in psutil.process_iter(): + if proc.name() == name: + proc.kill() + +def major_exception(): + """Display traceback and exit""" + print_error('Major exception') + print_warning(SUPPORT_MESSAGE) + print(traceback.format_exc()) + print_log(traceback.format_exc()) + sleep(30) + pause('Press Enter to exit...') + exit_script(1) + +def menu_select(title='~ Untitled Menu ~', + prompt='Please make a selection', secret_exit=False, + main_entries=[], action_entries=[], disabled_label='DISABLED'): + """Display options in a menu and return selected option as a str.""" + # Bail early + if not main_entries and not action_entries: + raise Exception("MenuError: No items given") + + # Build menu + menu_splash = '{}\n\n'.format(title) + width = len(str(len(main_entries))) + valid_answers = [] + if (secret_exit): + valid_answers.append('Q') + + # Add main entries + for i in range(len(main_entries)): + entry = main_entries[i] + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + entry_str = '{number:>{width}}: {name}'.format( + number = i+1, + width = width, + name = entry.get('Display Name', entry['Name'])) + if entry.get('Disabled', False): + entry_str = '{YELLOW}{entry_str} ({disabled}){CLEAR}'.format( + entry_str = entry_str, + disabled = disabled_label, + **COLORS) + else: + valid_answers.append(str(i+1)) + menu_splash += '{}\n'.format(entry_str) + menu_splash += '\n' + + # Add action entries + for entry in action_entries: + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(entry['Letter']) + menu_splash += '{letter:>{width}}: {name}\n'.format( + letter = entry['Letter'].upper(), + width = len(str(len(action_entries))), + name = entry['Name']) + menu_splash += '\n' + + answer = '' + + while (answer.upper() not in valid_answers): + os.system('cls') + print(menu_splash) + answer = input('{}: '.format(prompt)) + + return answer.upper() + +def non_clobber_rename(full_path): + """Append suffix to path, if necessary, to avoid clobbering path""" + new_path = full_path + _i = 1; + while os.path.exists(new_path): + new_path = '{path}_{i}'.format(i=_i, path=full_path) + _i += 1 + + return new_path + +def pause(prompt='Press Enter to continue... '): + """Simple pause implementation.""" + input(prompt) + +def ping(addr='google.com'): + """Attempt to ping addr.""" + cmd = ['ping', '-n', '2', addr] + run_program(cmd) + +def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs): + """Run program and return a subprocess.Popen object.""" + startupinfo=None + if minimized: + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = 6 + + if pipe: + popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo) + + return popen_obj + +def print_error(*args, **kwargs): + """Prints message to screen in RED.""" + print_standard(*args, color=COLORS['RED'], **kwargs) + +def print_info(*args, **kwargs): + """Prints message to screen in BLUE.""" + print_standard(*args, color=COLORS['BLUE'], **kwargs) + +def print_standard(message='Generic info', + color=None, end='\n', timestamp=True, **kwargs): + """Prints message to screen and log (if set).""" + display_message = message + if color: + display_message = color + message + COLORS['CLEAR'] + # **COLORS is used below to support non-"standard" color printing + print(display_message.format(**COLORS), end=end, **kwargs) + print_log(message, end, timestamp) + +def print_success(*args, **kwargs): + """Prints message to screen in GREEN.""" + print_standard(*args, color=COLORS['GREEN'], **kwargs) + +def print_warning(*args, **kwargs): + """Prints message to screen in YELLOW.""" + print_standard(*args, color=COLORS['YELLOW'], **kwargs) + +def print_log(message='', end='\n', timestamp=True): + time_str = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else '' + if 'LogFile' in global_vars and global_vars['LogFile'] is not None: + with open(global_vars['LogFile'], 'a') as f: + for line in message.splitlines(): + f.write('{timestamp}{line}{end}'.format( + timestamp = time_str, + line = line, + end = end)) + +def run_program(cmd, args=[], check=True, pipe=True, shell=False): + """Run program and return a subprocess.CompletedProcess object.""" + if args: + # Deprecated so let's raise an exception to find & fix all occurances + print_error('ERROR: Using args is no longer supported.') + raise Exception + cmd = [c for c in cmd if c] + if shell: + cmd = ' '.join(cmd) + + if pipe: + process_return = subprocess.run(cmd, check=check, shell=shell, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + process_return = subprocess.run(cmd, check=check, shell=shell) + + return process_return + +def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): + """Display info with formatting.""" + print_standard('{indent}{message:<{width}}{info}'.format( + indent=' '*indent, width=width, message=message, info=info)) + +def sleep(seconds=2): + """Wait for a while.""" + time.sleep(seconds) + +def stay_awake(): + """Prevent the system from sleeping or hibernating.""" + # Bail if caffeine is already running + for proc in psutil.process_iter(): + if proc.name() == 'caffeine.exe': + return + # Extract and run + extract_item('Caffeine', silent=True) + try: + popen_program(global_vars['Tools']['Caffeine']) + except Exception: + print_error('ERROR: No caffeine available.') + print_warning('Please set the power setting to High Performance.') + +def get_exception(s): + """Get exception by name, returns Exception object.""" + return getattr(sys.modules[__name__], s) + +def try_and_print(message='Trying...', + function=None, cs='CS', ns='NS', other_results={}, + catch_all=True, print_return=False, silent_function=True, + indent=8, width=32, *args, **kwargs): + """Run function, print if successful or not, and return dict. + + other_results is in the form of + { + 'Warning': {'ExceptionClassName': 'Result Message'}, + 'Error': {'ExceptionClassName': 'Result Message'} + } + The the ExceptionClassNames will be excepted conditions + and the result string will be printed in the correct color. + catch_all=False will result in unspecified exceptions being re-raised.""" + err = None + w_exceptions = other_results.get('Warning', {}).keys() + w_exceptions = tuple(get_exception(e) for e in w_exceptions) + e_exceptions = other_results.get('Error', {}).keys() + e_exceptions = tuple(get_exception(e) for e in e_exceptions) + w_results = other_results.get('Warning', {}) + e_results = other_results.get('Error', {}) + + # Run function and catch errors + print_standard('{indent}{message:<{width}}'.format( + indent=' '*indent, message=message, width=width), end='', flush=True) + try: + out = function(*args, **kwargs) + if print_return: + print_standard(out[0], timestamp=False) + for item in out[1:]: + print_standard('{indent}{item}'.format( + indent=' '*(indent+width), item=item)) + elif silent_function: + print_success(cs, timestamp=False) + except w_exceptions as e: + _result = w_results.get(e.__class__.__name__, 'Warning') + print_warning(_result, timestamp=False) + err = e + except e_exceptions as e: + _result = e_results.get(e.__class__.__name__, 'Error') + print_error(_result, timestamp=False) + err = e + except Exception: + print_error(ns, timestamp=False) + err = traceback.format_exc() + + # Return or raise? + if bool(err) and not catch_all: + raise + else: + return {'CS': not bool(err), 'Error': err} + +def upload_data(path, file): + """Add CLIENT_INFO_SERVER to authorized connections and upload file.""" + if not ENABLED_UPLOAD_DATA: + raise GenericError('Feature disabled.') + + extract_item('PuTTY', filter='wizkit.ppk psftp.exe', silent=True) + + # Authorize connection to the server + winreg.CreateKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys') + with winreg.OpenKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys', + access=winreg.KEY_WRITE) as key: + winreg.SetValueEx(key, + 'rsa2@22:{IP}'.format(**CLIENT_INFO_SERVER), 0, + winreg.REG_SZ, CLIENT_INFO_SERVER['RegEntry']) + + # Write batch file + with open(r'{TmpDir}\psftp.batch'.format(**global_vars), + 'w', encoding='ascii') as f: + f.write('lcd "{path}"\n'.format(path=path)) + f.write('cd "{Share}"\n'.format(**CLIENT_INFO_SERVER)) + f.write('mkdir {TicketNumber}\n'.format(**global_vars)) + f.write('cd {TicketNumber}\n'.format(**global_vars)) + f.write('put "{file}"\n'.format(file=file)) + + # Upload Info + cmd = [ + global_vars['Tools']['PuTTY-PSFTP'], + '-noagent', + '-i', r'{BinDir}\PuTTY\wizkit.ppk'.format(**global_vars), + '{User}@{IP}'.format(**CLIENT_INFO_SERVER), + '-b', r'{TmpDir}\psftp.batch'.format(**global_vars)] + run_program(cmd) + +def upload_info(): + """Upload compressed Info file to the NAS as set in settings.main.py.""" + if not ENABLED_UPLOAD_DATA: + raise GenericError('Feature disabled.') + + path = '{ClientDir}'.format(**global_vars) + file = 'Info_{Date-Time}.7z'.format(**global_vars) + upload_data(path, file) + +def compress_info(): + """Compress ClientDir info folders with 7-Zip for upload_info().""" + path = '{ClientDir}'.format(**global_vars) + file = 'Info_{Date-Time}.7z'.format(**global_vars) + _cmd = [ + global_vars['Tools']['SevenZip'], + 'a', '-t7z', '-mx=9', '-bso0', '-bse0', + r'{}\{}'.format(path, file), + r'{ClientDir}\Info'.format(**global_vars)] + run_program(_cmd) + +def wait_for_process(name, poll_rate=3): + """Wait for process by name.""" + running = True + while running: + sleep(poll_rate) + running = False + for proc in psutil.process_iter(): + if re.search(r'^{}'.format(name), proc.name(), re.IGNORECASE): + running = True + sleep(1) + +# global_vars functions +def init_global_vars(): + """Sets global variables based on system info.""" + print_info('Initializing') + os.system('title Wizard Kit') + init_functions = [ + ['Checking .bin...', find_bin], + ['Checking environment...', set_common_vars], + ['Checking OS...', check_os], + ['Checking tools...', check_tools], + ['Creating folders...', make_tmp_dirs], + ['Clearing collisions...', clean_env_vars], + ] + try: + for f in init_functions: + try_and_print( + message=f[0], function=f[1], + cs='Done', ns='Error', catch_all=False) + except: + major_exception() + +def check_os(): + """Set OS specific variables.""" + tmp = {} + + # Query registry + _reg_path = winreg.OpenKey( + HKLM, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') + for key in ['CSDVersion', 'CurrentBuild', 'CurrentBuildNumber', + 'CurrentVersion', 'ProductName']: + try: + tmp[key] = winreg.QueryValueEx(_reg_path, key)[0] + if key in ['CurrentBuild', 'CurrentBuildNumber']: + tmp[key] = int(tmp[key]) + except ValueError: + # Couldn't convert Build to int so this should be interesting... + tmp[key] = 0 + except Exception: + tmp[key] = 'Unknown' + + # Determine OS bit depth + tmp['Arch'] = 32 + if 'PROGRAMFILES(X86)' in global_vars['Env']: + tmp['Arch'] = 64 + + # Determine OS Name + tmp['Name'] = '{ProductName} {CSDVersion}'.format(**tmp) + if tmp['CurrentBuild'] == 9600: + tmp['Name'] += ' Update' # Win 8.1u + if tmp['CurrentBuild'] == 10240: + tmp['Name'] += ' Release 1507 "Threshold 1"' + if tmp['CurrentBuild'] == 10586: + tmp['Name'] += ' Release 1511 "Threshold 2"' + if tmp['CurrentBuild'] == 14393: + tmp['Name'] += ' Release 1607 "Redstone 1" / "Anniversary Update"' + if tmp['CurrentBuild'] == 15063: + tmp['Name'] += ' Release 1703 "Redstone 2" / "Creators Update"' + if tmp['CurrentBuild'] == 16299: + tmp['Name'] += ' Release 1709 "Redstone 3" / "Fall Creators Update"' + tmp['Name'] = tmp['Name'].replace('Service Pack ', 'SP') + tmp['Name'] = tmp['Name'].replace('Unknown Release', 'Release') + tmp['Name'] = re.sub(r'\s+', ' ', tmp['Name']) + + # Determine OS version + name = '{Name} x{Arch}'.format(**tmp) + if tmp['CurrentVersion'] == '6.0': + tmp['Version'] = 'Vista' + name += ' (very outdated)' + elif tmp['CurrentVersion'] == '6.1': + tmp['Version'] = '7' + if tmp['CSDVersion'] == 'Service Pack 1': + name += ' (outdated)' + else: + name += ' (very outdated)' + elif tmp['CurrentVersion'] in ['6.2', '6.3']: + if int(tmp['CurrentBuildNumber']) <= 9600: + tmp['Version'] = '8' + elif int(tmp['CurrentBuildNumber']) >= 10240: + tmp['Version'] = '10' + if tmp['CurrentBuild'] in [9200, 10240, 10586]: + name += ' (very outdated)' + elif tmp['CurrentBuild'] in [9600, 14393, 15063]: + name += ' (outdated)' + elif tmp['CurrentBuild'] == 16299: + pass # Current Win10 + else: + name += ' (unrecognized)' + tmp['DisplayName'] = name + + # == vista == + # 6.0.6000 + # 6.0.6001 + # 6.0.6002 + # ==== 7 ==== + # 6.1.7600 + # 6.1.7601 + # 6.1.7602 + # ==== 8 ==== + # 6.2.9200 + # === 8.1 === + # 6.3.9200 + # === 8.1u == + # 6.3.9600 + # === 10 v1507 "Threshold 1" == + # 6.3.10240 + # === 10 v1511 "Threshold 2" == + # 6.3.10586 + # === 10 v1607 "Redstone 1" "Anniversary Update" == + # 6.3.14393 + # === 10 v1703 "Redstone 2" "Creators Update" == + # 6.3.15063 + # === 10 v1709 "Redstone 3" "Fall Creators Update" == + # 6.3.16299 + global_vars['OS'] = tmp + +def check_tools(): + """Set tool variables based on OS bit-depth and tool availability.""" + if global_vars['OS'].get('Arch', 32) == 64: + global_vars['Tools'] = { + k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()} + else: + global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()} + + # Fix paths + global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v) + for (k, v) in global_vars['Tools'].items()} + +def clean_env_vars(): + """Remove conflicting global_vars and env variables. + + This fixes an issue where both global_vars and + global_vars['Env'] are expanded at the same time.""" + for key in global_vars.keys(): + global_vars['Env'].pop(key, None) + +def find_bin(): + """Find .bin folder in the cwd or it's parents.""" + wd = os.getcwd() + base = None + while base is None: + if os.path.exists('.bin'): + base = os.getcwd() + break + if re.fullmatch(r'\w:\\', os.getcwd()): + break + os.chdir('..') + os.chdir(wd) + if base is None: + raise BinNotFoundError + global_vars['BaseDir'] = base + +def make_tmp_dirs(): + """Make temp directories.""" + os.makedirs(global_vars['BackupDir'], exist_ok=True) + os.makedirs(global_vars['LogDir'], exist_ok=True) + os.makedirs(global_vars['TmpDir'], exist_ok=True) + +def set_common_vars(): + """Set common variables.""" + global_vars['Date'] = time.strftime("%Y-%m-%d") + global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z") + global_vars['Env'] = os.environ.copy() + + global_vars['ArchivePassword'] = ARCHIVE_PASSWORD + global_vars['BinDir'] = r'{BaseDir}\.bin'.format( + **global_vars) + global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format( + **global_vars) + global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format( + prefix=KIT_NAME_SHORT, **global_vars['Env']) + global_vars['BackupDir'] = r'{ClientDir}\Backups\{Date}'.format( + **global_vars) + global_vars['LogDir'] = r'{ClientDir}\Info\{Date}'.format( + **global_vars) + global_vars['ProgBackupDir'] = r'{ClientDir}\Backups'.format( + **global_vars) + global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format( + **global_vars) + global_vars['TmpDir'] = r'{BinDir}\tmp'.format( + **global_vars) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/data.py b/Scripts/functions/data.py new file mode 100644 index 00000000..66797329 --- /dev/null +++ b/Scripts/functions/data.py @@ -0,0 +1,607 @@ +# Wizard Kit PE: Functions - Data + +import ctypes + +from operator import itemgetter + +from functions.common import * + +# Classes +class LocalDisk(): + def __init__(self, disk): + self.disk = disk + self.name = disk.mountpoint.upper() + self.path = self.name + def is_dir(self): + # Should always be true + return True + +# Regex +REGEX_EXCL_ITEMS = re.compile( + r'^(\.(AppleDB|AppleDesktop|AppleDouble' + r'|com\.apple\.timemachine\.supported|dbfseventsd' + r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' + r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' + r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' + r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' + r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' + r'|Thumbs\.db)$', + re.IGNORECASE) +REGEX_EXCL_ROOT_ITEMS = re.compile( + r'^\\?(boot(mgr|nxt)$|Config.msi' + r'|(eula|globdata|install|vc_?red)' + r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' + r'|\$?Win(dows(.old.*|\.~BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' + r'|PerfLogs|Program Files|SYSTEM.SAV' + r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', + re.IGNORECASE) +REGEX_INCL_ROOT_ITEMS = re.compile( + r'^\\?(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' + r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' + r'|{prefix}(-?Info|-?Transfer|)' + r'|(ProgramData|Recovery|Temp.*|Users)$' + r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' + r''.format(prefix=KIT_NAME_SHORT), + re.IGNORECASE) +REGEX_WIM_FILE = re.compile( + r'\.wim$', + re.IGNORECASE) +REGEX_WINDOWS_OLD = re.compile( + r'^\\Win(dows|)\.old', + re.IGNORECASE) + +# STATIC VARIABLES +FAST_COPY_EXCLUDES = [ + r'\*.esd', + r'\*.swm', + r'\*.wim', + r'\*.dd', + r'\*.dd.tgz', + r'\*.dd.txz', + r'\*.map', + r'\*.dmg', + r'\*.image', + r'$RECYCLE.BIN', + r'$Recycle.Bin', + r'.AppleDB', + r'.AppleDesktop', + r'.AppleDouble', + r'.com.apple.timemachine.supported', + r'.dbfseventsd', + r'.DocumentRevisions-V100*', + r'.DS_Store', + r'.fseventsd', + r'.PKInstallSandboxManager', + r'.Spotlight*', + r'.SymAV*', + r'.symSchedScanLockxz', + r'.TemporaryItems', + r'.Trash*', + r'.vol', + r'.VolumeIcon.icns', + r'desktop.ini', + r'Desktop?DB', + r'Desktop?DF', + r'hiberfil.sys', + r'lost+found', + r'Network?Trash?Folder', + r'pagefile.sys', + r'Recycled', + r'RECYCLER', + r'System?Volume?Information', + r'Temporary?Items', + r'Thumbs.db', + ] +FAST_COPY_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] +# Code borrowed from: https://stackoverflow.com/a/29075319 +SEM_NORMAL = ctypes.c_uint() +SEM_FAILCRITICALERRORS = 1 +SEM_NOOPENFILEERRORBOX = 0x8000 +SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS + +def cleanup_transfer(dest_path): + """Fix attributes and move extraneous items outside the Transfer folder.""" + try: + # Remove dest_path if empty + os.rmdir(dest_path) + except OSError: + pass + if not os.path.exists(dest_path): + # Bail if dest_path was empty and removed + raise Exception + + # Fix attributes + cmd = ['attrib', '-a', '-h', '-r', '-s', dest_path] + run_program(cmd, check=False) + + for root, dirs, files in os.walk(dest_path, topdown=False): + for name in dirs: + # Remove empty directories and junction points + try: + os.rmdir(os.path.join(root, name)) + except OSError: + pass + for name in files: + # "Remove" files based on exclusion regex + if REGEX_EXCL_ITEMS.search(name): + # Make dest folder + dest_name = root.replace(dest_path, dest_path+'.Removed') + os.makedirs(dest_name, exist_ok=True) + # Set dest filename + dest_name = os.path.join(dest_name, name) + dest_name = non_clobber_rename(dest_name) + source_name = os.path.join(root, name) + try: + shutil.move(source_name, dest_name) + except Exception: + pass + +def is_valid_wim_file(item): + """Checks if the provided os.DirEntry is a valid WIM file, returns bool.""" + valid = bool(item.is_file() and REGEX_WIM_FILE.search(item.name)) + if valid: + extract_item('wimlib', silent=True) + cmd = [global_vars['Tools']['wimlib-imagex'], 'info', item.path] + try: + run_program(cmd) + except subprocess.CalledProcessError: + valid = False + print_log('WARNING: Image "{}" damaged.'.format(item.name)) + return valid + +def mount_backup_shares(): + """Mount the backup shares unless labeled as already mounted.""" + for server in BACKUP_SERVERS: + # Blindly skip if we mounted earlier + if server['Mounted']: + continue + + mount_network_share(server) + +def mount_network_share(server): + """Mount a network share defined by server.""" + # Test connection + try: + ping(server['IP']) + except subprocess.CalledProcessError: + print_error( + r'Failed to mount \\{Name}\{Share}, {IP} unreachable.'.format( + **server)) + sleep(1) + return False + + # Mount + cmd = r'net use \\{IP}\{Share} /user:{User} {Pass}'.format(**server) + cmd = cmd.split(' ') + try: + run_program(cmd) + except Exception: + print_warning(r'Failed to mount \\{Name}\{Share} ({IP})'.format( + **server)) + sleep(1) + else: + print_info('Mounted {Name}'.format(**server)) + server['Mounted'] = True + +def run_fast_copy(items, dest): + """Copy items to dest using FastCopy.""" + if not items: + raise Exception + + cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS] + if 'LogFile' in global_vars: + cmd.append('/logfile={LogFile}'.format(**global_vars)) + cmd.extend(items) + cmd.append('/to={}\\'.format(dest)) + + run_program(cmd) + +def run_wimextract(source, items, dest): + """Extract items from source WIM to dest folder.""" + if not items: + raise Exception + extract_item('wimlib', silent=True) + + # Write files.txt + with open(r'{TmpDir}\wim_files.txt'.format(**global_vars), 'w') as f: + # Defaults + for item in items: + f.write('{item}\n'.format(item=item)) + sleep(1) # For safety? + + # Extract files + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'extract', + source, '1', + r'@{TmpDir}\wim_files.txt'.format(**global_vars), + '--dest-dir={}\\'.format(dest), + '--no-acls', + '--nullglob'] + run_program(cmd) + +def scan_source(source_obj, dest_path): + """Scan source for files/folders to transfer.""" + selected_items = [] + + if source_obj.is_dir(): + # File-Based + print_standard('Scanning source (folder): {}'.format(source_obj.path)) + selected_items = scan_source_path(source_obj.path, dest_path) + else: + # Image-Based + if REGEX_WIM_FILE.search(source_obj.name): + print_standard('Scanning source (image): {}'.format( + source_obj.path)) + selected_items = scan_source_wim(source_obj.path, dest_path) + else: + print_error('ERROR: Unsupported image: {}'.format( + source_obj.path)) + raise GenericError + + return selected_items + +def scan_source_path(source_path, dest_path, rel_path=None, interactive=True): + """Scan source folder for files/folders to transfer, returns list. + + This will scan the root and (recursively) any Windows.old folders.""" + rel_path = '\\' + rel_path if rel_path else '' + if rel_path: + dest_path = dest_path + rel_path + selected_items = [] + win_olds = [] + + # Root items + root_items = [] + for item in os.scandir(source_path): + if REGEX_INCL_ROOT_ITEMS.search(item.name): + root_items.append(item.path) + elif not REGEX_EXCL_ROOT_ITEMS.search(item.name): + if (not interactive + or ask('Copy: "{}{}" ?'.format(rel_path, item.name))): + root_items.append(item.path) + if REGEX_WINDOWS_OLD.search(item.name): + win_olds.append(item) + if root_items: + selected_items.append({ + 'Message': '{}Root Items...'.format(rel_path), + 'Items': root_items.copy(), + 'Destination': dest_path}) + + # Fonts + if os.path.exists(r'{}\Windows\Fonts'.format(source_path)): + selected_items.append({ + 'Message': '{}Fonts...'.format(rel_path), + 'Items': [r'{}\Windows\Fonts'.format(rel_path)], + 'Destination': r'{}\Windows'.format(dest_path)}) + + # Registry + registry_items = [] + for folder in ['config', 'OEM']: + folder = r'Windows\System32\{}'.format(folder) + folder = os.path.join(source_path, folder) + if os.path.exists(folder): + registry_items.append(folder) + if registry_items: + selected_items.append({ + 'Message': '{}Registry...'.format(rel_path), + 'Items': registry_items.copy(), + 'Destination': r'{}\Windows\System32'.format(dest_path)}) + + # Windows.old(s) + for old in win_olds: + selected_items.append( + scan_source_path( + old.path, dest_path, rel_path=old.name, interactive=False)) + + # Done + return selected_items + +def scan_source_wim(source_wim, dest_path, rel_path=None, interactive=True): + """Scan source WIM file for files/folders to transfer, returns list. + + This will scan the root and (recursively) any Windows.old folders.""" + rel_path = '\\' + rel_path if rel_path else '' + selected_items = [] + win_olds = [] + + # Scan source + extract_item('wimlib', silent=True) + cmd = [ + global_vars['Tools']['wimlib-imagex'], 'dir', + source_wim, '1'] + try: + file_list = run_program(cmd) + except subprocess.CalledProcessError: + print_error('ERROR: Failed to get file list.') + raise + + # Root Items + file_list = [i.strip() + for i in file_list.stdout.decode('utf-8', 'ignore').splitlines() + if i.count('\\') == 1 and i.strip() != '\\'] + root_items = [] + if rel_path: + file_list = [i.replace(rel_path, '') for i in file_list] + for item in file_list: + if REGEX_INCL_ROOT_ITEMS.search(item): + root_items.append(item) + elif not REGEX_EXCL_ROOT_ITEMS.search(item): + if (not interactive + or ask('Extract: "{}{}" ?'.format(rel_path, item))): + root_items.append('{}{}'.format(rel_path, item)) + if REGEX_WINDOWS_OLD.search(item): + win_olds.append(item) + if root_items: + selected_items.append({ + 'Message': '{}Root Items...'.format(rel_path), + 'Items': root_items.copy(), + 'Destination': dest_path}) + + # Fonts + if wim_contains(source_wim, r'{}Windows\Fonts'.format(rel_path)): + selected_items.append({ + 'Message': '{}Fonts...'.format(rel_path), + 'Items': [r'{}\Windows\Fonts'.format(rel_path)], + 'Destination': dest_path}) + + # Registry + registry_items = [] + for folder in ['config', 'OEM']: + folder = r'{}Windows\System32\{}'.format(rel_path, folder) + if wim_contains(source_wim, folder): + registry_items.append(folder) + if registry_items: + selected_items.append({ + 'Message': '{}Registry...'.format(rel_path), + 'Items': registry_items.copy(), + 'Destination': dest_path}) + + # Windows.old(s) + for old in win_olds: + scan_source_wim(source_wim, dest_path, rel_path=old, interactive=False) + + # Done + return selected_items + +def select_destination(folder_path, prompt='Select destination'): + """Select destination drive, returns path as string.""" + disk = select_disk(prompt) + if 'fixed' not in disk['Disk'].opts: + folder_path = folder_path.replace('\\', '-') + path = '{disk}{folder_path}_{Date}'.format( + disk = disk['Disk'].mountpoint, + folder_path = folder_path, + **global_vars) + + # Avoid merging with existing folder + path = non_clobber_rename(path) + os.makedirs(path, exist_ok=True) + + return path + +def select_disk(title='Select disk', auto_select=True): + """Select disk from attached disks. returns dict.""" + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + disks = [] + + # Build list of disks + set_thread_error_mode(silent=True) # Prevents "No disk" popups + for d in psutil.disk_partitions(): + info = { + 'Disk': d, + 'Name': d.mountpoint} + try: + usage = psutil.disk_usage(d.device) + free = '{free} / {total} available'.format( + free = human_readable_size(usage.free, 2), + total = human_readable_size(usage.total, 2)) + except Exception: + # Meh, leaving unsupported destinations out + pass + # free = 'Unknown' + # info['Disabled'] = True + else: + info['Display Name'] = '{} ({})'.format(info['Name'], free) + disks.append(info) + set_thread_error_mode(silent=False) # Return to normal + + # Skip menu? + if len(disks) == 1 and auto_select: + return disks[0] + + # Show menu + selection = menu_select(title, main_entries=disks, action_entries=actions) + if selection == 'Q': + exit_script() + else: + return disks[int(selection)-1] + +def select_source(ticket_number): + """Select backup from those found on the BACKUP_SERVERS for the ticket.""" + selected_source = None + sources = [] + mount_backup_shares() + + # Check for ticket folders on servers + for server in BACKUP_SERVERS: + if server['Mounted']: + print_standard('Scanning {}...'.format(server['Name'])) + for d in os.scandir(r'\\{IP}\{Share}'.format(**server)): + if (d.is_dir() + and d.name.lower().startswith(ticket_number.lower())): + # Add folder to sources + sources.append({ + 'Name': '{:9}| File-Based: [DIR] {}'.format( + server['Name'], d.name), + 'Server': server, + 'Source': d}) + + # Check for images and subfolders + for ticket_path in sources.copy(): + for item in os.scandir(ticket_path['Source'].path): + if item.is_dir(): + # Add folder to sources + sources.append({ + 'Name': r'{:9}| File-Based: [DIR] {}\{}'.format( + ticket_path['Server']['Name'], # Server + ticket_path['Source'].name, # Ticket folder + item.name, # Sub-folder + ), + 'Server': ticket_path['Server'], + 'Source': item}) + + # Check for images in folder + for subitem in os.scandir(item.path): + if REGEX_WIM_FILE.search(item.name): + # Add image to sources + try: + size = human_readable_size(item.stat().st_size) + except Exception: + size = ' ? ?' # unknown + sources.append({ + 'Disabled': bool(not is_valid_wim_file(subitem)), + 'Name': r'{:9}| Image-Based: {:>7} {}\{}\{}'.format( + ticket_path['Server']['Name'], # Server + size, # Size (duh) + ticket_path['Source'].name, # Ticket folder + item.name, # Sub-folder + subitem.name, # Image file + ), + 'Server': ticket_path['Server'], + 'Source': subitem}) + elif REGEX_WIM_FILE.search(item.name): + # Add image to sources + try: + size = human_readable_size(item.stat().st_size) + except Exception: + size = ' ? ?' # unknown + sources.append({ + 'Disabled': bool(not is_valid_wim_file(item)), + 'Name': r'{:9}| Image-Based: {:>7} {}\{}'.format( + ticket_path['Server']['Name'], # Server + size, # Size (duh) + ticket_path['Source'].name, # Ticket folder + item.name, # Image file + ), + 'Server': ticket_path['Server'], + 'Source': item}) + # Check for local sources + print_standard('Scanning for local sources...') + set_thread_error_mode(silent=True) # Prevents "No disk" popups + sys_drive = global_vars['Env']['SYSTEMDRIVE'] + for d in psutil.disk_partitions(): + if re.search(r'^{}'.format(sys_drive), d.mountpoint, re.IGNORECASE): + # Skip current OS drive + continue + if 'fixed' in d.opts: + # Skip DVD, etc + sources.append({ + 'Name': '{:9}| File-Based: [DISK] {}'.format( + ' Local', d.mountpoint), + 'Source': LocalDisk(d)}) + set_thread_error_mode(silent=False) # Return to normal + + # Build Menu + sources.sort(key=itemgetter('Name')) + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + + # Select backup from sources + if len(sources) > 0: + selection = menu_select( + 'Which backup are we using?', + main_entries=sources, + action_entries=actions, + disabled_label='DAMAGED') + if selection == 'Q': + umount_backup_shares() + exit_script() + else: + selected_source = sources[int(selection)-1]['Source'] + else: + print_error('ERROR: No backups found for ticket: {}.'.format( + ticket_number)) + umount_backup_shares() + pause("Press Enter to exit...") + exit_script() + + # Done + return selected_source + +def set_thread_error_mode(silent=True): + """Disable or Enable Windows error message dialogs. + + Disable when scanning for disks to avoid popups for empty cardreaders, etc + """ + # Code borrowed from: https://stackoverflow.com/a/29075319 + kernel32 = ctypes.WinDLL('kernel32') + + if silent: + kernel32.SetThreadErrorMode(SEM_FAIL, ctypes.byref(SEM_NORMAL)) + else: + kernel32.SetThreadErrorMode(SEM_NORMAL, ctypes.byref(SEM_NORMAL)) + +def transfer_source(source_obj, dest_path, selected_items): + """Transfer, or extract, files/folders from source to destination.""" + if source_obj.is_dir(): + # Run FastCopy for each selection "group" + for group in selected_items: + try_and_print(message=group['Message'], + function=run_fast_copy, cs='Done', + items=group['Items'], + dest=group['Destination']) + else: + if REGEX_WIM_FILE.search(source_obj.name): + # Extract files from WIM + for group in selected_items: + try_and_print(message=group['Message'], + function=run_wimextract, cs='Done', + source=source_obj.path, + items=group['Items'], + dest=group['Destination']) + else: + print_error('ERROR: Unsupported image: {}'.format(source_obj.path)) + raise GenericError + +def umount_backup_shares(): + """Unnount the backup shares regardless of current status.""" + for server in BACKUP_SERVERS: + umount_network_share(server) + +def umount_network_share(server): + """Unnount a network share defined by server.""" + cmd = r'net use \\{IP}\{Share} /delete'.format(**server) + cmd = cmd.split(' ') + try: + run_program(cmd) + except Exception: + print_error(r'Failed to umount \\{Name}\{Share}.'.format(**server)) + sleep(1) + else: + print_info('Umounted {Name}'.format(**server)) + server['Mounted'] = False + +def wim_contains(source_path, file_path): + """Check if the WIM contains a file or folder.""" + _cmd = [ + global_vars['Tools']['wimlib-imagex'], 'dir', + source_path, '1', + '--path={}'.format(file_path), + '--one-file-only'] + try: + run_program(_cmd) + except subprocess.CalledProcessError: + return False + else: + return True + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/partition_uids.py b/Scripts/functions/partition_uids.py similarity index 98% rename from Scripts/partition_uids.py rename to Scripts/functions/partition_uids.py index 1484e2af..e31117db 100644 --- a/Scripts/partition_uids.py +++ b/Scripts/functions/partition_uids.py @@ -1,4 +1,4 @@ -# WK WinPE - PARTITION UIDs +# Wizard Kit PE: Functions - PARTITION UIDs # sources: https://en.wikipedia.org/wiki/GUID_Partition_Table # https://en.wikipedia.org/wiki/Partition_type diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py new file mode 100644 index 00000000..e70e88cf --- /dev/null +++ b/Scripts/functions/windows_setup.py @@ -0,0 +1,273 @@ +# Wizard Kit PE: Functions - Windows Setup + +from functions.common import * + +# STATIC VARIABLES +DISKPART_SCRIPT = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) +WINDOWS_VERSIONS = [ + {'Name': 'Windows 7 Home Basic', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEBASIC', + 'Family': '7'}, + {'Name': 'Windows 7 Home Premium', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEPREMIUM', + 'Family': '7'}, + {'Name': 'Windows 7 Professional', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 PROFESSIONAL', + 'Family': '7'}, + {'Name': 'Windows 7 Ultimate', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 ULTIMATE', + 'Family': '7'}, + + {'Name': 'Windows 8.1', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1', + 'Family': '8', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1 Pro', + 'Family': '8'}, + + {'Name': 'Windows 10 Home', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Home', + 'Family': '10', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Pro', + 'Family': '10'}, + ] + +def is_index_in_image(bin=None, filename=None, imagename=None): + # Bail early + if bin is None: + raise Exception('bin not specified.') + if filename is None: + raise Exception('Filename not specified.') + if imagename is None: + raise Exception('Image Name not specified.') + + cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Invalid image: {filename}'.format(filename=filename)) + return False + + return True + +def find_windows_image(bin, windows_version=None): + """Search for a Windows source image file on local drives and network drives (in that order)""" + image = {} + + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + imagefile = windows_version['Image File'] + + # Search local source + process_return = run_program('mountvol') + for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): + for ext in ['esd', 'wim', 'swm']: + filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_index_in_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = tmp[0] + break + + # Check for network source (if necessary) + if not any(image): + if not WINDOWS_SERVER['Mounted']: + mount_windows_share() + for ext in ['esd', 'wim', 'swm']: + filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_index_in_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = None + break + + # Display image to be used (if any) and return + if any(image): + print_info('Using image: {File}.{Ext}'.format(**image)) + return image + else: + print_error('Failed to find Windows source image for {winver}'.format(winver=windows_version['Name'])) + abort_to_main_menu('Aborting Windows setup') + +def format_gpt(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + # print_info('Drive will use a GPT (UEFI) layout.') + with open(DISKPART_SCRIPT, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + script.write('convert gpt\n') + + # System partition + script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives + script.write('format quick fs=fat32 label="System"\n') + script.write('assign letter="S"\n') + + # Microsoft Reserved (MSR) partition + script.write('create partition msr size=128\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery Tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') + + # Run script + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + time.sleep(2) + +def format_mbr(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + # print_info('Drive will use a MBR (legacy) layout.') + with open(DISKPART_SCRIPT, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + + # System partition + script.write('create partition primary size=100\n') + script.write('format fs=ntfs quick label="System Reserved"\n') + script.write('active\n') + script.write('assign letter="S"\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format fs=ntfs quick label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery"\n') + script.write('assign letter="T"\n') + script.write('set id=27\n') + + # Run script + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + time.sleep(2) + +def get_boot_mode(): + boot_mode = 'Legacy' + try: + reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + boot_mode = 'UEFI' + except: + boot_mode = 'Unknown' + + return boot_mode + +def mount_windows_share(): + """Mount the Windows images share for use in Windows setup""" + + # Blindly skip if we mounted earlier + if WINDOWS_SERVER['Mounted']: + return None + else: + try: + # Test connection + run_program('ping -w 800 -n 2 {IP}'.format(**WINDOWS_SERVER)) + # Mount + run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**WINDOWS_SERVER)) + print_info('Mounted {Name}'.format(**WINDOWS_SERVER)) + WINDOWS_SERVER['Mounted'] = True + except subprocess.CalledProcessError: + print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**WINDOWS_SERVER)) + time.sleep(1) + except: + print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) + time.sleep(1) + +def select_windows_version(): + actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + + # Menu loop + selection = menu_select('Which version of Windows are we installing?', WINDOWS_VERSIONS, actions) + + if selection.isnumeric(): + return WINDOWS_VERSIONS[int(selection)-1] + elif selection == 'M': + abort_to_main_menu() + +def setup_windows(bin=None, windows_image=None, windows_version=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if windows_image is None: + raise Exception('Windows image not specified.') + if windows_version is None: + raise Exception('Windows version not specified.') + + # Apply image + cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) + run_program(cmd) + +def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T'): + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + + _win = '{win}:\\Windows'.format(win=windows_letter) + _winre = '{win}\\System32\\Recovery\\WinRE.wim'.format(win=_win) + _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) + + if re.search(r'^(8|10)', windows_version['Family']): + # Copy WinRE.wim + os.makedirs(_dest, exist_ok=True) + shutil.copy(_winre, '{dest}\\WinRE.wim'.format(dest=_dest)) + + # Set location + run_program('{win}\\System32\\reagentc /setreimage /path {dest} /target {win}'.format(dest=_dest, win=_win)) + else: + # Only supported on Windows 8 and above + raise SetupError + +def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): + run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/menu.py b/Scripts/functions/winpe_menus.py similarity index 66% rename from Scripts/menu.py rename to Scripts/functions/winpe_menus.py index 7a72f729..21d2e11b 100644 --- a/Scripts/menu.py +++ b/Scripts/functions/winpe_menus.py @@ -1,38 +1,66 @@ -# WK WinPE Menu +# Wizard Kit PE: Menus -# Init -import os -import re -import subprocess -import sys -import time -import traceback -os.chdir(os.path.dirname(os.path.realpath(__file__))) -bin = os.path.abspath('..\\') -sys.path.append(os.getcwd()) -from functions import * +from functions.data import * -## Colors -COLORS = { - 'CLEAR': '\033[0m', - 'RED': '\033[31m', - 'GREEN': '\033[32m', - 'YELLOW': '\033[33m', - 'BLUE': '\033[34m'} +# STATIC VARIABLES +FAST_COPY_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] +PE_TOOLS = { + 'BlueScreenView': { + 'Path': r'BlueScreenView\BlueScreenView.exe', + }, + 'FastCopy': { + 'Path': r'FastCopy\FastCopy.exe', + 'Args': FAST_COPY_ARGS, + }, + 'HWiNFO': { + 'Path': r'HWiNFO\HWiNFO.exe', + }, + 'NT Password Editor': { + 'Path': r'NT Password Editor\ntpwedit.exe', + }, + 'Notepad++': { + 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', + }, + 'PhotoRec': { + 'Path': r'TestDisk\photorec_win.exe', + 'Args': ['-new_console:n'], + }, + 'Prime95': { + 'Path': r'Prime95\prime95.exe', + }, + 'ProduKey': { + 'Path': r'ProduKey\ProduKey.exe', + }, + 'Q-Dir': { + 'Path': r'Q-Dir\Q-Dir.exe', + }, + 'TestDisk': { + 'Path': r'TestDisk\testdisk_win.exe', + 'Args': ['-new_console:n'], + }, + } -def menu_backup_imaging(): +def menu_backup(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" errors = False # Set ticket ID os.system('cls') - ticket_id = get_ticket_id() + ticket_id = get_ticket_number() # Mount backup shares mount_backup_shares() # Select destination - dest = select_destination() + dest = select_backup_destination() if dest is None: abort_to_main_menu('Aborting Backup Creation') @@ -90,13 +118,48 @@ def menu_backup_imaging(): time.sleep(5) pause('\nPress Enter to return to main menu... ') -def menu_windows_setup(): +def menu_root(): + title = '{}: Main Menu'.format(KIT_NAME_FULL) + menus = [ + {'Name': 'Create Backups', 'Menu': menu_backup}, + {'Name': 'Setup Windows', 'Menu': menu_setup}, + {'Name': 'Misc Tools', 'Menu': menu_tools}, + ] + actions = [ + {'Name': 'Command Prompt', 'Letter': 'C'}, + {'Name': 'Reboot', 'Letter': 'R'}, + {'Name': 'Shutdown', 'Letter': 'S'}, + ] + + # Main loop + while True: + selection = menu_select( + title=title, + main_entries=menus, + action_entries=actions, + secret_exit=True) + + if (selection.isnumeric()): + try: + menus[int(selection)-1]['Menu']() + except AbortError: + pass + elif (selection == 'C'): + run_program(['cmd', '-new_console:n'], check=False) + elif (selection == 'R'): + run_program(['wpeutil', 'reboot']) + elif (selection == 'S'): + run_program(['wpeutil', 'shutdown']) + else: + exit_script() + +def menu_setup(): """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" errors = False # Set ticket ID os.system('cls') - ticket_id = get_ticket_id() + ticket_id = get_ticket_number() # Select the version of Windows to apply windows_version = select_windows_version() @@ -197,80 +260,55 @@ def menu_windows_setup(): pause('\nPress Enter to return to main menu... ') def menu_tools(): - tools = [ - {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, - {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, - {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, - {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, - {'Name': 'Notepad++', 'Folder': 'NotepadPlusPlus', 'File': 'notepadplusplus.exe'}, - {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, - {'Name': 'Prime95', 'Folder': 'Prime95', 'File': 'prime95.exe'}, - {'Name': 'ProduKey', 'Folder': 'ProduKey', 'File': 'ProduKey.exe', 'Args': ['/external', '/ExtractEdition:1']}, - {'Name': 'Q-Dir', 'Folder': 'Q-Dir', 'File': 'Q-Dir.exe'}, - {'Name': 'TestDisk', 'Folder': 'TestDisk', 'File': 'testdisk_win.exe', 'Args': ['-new_console:n']}, - ] - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] + title = '{}: Tools Menu'.format(KIT_NAME_FULL) + tools = [k for k in sorted(PE_TOOLS.keys())] + actions = [{'Name': 'Main Menu', 'Letter': 'M'},] # Menu loop while True: - selection = menu_select('Tools Menu', tools, actions) - + selection = menu_select(title, tools, actions) if (selection.isnumeric()): tool = tools[int(selection)-1] - cmd = ['{bin}\\{folder}\\{file}'.format(bin=bin, folder=tool['Folder'], file=tool['File'])] - if tool['Name'] == 'Blue Screen View': + cmd = [PE_TOOLS[tool]['Path']] + PE_TOOLS[tool].get('Args', []) + if tool == 'Blue Screen View': # Select path to scan minidump_path = select_minidump_path() - if minidump_path is not None: - tool['Args'] = ['/MiniDumpFolder', minidump_path] - if 'Args' in tool: - cmd += tool['Args'] + if minidump_path: + cmd.extend(['/MiniDumpFolder', minidump_path]) try: - subprocess.Popen(cmd) - except: + popen_program(cmd) + except Exception: print_error('Failed to run {prog}'.format(prog=tool['Name'])) - time.sleep(2) + time.sleep(2) + pause() elif (selection == 'M'): break -def menu_main(): - menus = [ - {'Name': 'Create Backups', 'Menu': menu_backup_imaging}, - {'Name': 'Setup Windows', 'Menu': menu_windows_setup}, - {'Name': 'Misc Tools', 'Menu': menu_tools}, - ] - actions = [ - {'Name': 'Command Prompt', 'Letter': 'C'}, - {'Name': 'Reboot', 'Letter': 'R'}, - {'Name': 'Shutdown', 'Letter': 'S'}, - ] +def select_minidump_path(): + dumps = [] - # Main loop - while True: - selection = menu_select('Main Menu', menus, actions, secret_exit=True) + # Assign volume letters first + assign_volume_letters() - if (selection.isnumeric()): - try: - menus[int(selection)-1]['Menu']() - except AbortError: - pass - except: - print_error('Major exception in: {menu}'.format(menu=menus[int(selection)-1]['Name'])) - print_warning(' Please let The Wizard know and he\'ll look into it (Please include the details below).') - print(traceback.print_exc()) - time.sleep(5) - print_info(' You can retry but if this crashes again an alternative approach may be required.') - pause('\nPress enter to return to the main menu') - elif (selection == 'C'): - run_program(['cmd', '-new_console:n'], check=False) - elif (selection == 'R'): - run_program(['wpeutil', 'reboot']) - elif (selection == 'S'): - run_program(['wpeutil', 'shutdown']) - else: - sys.exit(0) + # Search for minidumps + tmp = run_program('mountvol') + tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] + # Remove RAMDisk letter + if 'X' in tmp: + tmp.remove('X') + for drive in tmp: + if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): + dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) + + # Check results before showing menu + if len(dumps) == 0: + print_error(' No BSoD / MiniDump paths found') + time.sleep(2) + return None + + # Menu + selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) + return dumps[int(selection) - 1]['Name'] if __name__ == '__main__': - menu_main() \ No newline at end of file + print("This file is not meant to be called directly.") diff --git a/Scripts/settings/main.py b/Scripts/settings/main.py new file mode 100644 index 00000000..4b1d9818 --- /dev/null +++ b/Scripts/settings/main.py @@ -0,0 +1,68 @@ +# Wizard Kit PE: Settings - Main / Branding + +# Features +ENABLED_UPLOAD_DATA = False + +# STATIC VARIABLES (also used by .cmd files) +## Not using spaces aroung '=' for easier .cmd substrings +ARCHIVE_PASSWORD='Abracadabra' +KIT_NAME_FULL='Wizard Kit PE' +KIT_NAME_SHORT='WKPE' +OFFICE_SERVER_IP='10.0.0.10' +QUICKBOOKS_SERVER_IP='10.0.0.10' +SUPPORT_MESSAGE='Please let 2Shirt know by opening an issue on GitHub' +TIME_ZONE='Pacific Standard Time' # Always use "Standard Time" (DST is applied correctly) + +# SERVER VARIABLES +## NOTE: Windows can only use one user per server. This means that if +## one server serves multiple shares then you have to use the same +## user/password for all of those shares. +BACKUP_SERVERS = [ + { 'IP': '10.0.0.10', + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Backups', + 'User': 'restore', + 'Pass': 'Abracadabra', + }, + { 'IP': '10.0.0.11', + 'Name': 'ServerTwo', + 'Mounted': False, + 'Share': 'Backups', + 'User': 'restore', + 'Pass': 'Abracadabra', + }, +] +CLIENT_INFO_SERVER = { + 'IP': '10.0.0.10', + 'RegEntry': r'0x10001,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'Share': '/srv/ClientInfo', + 'User': 'upload', +} +OFFICE_SERVER = { + 'IP': OFFICE_SERVER_IP, + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Office', + 'User': 'restore', + 'Pass': 'Abracadabra', +} +QUICKBOOKS_SERVER = { + 'IP': QUICKBOOKS_SERVER_IP, + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'QuickBooks', + 'User': 'restore', + 'Pass': 'Abracadabra', +} +WINDOWS_SERVER = { + 'IP': '10.0.0.10', + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Windows', + 'User': 'restore', + 'Pass': 'Abracadabra', +} + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/settings/tools.py b/Scripts/settings/tools.py new file mode 100644 index 00000000..ab8be9e1 --- /dev/null +++ b/Scripts/settings/tools.py @@ -0,0 +1,55 @@ +# Wizard Kit PE: Settings - Tools + +TOOLS = { + # NOTE: BinDir will be prepended to these paths at runtime + 'AIDA64': { + '32': r'AIDA64\aida64.exe'}, + 'AutoRuns': { + '32': r'Autoruns\autoruns.exe', + '64': r'Autoruns\autoruns64.exe'}, + 'BleachBit': { + '32': r'BleachBit\bleachbit_console.exe'}, + 'Caffeine': { + '32': r'Caffeine\caffeine.exe'}, + 'Du': { + '32': r'Du\du.exe', + '64': r'Du\du64.exe'}, + 'ERUNT': { + '32': r'ERUNT\ERUNT.EXE'}, + 'Everything': { + '32': r'Everything\Everything.exe', + '64': r'Everything\Everything64.exe'}, + 'FastCopy': { + '32': r'FastCopy\FastCopy.exe', + '64': r'FastCopy\FastCopy64.exe'}, + 'HitmanPro': { + '32': r'HitmanPro\HitmanPro.exe', + '64': r'HitmanPro\HitmanPro64.exe'}, + 'HWiNFO': { + '32': r'HWiNFO\HWiNFO.exe', + '64': r'HWiNFO\HWiNFO64.exe'}, + 'KVRT': { + '32': r'KVRT\KVRT.exe'}, + 'NotepadPlusPlus': { + '32': r'NotepadPlusPlus\notepadplusplus.exe'}, + 'ProduKey': { + '32': r'ProduKey\ProduKey.exe', + '64': r'ProduKey\ProduKey64.exe'}, + 'PuTTY-PSFTP': { + '32': r'PuTTY\PSFTP.EXE'}, + 'RKill': { + '32': r'RKill\RKill.exe'}, + 'SevenZip': { + '32': r'7-Zip\7za.exe', + '64': r'7-Zip\7za64.exe'}, + 'TDSSKiller': { + '32': r'TDSSKiller\TDSSKiller.exe'}, + 'wimlib-imagex': { + '32': r'wimlib\x32\wimlib-imagex.exe', + '64': r'wimlib\x64\wimlib-imagex.exe'}, + 'XMPlay': { + '32': r'XMPlay\xmplay.exe'}, + } + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py new file mode 100644 index 00000000..370186f0 --- /dev/null +++ b/Scripts/winpe_root_menu.py @@ -0,0 +1,21 @@ +# Wizard Kit PE: Root Menu + +import os +import sys + +# Init +os.chdir(os.path.dirname(os.path.realpath(__file__))) +sys.path.append(os.getcwd()) +from functions.common import * +from functions.winpe_menus import * +init_global_vars() +os.system('title {}: Root Menu'.format(KIT_NAME_FULL)) +global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) + +if __name__ == '__main__': + try: + menu_root() + except SystemExit: + pass + except: + major_exception() From dd20cdd36e04433fbdf2275423cd83c373e65921 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 13:40:22 -0800 Subject: [PATCH 36/85] Renamed X:\WK to X:\.bin * Allows functions\common.py to be used as-is --- .bin/Scripts/build_pe.ps1 | 14 +++++++------- System32/Winpeshl.ini | 4 ++-- System32/menu.cmd | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 631d6d9e..afcc6fe7 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -501,16 +501,16 @@ if ($MyInvocation.InvocationName -ne ".") { # Add WK tools Write-Host "Copying tools..." - Copy-Item -Path "$Root\WK\$Arch" -Destination "$Mount\WK" -Recurse -Force - Copy-Item -Path "$Root\WK\_include\*" -Destination "$Mount\WK" -Recurse -Force + Copy-Item -Path "$Root\WK\$Arch" -Destination "$Mount\.bin" -Recurse -Force + Copy-Item -Path "$Root\WK\_include\*" -Destination "$Mount\.bin" -Recurse -Force if ($Arch -eq "amd64") { - $DestIni = "$Mount\WK\HWiNFO\HWiNFO64.INI" + $DestIni = "$Mount\.bin\HWiNFO\HWiNFO64.INI" } else { - $DestIni = "$Mount\WK\HWiNFO\HWiNFO32.INI" + $DestIni = "$Mount\.bin\HWiNFO\HWiNFO32.INI" } - Move-Item -Path "$Mount\WK\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force - Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\WK\ConEmu\ConEmu.jpg" -Recurse -Force - Copy-Item -Path "$Root\Scripts" -Destination "$Mount\WK\Scripts" -Recurse -Force + Move-Item -Path "$Mount\.bin\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force + Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\.bin\ConEmu\ConEmu.jpg" -Recurse -Force + Copy-Item -Path "$Root\Scripts" -Destination "$Mount\.bin\Scripts" -Recurse -Force # Add System32 items $HostSystem32 = "{0}\System32" -f $Env:SystemRoot diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index 716d7d6e..d272162f 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,5 +2,5 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -cd /d "%SystemDrive%\WK" -"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\WK" & python "%SystemDrive%\WK\Scripts\menu.py" +cd /d "%SystemDrive%\.bin" +"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\menu.py" diff --git a/System32/menu.cmd b/System32/menu.cmd index 771dc372..b8e5509a 100644 --- a/System32/menu.cmd +++ b/System32/menu.cmd @@ -1,2 +1,2 @@ @echo off -python "%SystemDrive%\WK\Scripts\menu.py" \ No newline at end of file +python "%SystemDrive%\.bin\Scripts\menu.py" \ No newline at end of file From e136283a71e43820f572b2eaa366cb6160a5c3b8 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 14:40:44 -0800 Subject: [PATCH 37/85] Added clear_screen() --- Scripts/functions/common.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index a0453a95..d20a9ea6 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -81,6 +81,10 @@ def ask(prompt='Kotaero!'): print_log(message=message) return answer +def clear_screen(): + """Simple wrapper for cls.""" + os.system('cls') + def convert_to_bytes(size): """Convert human-readable size str to bytes and return an int.""" size = str(size) From a249cdeb7e815a7e0ffb469d7f316b60c21f0d8a Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 14:41:29 -0800 Subject: [PATCH 38/85] Adjusted Notepad++ settings --- WK/_include/NotepadPlusPlus/config.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WK/_include/NotepadPlusPlus/config.xml b/WK/_include/NotepadPlusPlus/config.xml index 3a88a83e..17e6cda1 100644 --- a/WK/_include/NotepadPlusPlus/config.xml +++ b/WK/_include/NotepadPlusPlus/config.xml @@ -5,10 +5,10 @@ standard hide - + vertical hide - + no yes no From b5b03e4dfef7e5d1e69d3e7a4f4b5a15c540ea34 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 15:19:43 -0800 Subject: [PATCH 39/85] Fixed notepad replacement --- .bin/Scripts/build_pe.ps1 | 13 ++++++------ WK/_include/NotepadPlusPlus/npp.cmd | 3 +++ WK/_include/NotepadPlusPlus/npp.vbs | 33 ----------------------------- 3 files changed, 9 insertions(+), 40 deletions(-) create mode 100644 WK/_include/NotepadPlusPlus/npp.cmd delete mode 100644 WK/_include/NotepadPlusPlus/npp.vbs diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index afcc6fe7..4276b152 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -499,7 +499,7 @@ if ($MyInvocation.InvocationName -ne ".") { ) Start-Process -FilePath $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait - # Add WK tools + # Add tools Write-Host "Copying tools..." Copy-Item -Path "$Root\WK\$Arch" -Destination "$Mount\.bin" -Recurse -Force Copy-Item -Path "$Root\WK\_include\*" -Destination "$Mount\.bin" -Recurse -Force @@ -538,17 +538,16 @@ if ($MyInvocation.InvocationName -ne ".") { $RegKey = $Hive.OpenSubKey($RegPath) $CurValue = $RegKey.GetValue( "Path", $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) - $NewValue = "$CurValue;%SystemDrive%\WK\7-Zip;%SystemDrive%\WK\python;%SystemDrive%\WK\wimlib" + $NewValue = "$CurValue;%SystemDrive%\.bin\7-Zip;%SystemDrive%\.bin\python;%SystemDrive%\.bin\wimlib" Set-ItemProperty -Path "HKLM:\$RegPath" -Name "Path" -Value $NewValue -Force | Out-Null $Hive.close() $RegKey.close() # Replace Notepad - ## Currently broken ## - # $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" - # $NewValue = 'wscript "X:\WK\NotepadPlusPlus\npp.vbs"' - # New-Item -Path $RegPath -Force | Out-Null - # New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null + $RegPath = "HKLM:\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" + $NewValue = 'cmd /c "%SystemDrive%\.bin\NotepadPlusPlus\npp.cmd"' + New-Item -Path $RegPath -Force | Out-Null + New-ItemProperty -Path $RegPath -Name "Debugger" -Value $NewValue -Force | Out-Null # Run garbage collection to release potential stale handles ## Credit: https://jrich523.wordpress.com/2012/03/06/powershell-loading-and-unloading-registry-hives/ diff --git a/WK/_include/NotepadPlusPlus/npp.cmd b/WK/_include/NotepadPlusPlus/npp.cmd new file mode 100644 index 00000000..d387df55 --- /dev/null +++ b/WK/_include/NotepadPlusPlus/npp.cmd @@ -0,0 +1,3 @@ +@echo off + +start "" %SystemDrive%\.bin\NotepadPlusPlus\notepadplusplus.exe %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/WK/_include/NotepadPlusPlus/npp.vbs b/WK/_include/NotepadPlusPlus/npp.vbs deleted file mode 100644 index 3fb12a41..00000000 --- a/WK/_include/NotepadPlusPlus/npp.vbs +++ /dev/null @@ -1,33 +0,0 @@ -'// DISCLAIMER -'// THIS COMES WITH NO WARRANTY, IMPLIED OR OTHERWISE. USE AT YOUR OWN RISK -'// IF YOU ARE NOT COMFORTABLE EDITING THE REGISTRY THEN DO NOT USE THIS SCRIPT -'// -'// NOTES: -'// This affects all users. -'// This will prevent ANY executable named notepad.exe from running located anywhere on this computer!! -'// -'// Save this text to your notepad++ folder as a text file named npp.vbs (some AV don't like vbs, get a different AV :-P ) -'// -'// USAGE -'// 1) -'// Navigate to registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ -'// -' // 2) -'// Add new subkey called notepad.exe -'// This step is what tells windows to use the notepad++ exe, to undo simply delete this key -'// -'// 3) -'// Create new Sting Value called Debugger -'// -'// 4) -'// Modify value and enter wscript.exe "path to npp.vbs" e.g. wscript.exe "C:\Program Files\Notepad++\npp.vbs" - -Option Explicit -Dim sCmd, x -sCmd = """" & LeftB(WScript.ScriptFullName, LenB(WScript.ScriptFullName) - LenB(WScript.ScriptName)) & "notepad++.exe" & """ """ -For x = 1 To WScript.Arguments.Count - 1 - sCmd = sCmd & WScript.Arguments(x) & " " -Next -sCmd = sCmd & """" -CreateObject("WScript.Shell").Run sCmd, 1, True -WScript.Quit \ No newline at end of file From d54c9da56f48d3b956e1a1659cb9a4951db32dd6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 15:58:47 -0800 Subject: [PATCH 40/85] Set Notepad++ default font --- WK/_include/NotepadPlusPlus/config.xml | 2 +- WK/_include/NotepadPlusPlus/stylers.model.xml | 1371 +++++++++++++++++ 2 files changed, 1372 insertions(+), 1 deletion(-) create mode 100644 WK/_include/NotepadPlusPlus/stylers.model.xml diff --git a/WK/_include/NotepadPlusPlus/config.xml b/WK/_include/NotepadPlusPlus/config.xml index 17e6cda1..999daa1b 100644 --- a/WK/_include/NotepadPlusPlus/config.xml +++ b/WK/_include/NotepadPlusPlus/config.xml @@ -24,7 +24,7 @@ yes yes 2 - + diff --git a/WK/_include/NotepadPlusPlus/stylers.model.xml b/WK/_include/NotepadPlusPlus/stylers.model.xml new file mode 100644 index 00000000..17235271 --- /dev/null +++ b/WK/_include/NotepadPlusPlus/stylers.model.xml @@ -0,0 +1,1371 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 9a3234c82221524b0dd68772e6f8a91a60e6e4fd Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 16:07:51 -0800 Subject: [PATCH 41/85] Simplified Windows share sections --- Scripts/functions/common.py | 2 +- Scripts/functions/windows_setup.py | 34 ++++++++---------------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index d20a9ea6..fcb2dd51 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -174,7 +174,7 @@ def human_readable_size(size, decimals=0): size = convert_to_bytes(size) # Verify we have a valid size - if size <= 0: + if size < 0: return '{size:>{width}} b'.format(size='???', width=width) # Convert to sensible units diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index e70e88cf..8de76f76 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -61,13 +61,9 @@ def is_index_in_image(bin=None, filename=None, imagename=None): return True -def find_windows_image(bin, windows_version=None): +def find_windows_image(bin, windows_version): """Search for a Windows source image file on local drives and network drives (in that order)""" image = {} - - # Bail early - if windows_version is None: - raise Exception('Windows version not specified.') imagefile = windows_version['Image File'] # Search local source @@ -85,9 +81,10 @@ def find_windows_image(bin, windows_version=None): break # Check for network source (if necessary) - if not any(image): + if not image: + mount_windows_share() if not WINDOWS_SERVER['Mounted']: - mount_windows_share() + return None for ext in ['esd', 'wim', 'swm']: filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) @@ -202,25 +199,12 @@ def get_boot_mode(): return boot_mode def mount_windows_share(): - """Mount the Windows images share for use in Windows setup""" - - # Blindly skip if we mounted earlier + """Mount the Windows images share unless labeled as already mounted.""" if WINDOWS_SERVER['Mounted']: - return None - else: - try: - # Test connection - run_program('ping -w 800 -n 2 {IP}'.format(**WINDOWS_SERVER)) - # Mount - run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**WINDOWS_SERVER)) - print_info('Mounted {Name}'.format(**WINDOWS_SERVER)) - WINDOWS_SERVER['Mounted'] = True - except subprocess.CalledProcessError: - print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**WINDOWS_SERVER)) - time.sleep(1) - except: - print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) - time.sleep(1) + # Blindly skip if we mounted earlier + continue + + mount_network_share(WINDOWS_SERVER) def select_windows_version(): actions = [{'Name': 'Main Menu', 'Letter': 'M'},] From 80cb9b8ceab845003b3145fae347339383b7d8b6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 16:40:40 -0800 Subject: [PATCH 42/85] Function separation done. * Split backup.py into disk & backup * disk.py is for lower level disk management * Renamed functions\data.py's select_disk() to select_volume() * Avoid name collision with functions\disk.py's select_disk() * --- Scripts/functions/backup.py | 327 --------------------------- Scripts/functions/data.py | 4 +- Scripts/functions/disk.py | 345 +++++++++++++++++++++++++++++ Scripts/functions/windows_setup.py | 56 ++--- Scripts/functions/winpe_menus.py | 4 +- Scripts/winpe_root_menu.py | 1 - 6 files changed, 372 insertions(+), 365 deletions(-) create mode 100644 Scripts/functions/disk.py diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index 94f3b103..e33004ba 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -1,18 +1,6 @@ # Wizard Kit PE: Functions - Backup from functions.common import * -import partition_uids - -def assign_volume_letters(): - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('assign\n') - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - except subprocess.CalledProcessError: - pass def backup_partition(bin=None, disk=None, par=None): # Bail early @@ -40,232 +28,6 @@ def backup_partition(bin=None, disk=None, par=None): par['Error'] = err.stderr.decode().splitlines() raise BackupError -def get_attached_disk_info(): - """Get details about the attached disks""" - disks = [] - print_info('Getting drive info...') - - # Assign all the letters - assign_volume_letters() - - # Get disks - disks = get_disks() - - # Get disk details - for disk in disks: - # Get partition style - disk['Table'] = get_table_type(disk) - - # Get disk name/model and physical details - disk.update(get_disk_details(disk)) - - # Get partition info for disk - disk['Partitions'] = get_partitions(disk) - - for par in disk['Partitions']: - # Get partition details - par.update(get_partition_details(disk, par)) - - # Done - return disks - -def get_disk_details(disk=None): - details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('detail disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Set disk name - details['Name'] = tmp[4] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - return details - -def get_disks(): - disks = [] - - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append disk numbers - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - disks.append({'Number': _num, 'Size': _size}) - - return disks - -def get_partition_details(disk=None, par=None): - details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - if par is None: - raise Exception('Partition not specified.') - - # Diskpart details - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('select partition {Number}\n'.format(**par)) - script.write('detail partition\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Get volume letter or RAW status - tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) - if tmp: - if tmp.group(1).upper() == 'RAW': - details['FileSystem'] = RAW - else: - details['Letter'] = tmp.group(1) - - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Get MBR type / GPT GUID for extra details on "Unknown" partitions - guid = partition_uids.lookup_guid(details['Type']) - if guid is not None: - details.update({ - 'Description': guid.get('Description', ''), - 'OS': guid.get('OS', '')}) - - if 'Letter' in details: - # Disk usage - tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) - details['Used Space'] = human_readable_size(tmp.used) - - # fsutil details - try: - process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Add "Feature" lines - details['File System Features'] = [s.strip() for s in tmp if ':' not in s] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.split(':') for s in tmp if ':' in s] - - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Set Volume Name - details['Name'] = details.get('Volume Name', '') - - # Set FileSystem Type - if details.get('FileSystem', '') != 'RAW': - details['FileSystem'] = details.get('File System Name', 'Unknown') - - return details - -def get_partitions(disk=None): - partitions = [] - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('list partition\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append partition numbers - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - partitions.append({'Number': _num, 'Size': _size}) - - return partitions - -def get_table_type(disk=None): - _type = 'Unknown' - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - - try: - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('uniqueid disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): - _type = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): - _type = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): - _type = 'MBR' - - return _type - -def get_volumes(): - vols = [] - - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append volume numbers - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): - vols.append({'Number': tmp[0], 'Letter': tmp[1]}) - - return vols - def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): disk['Backup Warnings'] = '\n' disk['Clobber Risk'] = [] @@ -342,54 +104,6 @@ def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) == 1: disk['Backup Warnings'] += '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) -def prep_disk_for_formatting(disk=None): - disk['Format Warnings'] = '\n' - width = len(str(len(disk['Partitions']))) - - # Bail early - if disk is None: - raise Exception('Disk not provided.') - - # Set boot method and partition table type - disk['Use GPT'] = True - if (get_boot_mode() == 'UEFI'): - if (not ask("Setup Windows to use UEFI booting?")): - disk['Use GPT'] = False - else: - if (ask("Setup Windows to use BIOS/Legacy booting?")): - disk['Use GPT'] = False - - # Set Display and Warning Strings - if len(disk['Partitions']) == 0: - disk['Format Warnings'] += 'No partitions found\n' - for par in disk['Partitions']: - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - # FileSystem not accessible to WinPE. List partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) - else: - # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) - -def remove_volume_letters(keep=''): - if keep is None: - keep = '' - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - if vol['Letter'].upper() != keep.upper(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('remove noerr\n') - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - except subprocess.CalledProcessError: - pass - def select_backup_destination(): # Build menu dests = [] @@ -420,47 +134,6 @@ def select_backup_destination(): print_warning('No backup destinations found.') return None -def select_disk(prompt='Which disk?'): - """Select a disk from the attached disks""" - disks = get_attached_disk_info() - - # Build menu - disk_options = [] - for disk in disks: - display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if len(disk['Partitions']) > 0: - pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: - # Show unsupported partition(s) in RED - par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - par_skip = True - if par_skip: - display_name += COLORS['YELLOW'] - - # Main text - display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) - if par['Name'] != '': - display_name += '\t"{Name}"'.format(**par) - - # Clear color (if set above) - if par_skip: - display_name += COLORS['CLEAR'] - else: - display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) - disk_options.append({'Name': display_name, 'Disk': disk}) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select(prompt, disk_options, actions) - - if (selection.isnumeric()): - return disk_options[int(selection)-1]['Disk'] - elif (selection == 'M'): - abort_to_main_menu() - def verify_wim_backup(bin=None, par=None): # Bail early if bin is None: diff --git a/Scripts/functions/data.py b/Scripts/functions/data.py index 66797329..63825293 100644 --- a/Scripts/functions/data.py +++ b/Scripts/functions/data.py @@ -374,7 +374,7 @@ def scan_source_wim(source_wim, dest_path, rel_path=None, interactive=True): def select_destination(folder_path, prompt='Select destination'): """Select destination drive, returns path as string.""" - disk = select_disk(prompt) + disk = select_volume(prompt) if 'fixed' not in disk['Disk'].opts: folder_path = folder_path.replace('\\', '-') path = '{disk}{folder_path}_{Date}'.format( @@ -388,7 +388,7 @@ def select_destination(folder_path, prompt='Select destination'): return path -def select_disk(title='Select disk', auto_select=True): +def select_volume(title='Select disk', auto_select=True): """Select disk from attached disks. returns dict.""" actions = [{'Name': 'Quit', 'Letter': 'Q'}] disks = [] diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py new file mode 100644 index 00000000..3b7730c0 --- /dev/null +++ b/Scripts/functions/disk.py @@ -0,0 +1,345 @@ +# Wizard Kit PE: Functions - Disk + +from functions.common import * +import partition_uids + +def assign_volume_letters(): + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('assign\n') + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + except subprocess.CalledProcessError: + pass + +def get_attached_disk_info(): + """Get details about the attached disks""" + disks = [] + print_info('Getting drive info...') + + # Assign all the letters + assign_volume_letters() + + # Get disks + disks = get_disks() + + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for par in disk['Partitions']: + # Get partition details + par.update(get_partition_details(disk, par)) + + # Done + return disks + +def get_boot_mode(): + boot_mode = 'Legacy' + try: + reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + boot_mode = 'UEFI' + except: + boot_mode = 'Unknown' + + return boot_mode + +def get_disk_details(disk=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('detail disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Set disk name + details['Name'] = tmp[4] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + return details + +def get_disks(): + disks = [] + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append disk numbers + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + disks.append({'Number': _num, 'Size': _size}) + + return disks + +def get_partition_details(disk=None, par=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Diskpart details + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('select partition {Number}\n'.format(**par)) + script.write('detail partition\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Get volume letter or RAW status + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) + if tmp: + if tmp.group(1).upper() == 'RAW': + details['FileSystem'] = RAW + else: + details['Letter'] = tmp.group(1) + + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + guid = partition_uids.lookup_guid(details['Type']) + if guid is not None: + details.update({ + 'Description': guid.get('Description', ''), + 'OS': guid.get('OS', '')}) + + if 'Letter' in details: + # Disk usage + tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) + details['Used Space'] = human_readable_size(tmp.used) + + # fsutil details + try: + process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Add "Feature" lines + details['File System Features'] = [s.strip() for s in tmp if ':' not in s] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Set Volume Name + details['Name'] = details.get('Volume Name', '') + + # Set FileSystem Type + if details.get('FileSystem', '') != 'RAW': + details['FileSystem'] = details.get('File System Name', 'Unknown') + + return details + +def get_partitions(disk=None): + partitions = [] + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('list partition\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append partition numbers + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + partitions.append({'Number': _num, 'Size': _size}) + + return partitions + +def get_table_type(disk=None): + _type = 'Unknown' + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('uniqueid disk\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): + _type = 'GPT' + elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): + _type = 'RAW' + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): + _type = 'MBR' + + return _type + +def get_volumes(): + vols = [] + + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append volume numbers + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): + vols.append({'Number': tmp[0], 'Letter': tmp[1]}) + + return vols + +def prep_disk_for_formatting(disk=None): + disk['Format Warnings'] = '\n' + width = len(str(len(disk['Partitions']))) + + # Bail early + if disk is None: + raise Exception('Disk not provided.') + + # Set boot method and partition table type + disk['Use GPT'] = True + if (get_boot_mode() == 'UEFI'): + if (not ask("Setup Windows to use UEFI booting?")): + disk['Use GPT'] = False + else: + if (ask("Setup Windows to use BIOS/Legacy booting?")): + disk['Use GPT'] = False + + # Set Display and Warning Strings + if len(disk['Partitions']) == 0: + disk['Format Warnings'] += 'No partitions found\n' + for par in disk['Partitions']: + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): + # FileSystem not accessible to WinPE. List partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + else: + # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician + par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + +def remove_volume_letters(keep=''): + if keep is None: + keep = '' + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('remove noerr\n') + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + except subprocess.CalledProcessError: + pass + +def select_disk(prompt='Which disk?'): + """Select a disk from the attached disks""" + disks = get_attached_disk_info() + + # Build menu + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + if len(disk['Partitions']) > 0: + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Show unsupported partition(s) in RED + par_skip = False + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): + par_skip = True + if par_skip: + display_name += COLORS['YELLOW'] + + # Main text + display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) + if par['Name'] != '': + display_name += '\t"{Name}"'.format(**par) + + # Clear color (if set above) + if par_skip: + display_name += COLORS['CLEAR'] + else: + display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select(prompt, disk_options, actions) + + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + abort_to_main_menu() + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index 8de76f76..199999a4 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -1,9 +1,9 @@ # Wizard Kit PE: Functions - Windows Setup -from functions.common import * +from functions.data import * # STATIC VARIABLES -DISKPART_SCRIPT = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) +DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) WINDOWS_VERSIONS = [ {'Name': 'Windows 7 Home Basic', 'Image File': 'Win7', @@ -43,24 +43,6 @@ WINDOWS_VERSIONS = [ 'Family': '10'}, ] -def is_index_in_image(bin=None, filename=None, imagename=None): - # Bail early - if bin is None: - raise Exception('bin not specified.') - if filename is None: - raise Exception('Filename not specified.') - if imagename is None: - raise Exception('Image Name not specified.') - - cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) - try: - run_program(cmd) - except subprocess.CalledProcessError: - print_error('Invalid image: {filename}'.format(filename=filename)) - return False - - return True - def find_windows_image(bin, windows_version): """Search for a Windows source image file on local drives and network drives (in that order)""" image = {} @@ -73,7 +55,7 @@ def find_windows_image(bin, windows_version): filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) if os.path.isfile(filename_ext): - if is_index_in_image(bin, filename_ext, windows_version['Image Name']): + if wim_contains_image(bin, filename_ext, windows_version['Image Name']): image['Ext'] = ext image['File'] = filename image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' @@ -89,7 +71,7 @@ def find_windows_image(bin, windows_version): filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) if os.path.isfile(filename_ext): - if is_index_in_image(bin, filename_ext, windows_version['Image Name']): + if wim_contains_image(bin, filename_ext, windows_version['Image Name']): image['Ext'] = ext image['File'] = filename image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' @@ -186,18 +168,6 @@ def format_mbr(disk=None, windows_family=None): run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) time.sleep(2) -def get_boot_mode(): - boot_mode = 'Legacy' - try: - reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') - reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] - if reg_value == 2: - boot_mode = 'UEFI' - except: - boot_mode = 'Unknown' - - return boot_mode - def mount_windows_share(): """Mount the Windows images share unless labeled as already mounted.""" if WINDOWS_SERVER['Mounted']: @@ -253,5 +223,23 @@ def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T') def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) +def wim_contains_image(bin=None, filename=None, imagename=None): + # Bail early + if bin is None: + raise Exception('bin not specified.') + if filename is None: + raise Exception('Filename not specified.') + if imagename is None: + raise Exception('Image Name not specified.') + + cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Invalid image: {filename}'.format(filename=filename)) + return False + + return True + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 21d2e11b..b03802b4 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -1,6 +1,8 @@ # Wizard Kit PE: Menus -from functions.data import * +from functions.backup import * +from functions.disk import * +from functions.windows_setup import * # STATIC VARIABLES FAST_COPY_ARGS = [ diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index 370186f0..542114a5 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -6,7 +6,6 @@ import sys # Init os.chdir(os.path.dirname(os.path.realpath(__file__))) sys.path.append(os.getcwd()) -from functions.common import * from functions.winpe_menus import * init_global_vars() os.system('title {}: Root Menu'.format(KIT_NAME_FULL)) From b0db11cb4acca0897c3a58345c32ac379ab3cb7d Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 16:50:14 -0800 Subject: [PATCH 43/85] Added wimlib-imagex Woops, it's been missing for a bit.. --- .bin/Scripts/build_pe.ps1 | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 631d6d9e..fcc01980 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -162,7 +162,10 @@ if ($MyInvocation.InvocationName -ne ".") { @("qdir32.zip", "https://www.softwareok.com/Download/Q-Dir_Portable.zip"), # TestDisk / PhotoRec @("testdisk64.zip", "https://www.cgsecurity.org/testdisk-7.1-WIP.win64.zip"), - @("testdisk32.zip", "https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip") + @("testdisk32.zip", "https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip"), + # wimlib-imagex + @("wimlib64.zip", "https://wimlib.net/downloads/wimlib-1.12.0-windows-x86_64-bin.zip"), + @("wimlib32.zip", "https://wimlib.net/downloads/wimlib-1.12.0-windows-i686-bin.zip") ) foreach ($Tool in $ToolSources) { DownloadFile -Path $Temp -Name $Tool[0] -Url $Tool[1] @@ -444,6 +447,22 @@ if ($MyInvocation.InvocationName -ne ".") { catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" } + + # wimlib-imagex + try { + $ArgumentList = @( + "x", "$Temp\wimlib64.zip", "-o$Root\WK\amd64\wimlib", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + $ArgumentList = @( + "x", "$Temp\wimlib32.zip", "-o$Root\WK\x86\wimlib", + "-aoa", "-bso0", "-bse0", "-bsp0") + Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait + Remove-Item "$Temp\wimlib*" + } + catch { + Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" + } } ## Build ## From 45f0b4d2b1fdb2054cfc27a85286395bbe79c291 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 17:17:00 -0800 Subject: [PATCH 44/85] updated backup_partition() --- Scripts/functions/backup.py | 38 ++++++++++++-------------------- Scripts/functions/common.py | 7 ++++-- Scripts/functions/winpe_menus.py | 16 +++++++++++--- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index e33004ba..f91c692f 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -2,31 +2,21 @@ from functions.common import * -def backup_partition(bin=None, disk=None, par=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if disk is None: - raise Exception('Disk not specified.') - if par is None: - raise Exception('Partition not specified.') +def backup_partition(disk, partition): + if par['Image Exists'] or par['Number'] in disk['Bad Partitions']: + raise GenericAbort - print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) - if par['Number'] in disk['Bad Partitions']: - print_warning('Skipped.') - else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=none'.format(bin=bin, **par) - if par['Image Exists']: - print_warning('Skipped.') - else: - try: - os.makedirs('{Image Path}'.format(**par), exist_ok=True) - run_program(cmd) - print_success('Complete.') - except subprocess.CalledProcessError as err: - print_error('Failed.') - par['Error'] = err.stderr.decode().splitlines() - raise BackupError + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'capture' + '{}:\\'.format(par['Letter']), + r'{}\{}'.format(par['Image Path'], par['Image File']), + par['Image Name'], # Image name + par['Image Name'], # Image description + ' --compress=none', + ] + os.makedirs(par['Image Path'], exist_ok=True) + run_program(cmd) def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): disk['Backup Warnings'] = '\n' diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index fcb2dd51..4cf147e7 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -37,6 +37,9 @@ class BIOSKeyNotFoundError(Exception): class BinNotFoundError(Exception): pass +class GenericAbort(Exception): + pass + class GenericError(Exception): pass @@ -52,7 +55,7 @@ class NotInstalledError(Exception): class NoProfilesError(Exception): pass -class PathNotFoundException(Exception): +class PathNotFoundError(Exception): pass class UnsupportedOSError(Exception): @@ -432,7 +435,7 @@ def try_and_print(message='Trying...', err = traceback.format_exc() # Return or raise? - if bool(err) and not catch_all: + if err and not catch_all: raise else: return {'CS': not bool(err), 'Error': err} diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index b03802b4..2056b4fd 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -53,6 +53,14 @@ PE_TOOLS = { def menu_backup(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" errors = False + other_results = { + 'Error': { + 'CalledProcessError': 'Unknown Error', + }, + 'Warning': { + 'GenericAbort': 'Skipped', + 'GenericRepair': 'Repaired', + }} # Set ticket ID os.system('cls') @@ -89,10 +97,12 @@ def menu_backup(): # Backup partition(s) print('\n\nStarting task.\n') for par in disk['Partitions']: - try: - backup_partition(bin, disk, par) - except BackupError: + message = 'Partition {} Backup...'.format(par['Number']) + result = try_and_print(message=message, function=backup_partition, + other_results=other_results, disk=disk, partition=par) + if not result['CS']: errors = True + par['Error'] = result['Error'] # Verify backup(s) if disk['Valid Partitions'] > 1: From 67f08c50429d88198503dff6b1ed7837bceca4d3 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 19:45:59 -0800 Subject: [PATCH 45/85] updated prep_disk_for_backup() * Partition['Image Path'] is set to the full destination path * (i.e. ['Image Path'] + '\\' + ['Image File'] * Partition['Image File'] variable has been removed * Simplified ['Backup Warnings'] section * Added fix_path() * Replaces unsupported characters/strings with underscores --- Scripts/functions/backup.py | 127 +++++++++++++++++-------------- Scripts/functions/winpe_menus.py | 55 +++++++------ Scripts/winpe_root_menu.py | 2 + 3 files changed, 103 insertions(+), 81 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index f91c692f..62e45d19 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -2,6 +2,15 @@ from functions.common import * +# Regex +REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) +REGEX_BAD_PATH_NAMES = re.compile( + r'([<>:"/\\\|\?\*]' + r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' + r'|^\s+' + r'|[\s\.]+$', + re.IGNORECASE) + def backup_partition(disk, partition): if par['Image Exists'] or par['Number'] in disk['Bad Partitions']: raise GenericAbort @@ -10,89 +19,91 @@ def backup_partition(disk, partition): global_vars['Tools']['wimlib-imagex'], 'capture' '{}:\\'.format(par['Letter']), - r'{}\{}'.format(par['Image Path'], par['Image File']), + par['Image Path'], par['Image Name'], # Image name par['Image Name'], # Image description ' --compress=none', ] - os.makedirs(par['Image Path'], exist_ok=True) + dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE) + os.makedirs(dest_dir, exist_ok=True) run_program(cmd) -def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): - disk['Backup Warnings'] = '\n' +def fix_path(path): + return REGEX_BAD_PATH_NAMES.sub('_', path) + +def prep_disk_for_backup(destination, disk, ticket_number): disk['Clobber Risk'] = [] width = len(str(len(disk['Partitions']))) - - # Bail early - if dest is None: - raise Exception('Destination not provided.') - if disk is None: - raise Exception('Disk not provided.') - if ticket_id is None: - raise Exception('Ticket ID not provided.') # Get partition totals - disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE)] - disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) - - # Bail if no valid partitions are found (those that can be imaged) + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] + if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem'])] + num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) + disk['Valid Partitions'] = num_valid_partitions if disk['Valid Partitions'] <= 0: - abort_to_main_menu(' No partitions can be imaged for the selected drive') + print_error('ERROR: No partitions can be backed up for this disk') + raise GenericAbort # Prep partitions for par in disk['Partitions']: + display = 'Partition {num:>{width}}:\t{size} {fs}'.format( + num = par['Number'], + width = width, + size = par['Size'], + fs = par['FileSystem']) + if par['Number'] in disk['Bad Partitions']: - par['Display String'] = '{YELLOW} * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS}){CLEAR}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par, - **COLORS) + # Set display string using partition description & OS type + display = ' * {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( + display = display, + q = '"' if par['Name'] != '' else '', + name = par['Name'], + desc = par['Description'], + os = par['OS']) + display = '{YELLOW}{display}{CLEAR}'.format( + display=display, **COLORS) else: # Update info for WIM capturing - par['Image Name'] = str(par['Name']) - if par['Image Name'] == '': - par['Image Name'] = 'Unknown' - if 'IP' in dest: - par['Image Path'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket_id, **dest) + par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' + if 'IP' in destination: + par['Image Path'] = r'\\{}\{}\{}'.format( + destination['IP'], destination['Share'], ticket_number) else: - par['Image Path'] = '{Letter}:\\{ticket}'.format(ticket=ticket_id, **dest) - par['Image File'] = '{Number}_{Image Name}'.format(**par) - par['Image File'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['Image File'])) + par['Image Path'] = r'{}:\{}'.format( + ticket_number, destination['Letter']) + par['Image Path'] += r'\{}_{}.wim'.format( + par['Number'], par['Image Name']) + par['Image Path'] = fix_path(par['Image Path']) # Check for existing backups - par['Image Exists'] = False - if os.path.exists('{Image Path}\\{Image File}'.format(**par)): - par['Image Exists'] = True + par['Image Exists'] = os.path.exists(par['Image Path']) + if par['Image Exists']: disk['Clobber Risk'].append(par['Number']) - par['Display String'] = '{BLUE} + '.format(**COLORS) + display = '{} + {}'.format(COLORS['BLUE'], display) else: - par['Display String'] = '{CLEAR} '.format(**COLORS) + display = '{} {}'.format(COLORS['CLEAR'], display) # Append rest of Display String for valid/clobber partitions - par['Display String'] += 'Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}{CLEAR}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par, + display += ' (Used: {used})\t{q}{name}{q}{CLEAR}'.format( + used = par['Used Space'], + q = '"' if par['Name'] != '' else '', + name = par['Name'], **COLORS) + # For all partitions + par['Display String'] = display # Set description for bad partitions - if len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] += '{YELLOW} * Unable to backup these partitions{CLEAR}\n'.format(**COLORS) - elif len(disk['Bad Partitions']) == 1: - print_warning(' * Unable to backup this partition') - disk['Backup Warnings'] += '{YELLOW} * Unable to backup this partition{CLEAR}\n'.format(**COLORS) - - # Set description for partitions that would be clobbered - if len(disk['Clobber Risk']) > 1: - disk['Backup Warnings'] += '{BLUE} + These partitions already have backup images on {Name}{CLEAR}\n'.format(**dest, **COLORS) - elif len(disk['Clobber Risk']) == 1: - disk['Backup Warnings'] += '{BLUE} + This partition already has a backup image on {Name}{CLEAR}\n'.format(**dest, **COLORS) - - # Set warning for skipped partitions - if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) > 1: - disk['Backup Warnings'] += '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) - if len(disk['Clobber Risk']) + len(disk['Bad Partitions']) == 1: - disk['Backup Warnings'] += '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}\n'.format(**COLORS) + warnings = '\n' + if disk['Bad Partitions']: + warnings += '{} * Unsupported filesystem{}\n'.format( + COLORS['YELLOW'], COLORS['CLEAR']) + if disk['Clobber Risk']: + warnings += '{} + Backup exists on {}{}\n'.format( + COLORS['BLUE'], destination['Name'], COLORS['CLEAR']) + if disk['Bad Partitions'] or disk['Clobber Risk']: + warnings += '\n{}Marked partition(s) will NOT be backed up.{}\n'.format( + COLORS['YELLOW'], COLORS['CLEAR']) + disk['Backup Warnings'] = warnings def select_backup_destination(): # Build menu @@ -133,8 +144,8 @@ def verify_wim_backup(bin=None, par=None): # Verify hiding all output for quicker verification print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) - cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}\\{Image File}" --nocheck'.format(bin=bin, **par) - if not os.path.exists('{Image Path}\\{Image File}'.format(**par)): + cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}" --nocheck'.format(bin=bin, **par) + if not os.path.exists('{Image Path}'.format(**par)): print_error('Missing.') else: try: diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 2056b4fd..ddbcc313 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -62,40 +62,49 @@ def menu_backup(): 'GenericRepair': 'Repaired', }} - # Set ticket ID + # Set ticket Number os.system('cls') - ticket_id = get_ticket_number() + ticket_number = get_ticket_number() # Mount backup shares mount_backup_shares() # Select destination - dest = select_backup_destination() - if dest is None: - abort_to_main_menu('Aborting Backup Creation') + destination = select_backup_destination() + if not destination: + raise GenericAbort # Select disk to backup disk = select_disk('For which drive are we creating backups?') - if disk is None: - abort_to_main_menu() - prep_disk_for_backup(dest, disk, ticket_id) + if not disk: + raise GenericAbort + + # "Prep" disk? + prep_disk_for_backup(destination, disk, ticket_number) # Display details for backup task os.system('cls') - print('Create Backup - Details:\n') - print(' Ticket: \t{ticket_id}'.format(ticket_id=ticket_id)) - print(' Source: \t[{Table}] ({Type}) {Name} {Size}\n'.format(**disk)) - print(' Destination:\t{name}'.format(name=dest.get('Display Name', dest['Name']))) + print_info('Create Backup - Details:\n') + # def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): + show_info(message='Ticket:', info=ticket_number) + show_info( + message = 'Source:', + info = '[{Table}] ({Type}) {Name} {Size}'.format(**disk), + ) + show_info( + message = 'Destination:', + info = destination.get('Display Name', destination['Name']), + ) for par in disk['Partitions']: - print(par['Display String']) - print(disk['Backup Warnings']) + show_info(message='', info=par['Display String'], width=20) + print_standard(disk['Backup Warnings']) # Ask to proceed if (not ask('Proceed with backup?')): - abort_to_main_menu('Aborting Backup Creation') + raise GenericAbort # Backup partition(s) - print('\n\nStarting task.\n') + print_info('\n\nStarting task.\n') for par in disk['Partitions']: message = 'Partition {} Backup...'.format(par['Number']) result = try_and_print(message=message, function=backup_partition, @@ -106,9 +115,9 @@ def menu_backup(): # Verify backup(s) if disk['Valid Partitions'] > 1: - print('\n\n Verifying backups\n') + print_info('\n\n Verifying backups\n') else: - print('\n\n Verifying backup\n') + print_info('\n\n Verifying backup\n') for par in disk['Partitions']: if par['Number'] in disk['Bad Partitions']: continue # Skip verification @@ -121,9 +130,9 @@ def menu_backup(): if errors: print_warning('\nErrors were encountered and are detailed below.') for par in [p for p in disk['Partitions'] if 'Error' in p]: - print(' Partition {Number} Error:'.format(**par)) - for line in [line.strip() for line in par['Error'] if line.strip() != '']: - print_error('\t{line}'.format(line=line)) + print_standard(' Partition {} Error:'.format(par['Number'])) + for line in [line.strip() for line in par['Error'] if line.strip()]: + print_error('\t{}'.format(line)) time.sleep(30) else: print_success('\nNo errors were encountered during imaging.') @@ -171,7 +180,7 @@ def menu_setup(): # Set ticket ID os.system('cls') - ticket_id = get_ticket_number() + ticket_number = get_ticket_number() # Select the version of Windows to apply windows_version = select_windows_version() @@ -188,7 +197,7 @@ def menu_setup(): # Display details for setup task os.system('cls') print('Setup Windows - Details:\n') - print(' Ticket: \t{ticket_id}'.format(ticket_id=ticket_id)) + print(' Ticket: \t{ticket_number}'.format(ticket_number=ticket_number)) print(' Installing: \t{winver}'.format(winver=windows_version['Name'])) print(' Boot Method:\t{_type}'.format( _type='UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')) diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index 542114a5..9ff1508d 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -14,6 +14,8 @@ global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) if __name__ == '__main__': try: menu_root() + except GenericAbort: + pause('Press Enter to return to main menu... ') except SystemExit: pass except: From c043c3398d7de8dbb14bf68d570f0bb5a8d2027d Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 19:56:42 -0800 Subject: [PATCH 46/85] Reordered functions --- Scripts/functions/data.py | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Scripts/functions/data.py b/Scripts/functions/data.py index 63825293..d180c699 100644 --- a/Scripts/functions/data.py +++ b/Scripts/functions/data.py @@ -388,43 +388,6 @@ def select_destination(folder_path, prompt='Select destination'): return path -def select_volume(title='Select disk', auto_select=True): - """Select disk from attached disks. returns dict.""" - actions = [{'Name': 'Quit', 'Letter': 'Q'}] - disks = [] - - # Build list of disks - set_thread_error_mode(silent=True) # Prevents "No disk" popups - for d in psutil.disk_partitions(): - info = { - 'Disk': d, - 'Name': d.mountpoint} - try: - usage = psutil.disk_usage(d.device) - free = '{free} / {total} available'.format( - free = human_readable_size(usage.free, 2), - total = human_readable_size(usage.total, 2)) - except Exception: - # Meh, leaving unsupported destinations out - pass - # free = 'Unknown' - # info['Disabled'] = True - else: - info['Display Name'] = '{} ({})'.format(info['Name'], free) - disks.append(info) - set_thread_error_mode(silent=False) # Return to normal - - # Skip menu? - if len(disks) == 1 and auto_select: - return disks[0] - - # Show menu - selection = menu_select(title, main_entries=disks, action_entries=actions) - if selection == 'Q': - exit_script() - else: - return disks[int(selection)-1] - def select_source(ticket_number): """Select backup from those found on the BACKUP_SERVERS for the ticket.""" selected_source = None @@ -536,6 +499,43 @@ def select_source(ticket_number): # Done return selected_source +def select_volume(title='Select disk', auto_select=True): + """Select disk from attached disks. returns dict.""" + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + disks = [] + + # Build list of disks + set_thread_error_mode(silent=True) # Prevents "No disk" popups + for d in psutil.disk_partitions(): + info = { + 'Disk': d, + 'Name': d.mountpoint} + try: + usage = psutil.disk_usage(d.device) + free = '{free} / {total} available'.format( + free = human_readable_size(usage.free, 2), + total = human_readable_size(usage.total, 2)) + except Exception: + # Meh, leaving unsupported destinations out + pass + # free = 'Unknown' + # info['Disabled'] = True + else: + info['Display Name'] = '{} ({})'.format(info['Name'], free) + disks.append(info) + set_thread_error_mode(silent=False) # Return to normal + + # Skip menu? + if len(disks) == 1 and auto_select: + return disks[0] + + # Show menu + selection = menu_select(title, main_entries=disks, action_entries=actions) + if selection == 'Q': + exit_script() + else: + return disks[int(selection)-1] + def set_thread_error_mode(silent=True): """Disable or Enable Windows error message dialogs. From 7133089d31ee468e3bc1b1357f0d3ea66c1af7df Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 20:03:19 -0800 Subject: [PATCH 47/85] updated select_backup_destination() --- Scripts/functions/backup.py | 36 +++++++++++++++++--------------- Scripts/functions/winpe_menus.py | 2 -- Scripts/winpe_root_menu.py | 3 ++- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index 62e45d19..4ab89a43 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -105,35 +105,37 @@ def prep_disk_for_backup(destination, disk, ticket_number): COLORS['YELLOW'], COLORS['CLEAR']) disk['Backup Warnings'] = warnings -def select_backup_destination(): +def select_backup_destination(auto_select=True): # Build menu - dests = [] - for server in BACKUP_SERVERS: - if server['Mounted']: - dests.append(server) + destinations = [s for s in BACKUP_SERVERS if s['Mounted']] actions = [ {'Name': 'Main Menu', 'Letter': 'M'}, ] # Size check - for dest in dests: + for dest in destinations: if 'IP' in dest: - dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) + dest['Usage'] = shutil.disk_usage(r'\\{IP}\{Share}'.format(**dest)) else: - dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) + dest['Usage'] = shutil.disk_usage('{}:\\'.format(dest['Letter'])) dest['Free Space'] = human_readable_size(dest['Usage'].free) dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) - # Show menu or bail - if len(dests) > 0: - selection = menu_select('Where are we backing up to?', dests, actions) - if selection == 'M': - return None - else: - return dests[int(selection)-1] - else: + # Bail + if not destinations: print_warning('No backup destinations found.') - return None + raise GenericAbort + + # Skip menu? + if len(destinations) == 1 and auto_select: + return destinations[0] + + selection = menu_select( + 'Where are we backing up to?', destinations, actions) + if selection == 'M': + raise GenericAbort + else: + return destinations[int(selection)-1] def verify_wim_backup(bin=None, par=None): # Bail early diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index ddbcc313..2f405325 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -71,8 +71,6 @@ def menu_backup(): # Select destination destination = select_backup_destination() - if not destination: - raise GenericAbort # Select disk to backup disk = select_disk('For which drive are we creating backups?') diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index 9ff1508d..ad19b34b 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -15,7 +15,8 @@ if __name__ == '__main__': try: menu_root() except GenericAbort: - pause('Press Enter to return to main menu... ') + # pause('Press Enter to return to main menu... ') + pass except SystemExit: pass except: From b96e5f3be6d2bb2a7e2db8144809eda8f036df7d Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 20:31:37 -0800 Subject: [PATCH 48/85] updated verify_wim_backup() --- Scripts/functions/backup.py | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index 4ab89a43..c884638a 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -137,26 +137,16 @@ def select_backup_destination(auto_select=True): else: return destinations[int(selection)-1] -def verify_wim_backup(bin=None, par=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if par is None: - raise Exception('Partition not specified.') - - # Verify hiding all output for quicker verification - print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) - cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}" --nocheck'.format(bin=bin, **par) - if not os.path.exists('{Image Path}'.format(**par)): - print_error('Missing.') - else: - try: - run_program(cmd) - print_success('OK.') - except subprocess.CalledProcessError as err: - print_error('Damaged.') - par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() - raise BackupError +def verify_wim_backup(partition): + if not os.path.exists(partition['Image Path']): + raise PathNotFoundError + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'verify', + partition['Image Path'], + ' --nocheck', + ] + run_program(cmd) if __name__ == '__main__': print("This file is not meant to be called directly.") From 850a1fca738f747c5393a472513761fdd32be24c Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 20:31:46 -0800 Subject: [PATCH 49/85] updated menu_backup() --- Scripts/functions/winpe_menus.py | 42 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 2f405325..e14c0a22 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -56,6 +56,7 @@ def menu_backup(): other_results = { 'Error': { 'CalledProcessError': 'Unknown Error', + 'PathNotFoundError': 'Missing', }, 'Warning': { 'GenericAbort': 'Skipped', @@ -112,25 +113,40 @@ def menu_backup(): par['Error'] = result['Error'] # Verify backup(s) - if disk['Valid Partitions'] > 1: - print_info('\n\n Verifying backups\n') - else: - print_info('\n\n Verifying backup\n') - for par in disk['Partitions']: - if par['Number'] in disk['Bad Partitions']: - continue # Skip verification - try: - verify_wim_backup(bin, par) - except BackupError: - errors = True + if disk['Valid Partitions']: + print_info('\n\n Verifying backup images(s)\n') + for par in disk['Partitions']: + if par['Number'] in disk['Bad Partitions']: + continue # Skip verification + message = 'Partition {} Image...'.format(par['Number']) + result = try_and_print(message=message, function=verify_wim_backup, + other_results=other_results, partition=par) + if not result['CS']: + errors = True + par['Error'] = result['Error'] # Print summary if errors: print_warning('\nErrors were encountered and are detailed below.') for par in [p for p in disk['Partitions'] if 'Error' in p]: print_standard(' Partition {} Error:'.format(par['Number'])) - for line in [line.strip() for line in par['Error'] if line.strip()]: - print_error('\t{}'.format(line)) + if hasattr(par['Error'], 'stderr'): + try: + par['Error'] = par['Error'].stderr.decode() + except: + # Deal with badly formatted error message + pass + if isinstance(par['Error'], basestring): + print_error('\t{}'.format(par['Error'])) + else: + try: + par['Error'] = par['Error'].splitlines() + par['Error'] = [line.strip() for line in par['Error']] + par['Error'] = [line for line in par['Error'] if line] + except: + pass + for line in par['Error']: + print_error('\t{}'.format(line)) time.sleep(30) else: print_success('\nNo errors were encountered during imaging.') From 4ed6d41d1065bdecbfde2f40f9f083c87ee4c8fe Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 21:08:52 -0800 Subject: [PATCH 50/85] Updated menu / title sections * Added set_title() which sets window title and global_vars['Title'] * menu_select() will now display global_vars['Title'] above title * (If it exists) * Bugfix: fixed a few bad calls of menu_select() --- Scripts/functions/backup.py | 4 +++- Scripts/functions/common.py | 11 +++++++++++ Scripts/functions/disk.py | 7 +++++-- Scripts/functions/windows_setup.py | 5 ++++- Scripts/functions/winpe_menus.py | 23 +++++++++++++++-------- Scripts/winpe_root_menu.py | 2 +- 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index c884638a..c0e31370 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -131,7 +131,9 @@ def select_backup_destination(auto_select=True): return destinations[0] selection = menu_select( - 'Where are we backing up to?', destinations, actions) + title = 'Where are we backing up to?', + main_entries = destinations, + action_entries = actions) if selection == 'M': raise GenericAbort else: diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index 4cf147e7..5204b45f 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -224,6 +224,10 @@ def menu_select(title='~ Untitled Menu ~', if not main_entries and not action_entries: raise Exception("MenuError: No items given") + # Set title + if 'Title' in global_vars: + title = '{}\n\n{}'.format(global_vars['Title']) + # Build menu menu_splash = '{}\n\n'.format(title) width = len(str(len(main_entries))) @@ -361,6 +365,13 @@ def run_program(cmd, args=[], check=True, pipe=True, shell=False): return process_return +def set_title(title='~Some Title~'): + """Set title. + + Used for window title and menu titles.""" + global_vars['Title'] = title + os.system('title {}'.format(title)) + def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): """Display info with formatting.""" print_standard('{indent}{message:<{width}}{info}'.format( diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 3b7730c0..5ea4be45 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -300,7 +300,7 @@ def remove_volume_letters(keep=''): except subprocess.CalledProcessError: pass -def select_disk(prompt='Which disk?'): +def select_disk(title='Which disk?'): """Select a disk from the attached disks""" disks = get_attached_disk_info() @@ -334,7 +334,10 @@ def select_disk(prompt='Which disk?'): ] # Menu loop - selection = menu_select(prompt, disk_options, actions) + selection = menu_select( + title = title, + main_entries = disk_options, + action_entries = actions) if (selection.isnumeric()): return disk_options[int(selection)-1]['Disk'] diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index 199999a4..aa1ced35 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -180,7 +180,10 @@ def select_windows_version(): actions = [{'Name': 'Main Menu', 'Letter': 'M'},] # Menu loop - selection = menu_select('Which version of Windows are we installing?', WINDOWS_VERSIONS, actions) + selection = menu_select( + title = 'Which version of Windows are we installing?', + main_entries = WINDOWS_VERSIONS, + action_entries = actions) if selection.isnumeric(): return WINDOWS_VERSIONS[int(selection)-1] diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index e14c0a22..419ef08e 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -62,6 +62,7 @@ def menu_backup(): 'GenericAbort': 'Skipped', 'GenericRepair': 'Repaired', }} + set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) # Set ticket Number os.system('cls') @@ -154,7 +155,6 @@ def menu_backup(): pause('\nPress Enter to return to main menu... ') def menu_root(): - title = '{}: Main Menu'.format(KIT_NAME_FULL) menus = [ {'Name': 'Create Backups', 'Menu': menu_backup}, {'Name': 'Setup Windows', 'Menu': menu_setup}, @@ -168,11 +168,12 @@ def menu_root(): # Main loop while True: + set_title(KIT_NAME_FULL) selection = menu_select( - title=title, - main_entries=menus, - action_entries=actions, - secret_exit=True) + title = 'Main Menu', + main_entries = menus, + action_entries = actions, + secret_exit = True) if (selection.isnumeric()): try: @@ -191,6 +192,7 @@ def menu_root(): def menu_setup(): """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" errors = False + set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) # Set ticket ID os.system('cls') @@ -295,13 +297,16 @@ def menu_setup(): pause('\nPress Enter to return to main menu... ') def menu_tools(): - title = '{}: Tools Menu'.format(KIT_NAME_FULL) tools = [k for k in sorted(PE_TOOLS.keys())] actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + set_title(KIT_NAME_FULL) # Menu loop while True: - selection = menu_select(title, tools, actions) + selection = menu_select( + title = 'Tools Menu', + main_entries = tools, + action_entries = actions) if (selection.isnumeric()): tool = tools[int(selection)-1] cmd = [PE_TOOLS[tool]['Path']] + PE_TOOLS[tool].get('Args', []) @@ -342,7 +347,9 @@ def select_minidump_path(): return None # Menu - selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) + selection = menu_select( + title = 'Which BSoD / MiniDump path are we scanning?', + main_entries = dumps) return dumps[int(selection) - 1]['Name'] if __name__ == '__main__': diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index ad19b34b..4bd39aef 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -8,7 +8,7 @@ os.chdir(os.path.dirname(os.path.realpath(__file__))) sys.path.append(os.getcwd()) from functions.winpe_menus import * init_global_vars() -os.system('title {}: Root Menu'.format(KIT_NAME_FULL)) +set_title('{}: Root Menu'.format(KIT_NAME_FULL)) global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) if __name__ == '__main__': From deb1e8f4fd20b2b67ede84a41611a56851c748e5 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 21:33:55 -0800 Subject: [PATCH 51/85] Volume letter updates * Added reassign_letter() * Attempts to reassign a volume to better ensure predictable letters * i.e. Local Windows source volume letter == 'I' * Adjusted code to avoid the "hidden" assign_volume_letters() call in select_disk() --- Scripts/functions/disk.py | 24 +++++++++++++++++++----- Scripts/functions/winpe_menus.py | 15 +++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 5ea4be45..f19bb81a 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -4,6 +4,7 @@ from functions.common import * import partition_uids def assign_volume_letters(): + remove_volume_letters() try: # Run script with open(DISKPART_SCRIPT, 'w') as script: @@ -19,9 +20,6 @@ def get_attached_disk_info(): disks = [] print_info('Getting drive info...') - # Assign all the letters - assign_volume_letters() - # Get disks disks = get_disks() @@ -286,8 +284,24 @@ def prep_disk_for_formatting(disk=None): q='"' if par['Name'] != '' else '', **par) -def remove_volume_letters(keep=''): - if keep is None: +def reassign_volume_letter(letter, new_letter='I'): + if not letter: + # Ignore + return None + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select volume {}\n'.format(letter)) + script.write('remove noerr\n') + script.write('assign letter={}\n'.format(new_letter)) + run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + except subprocess.CalledProcessError: + pass + else: + return new_letter + +def remove_volume_letters(keep=None): + if not keep: keep = '' try: # Run script diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 419ef08e..ceda3aa1 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -75,6 +75,7 @@ def menu_backup(): destination = select_backup_destination() # Select disk to backup + assign_volume_letters() disk = select_disk('For which drive are we creating backups?') if not disk: raise GenericAbort @@ -200,16 +201,15 @@ def menu_setup(): # Select the version of Windows to apply windows_version = select_windows_version() - - # Select drive to use as the OS drive - dest_disk = select_disk('To which drive are we installing Windows?') - prep_disk_for_formatting(dest_disk) # Find Windows image - ## NOTE: Needs to happen AFTER select_disk() is called as there's a hidden assign_volume_letters(). - ## This changes the current letters thus preventing installing from a local source. windows_image = find_windows_image(bin, windows_version) + # Select drive to use as the OS drive + assign_volume_letters() + dest_disk = select_disk('To which drive are we installing Windows?') + prep_disk_for_formatting(dest_disk) + # Display details for setup task os.system('cls') print('Setup Windows - Details:\n') @@ -235,6 +235,9 @@ def menu_setup(): # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) remove_volume_letters(keep=windows_image['Source']) + new_letter = reassign_volume_letter(letter=windows_image['Source']) + if new_letter: + windows_image['Source'] = new_letter # Format and partition drive print('\n Formatting Drive... \t\t', end='', flush=True) From e9ff02375f97cea418c85f10f7fee88e2377ad68 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 21:52:51 -0800 Subject: [PATCH 52/85] More letter updates --- Scripts/functions/disk.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index f19bb81a..4a265300 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -4,13 +4,16 @@ from functions.common import * import partition_uids def assign_volume_letters(): + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('assign\n') + + # Remove current letters remove_volume_letters() + + # Run script try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('assign\n') run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) except subprocess.CalledProcessError: pass @@ -303,13 +306,14 @@ def reassign_volume_letter(letter, new_letter='I'): def remove_volume_letters(keep=None): if not keep: keep = '' + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.write('select volume {Number}\n'.format(**vol)) + script.write('remove noerr\n') + + # Run script try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - if vol['Letter'].upper() != keep.upper(): - script.write('select volume {Number}\n'.format(**vol)) - script.write('remove noerr\n') run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) except subprocess.CalledProcessError: pass From fbedd79aa360662691885b9709dac46c8f092279 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 22:10:45 -0800 Subject: [PATCH 53/85] updated scan_disks() * Renamed from get_attached_disk_info() --- Scripts/functions/common.py | 3 +- Scripts/functions/disk.py | 52 ++++++++++++++------------------ Scripts/functions/winpe_menus.py | 30 +++++++++++++++--- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index 5204b45f..59826f0f 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -414,6 +414,7 @@ def try_and_print(message='Trying...', and the result string will be printed in the correct color. catch_all=False will result in unspecified exceptions being re-raised.""" err = None + out = None w_exceptions = other_results.get('Warning', {}).keys() w_exceptions = tuple(get_exception(e) for e in w_exceptions) e_exceptions = other_results.get('Error', {}).keys() @@ -449,7 +450,7 @@ def try_and_print(message='Trying...', if err and not catch_all: raise else: - return {'CS': not bool(err), 'Error': err} + return {'CS': not bool(err), 'Error': err, 'Out': out} def upload_data(path, file): """Add CLIENT_INFO_SERVER to authorized connections and upload file.""" diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 4a265300..15343053 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -18,32 +18,6 @@ def assign_volume_letters(): except subprocess.CalledProcessError: pass -def get_attached_disk_info(): - """Get details about the attached disks""" - disks = [] - print_info('Getting drive info...') - - # Get disks - disks = get_disks() - - # Get disk details - for disk in disks: - # Get partition style - disk['Table'] = get_table_type(disk) - - # Get disk name/model and physical details - disk.update(get_disk_details(disk)) - - # Get partition info for disk - disk['Partitions'] = get_partitions(disk) - - for par in disk['Partitions']: - # Get partition details - par.update(get_partition_details(disk, par)) - - # Done - return disks - def get_boot_mode(): boot_mode = 'Legacy' try: @@ -318,10 +292,30 @@ def remove_volume_letters(keep=None): except subprocess.CalledProcessError: pass -def select_disk(title='Which disk?'): - """Select a disk from the attached disks""" - disks = get_attached_disk_info() +def scan_disks(): + """Get details about the attached disks""" + disks = get_disks() + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for par in disk['Partitions']: + # Get partition details + par.update(get_partition_details(disk, par)) + + # Done + return disks + +def select_disk(title='Which disk?', disks): + """Select a disk from the attached disks""" # Build menu disk_options = [] for disk in disks: diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index ceda3aa1..69b551fe 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -74,13 +74,21 @@ def menu_backup(): # Select destination destination = select_backup_destination() + # Scan disks + try_and_print(message='Assigning letters...', function=assign_volume_letters, other_results=other_results) + result = try_and_print(message='Getting drive info...', function=scan_disks, other_results=other_results) + if result['CS']: + disks = result['Out'] + else: + print_error('ERROR: No disks found.') + raise GenericAbort + # Select disk to backup - assign_volume_letters() - disk = select_disk('For which drive are we creating backups?') + disk = select_disk('For which drive are we creating backups?', disks) if not disk: raise GenericAbort - # "Prep" disk? + # "Prep" disk prep_disk_for_backup(destination, disk, ticket_number) # Display details for backup task @@ -205,9 +213,21 @@ def menu_setup(): # Find Windows image windows_image = find_windows_image(bin, windows_version) + # Scan disks + try_and_print(message='Assigning letters...', function=assign_volume_letters, other_results=other_results) + result = try_and_print(message='Getting drive info...', function=scan_disks, other_results=other_results) + if result['CS']: + disks = result['Out'] + else: + print_error('ERROR: No disks found.') + raise GenericAbort + # Select drive to use as the OS drive - assign_volume_letters() - dest_disk = select_disk('To which drive are we installing Windows?') + dest_disk = select_disk('To which drive are we installing Windows?', disks) + if not disk: + raise GenericAbort + + # "Prep" disk prep_disk_for_formatting(dest_disk) # Display details for setup task From 6903078ee017ae602fae1d599be683b62fa4cadc Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 22:19:31 -0800 Subject: [PATCH 54/85] updated prep_disk_for_formatting() --- Scripts/functions/disk.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 15343053..3b2ff179 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -248,18 +248,28 @@ def prep_disk_for_formatting(disk=None): if len(disk['Partitions']) == 0: disk['Format Warnings'] += 'No partitions found\n' for par in disk['Partitions']: - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - # FileSystem not accessible to WinPE. List partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) + display = ' Partition {num:>{width}}:\t{size} {fs}'.format( + num = par['Number'], + width = width, + size = par['Size'], + fs = par['FileSystem']) + + if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']): + # Set display string using partition description & OS type + display += '\t\t{q}{name}{q}\t{desc} ({os})'.format( + display = display, + q = '"' if par['Name'] != '' else '', + name = par['Name'], + desc = par['Description'], + os = par['OS']) else: - # FileSystem accessible to WinPE. List space used instead of partition type / OS info for technician - par['Display String'] = ' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par) + # List space used instead of partition description & OS type + display += ' (Used: {used})\t{q}{name}{q}'.format( + used = par['Used Space'], + q = '"' if par['Name'] != '' else '', + name = par['Name']) + # For all partitions + par['Display String'] = display def reassign_volume_letter(letter, new_letter='I'): if not letter: @@ -320,7 +330,7 @@ def select_disk(title='Which disk?', disks): disk_options = [] for disk in disks: display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if len(disk['Partitions']) > 0: + if disk['Partitions']: pwidth=len(str(len(disk['Partitions']))) for par in disk['Partitions']: # Show unsupported partition(s) in RED From a0460d6a82775179ec3596429508e92a4f999c52 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 22:35:16 -0800 Subject: [PATCH 55/85] updated select_disk() --- Scripts/functions/disk.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 3b2ff179..d216847e 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -330,26 +330,25 @@ def select_disk(title='Which disk?', disks): disk_options = [] for disk in disks: display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if disk['Partitions']: - pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: - # Show unsupported partition(s) in RED - par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'], re.IGNORECASE): - par_skip = True - if par_skip: - display_name += COLORS['YELLOW'] + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Main text + p_name = 'Partition {num:>{width}}: {size} ({fs})'.format( + num = par['Number'], + width = pwidth, + size = par['Size'], + fs = par['FileSystem']) + if par['Name']: + p_name += '\t"{}"'.format(par['Name']) + + # Show unsupported partition(s) + if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']): + p_display_name = '{YELLOW}{display}{CLEAR}'.format(display=p_name, **COLORS) + + display_name += '\n\t\t\t{}'.format(display_name) + if not disk['Partitions']: + display_name += '\n\t\t\t{YELLOW}No partitions found.{CLEAR}'.format(**COLORS) - # Main text - display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) - if par['Name'] != '': - display_name += '\t"{Name}"'.format(**par) - - # Clear color (if set above) - if par_skip: - display_name += COLORS['CLEAR'] - else: - display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) disk_options.append({'Name': display_name, 'Disk': disk}) actions = [ {'Name': 'Main Menu', 'Letter': 'M'}, From c9513804823fc449df646d91e2caca3338b096f8 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 23:06:23 -0800 Subject: [PATCH 56/85] functions\disk.py done --- Scripts/functions/disk.py | 239 +++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 121 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index d216847e..50277ca2 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -3,10 +3,18 @@ from functions.common import * import partition_uids +# Regex +REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) +REGEX_DISK_GPT = re.compile( + r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', + re.IGNORECASE) +REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) +REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) + def assign_volume_letters(): with open(DISKPART_SCRIPT, 'w') as script: for vol in get_volumes(): - script.write('select volume {Number}\n'.format(**vol)) + script.write('select volume {}\n'.format(vol['Number'])) script.write('assign\n') # Remove current letters @@ -14,14 +22,15 @@ def assign_volume_letters(): # Run script try: - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) except subprocess.CalledProcessError: pass def get_boot_mode(): boot_mode = 'Legacy' try: - reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_key = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Control') reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] if reg_value == 2: boot_mode = 'UEFI' @@ -30,32 +39,25 @@ def get_boot_mode(): return boot_mode -def get_disk_details(disk=None): +def get_disk_details(disk): details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('detail disk\n') try: # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('detail disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: # Remove empty lines - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] # Set disk name details['Name'] = tmp[4] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + # Split each line on ':' skipping those without ':' tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict details.update({key.strip(): value.strip() for (key, value) in tmp}) @@ -63,90 +65,85 @@ def get_disk_details(disk=None): def get_disks(): disks = [] + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list disk\n') try: # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: # Append disk numbers - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - disks.append({'Number': _num, 'Size': _size}) + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output): + num = tmp[0] + size = human_readable_size(tmp[1]) + disks.append({'Number': num, 'Size': size}) return disks -def get_partition_details(disk=None, par=None): +def get_partition_details(disk, partition): details = {} - - # Bail early - if disk is None: - raise Exception('Disk not specified.') - if par is None: - raise Exception('Partition not specified.') + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('select partition {}\n'.format(partition['Number'])) + script.write('detail partition\n') # Diskpart details try: # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('select partition {Number}\n'.format(**par)) - script.write('detail partition\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: # Get volume letter or RAW status - tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output) if tmp: if tmp.group(1).upper() == 'RAW': details['FileSystem'] = RAW else: details['Letter'] = tmp.group(1) - - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + # Remove empty lines from output + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] + # Split each line on ':' skipping those without ':' tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict details.update({key.strip(): value.strip() for (key, value) in tmp}) # Get MBR type / GPT GUID for extra details on "Unknown" partitions guid = partition_uids.lookup_guid(details['Type']) - if guid is not None: + if guid: details.update({ 'Description': guid.get('Description', ''), 'OS': guid.get('OS', '')}) if 'Letter' in details: # Disk usage - tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) + tmp = shutil.disk_usage('{}:\\'.format(details['Letter'])) details['Used Space'] = human_readable_size(tmp.used) # fsutil details + cmd = [ + 'fsutil', + 'fsinfo', + 'volumeinfo', + '{}:'.format(details['Letter']) + ] try: - process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) - process_return = process_return.stdout.decode().strip() + output = run_program(cmd) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: - # Remove empty lines from process_return - tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] - + # Remove empty lines from output + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] # Add "Feature" lines - details['File System Features'] = [s.strip() for s in tmp if ':' not in s] - - # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + details['File System Features'] = [s.strip() for s in tmp + if ':' not in s] + # Split each line on ':' skipping those without ':' tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict details.update({key.strip(): value.strip() for (key, value) in tmp}) @@ -159,74 +156,72 @@ def get_partition_details(disk=None, par=None): return details -def get_partitions(disk=None): +def get_partitions(disk): partitions = [] - - # Bail early - if disk is None: - raise Exception('Disk not specified.') + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('list partition\n') try: # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('list partition\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: # Append partition numbers - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return, re.IGNORECASE): - _num = tmp[0] - _size = human_readable_size(tmp[1]) - partitions.append({'Number': _num, 'Size': _size}) + regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+' + for tmp in re.findall(regex, output, re.IGNORECASE): + num = tmp[0] + size = human_readable_size(tmp[1]) + partitions.append({'Number': num, 'Size': size}) return partitions -def get_table_type(disk=None): - _type = 'Unknown' - - # Bail early - if disk is None: - raise Exception('Disk not specified.') +def get_table_type(disk): + part_type = 'Unknown' + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('uniqueid disk\n') try: - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('uniqueid disk\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return, re.IGNORECASE): - _type = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return, re.IGNORECASE): - _type = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return, re.IGNORECASE): - _type = 'MBR' + if REGEX_DISK_GPT.search(output): + part_type = 'GPT' + elif REGEX_DISK_MBR.search(output): + part_type = 'MBR' + elif REGEX_DISK_RAW.search(output): + part_type = 'RAW' + else: + part_type = 'Unknown - return _type + return part_type def get_volumes(): vols = [] + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list volume\n') try: # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) - process_return = process_return.stdout.decode().strip() + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() except subprocess.CalledProcessError: pass else: # Append volume numbers - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output): vols.append({'Number': tmp[0], 'Letter': tmp[1]}) return vols +def is_bad_partition(par): + return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']) + def prep_disk_for_formatting(disk=None): disk['Format Warnings'] = '\n' width = len(str(len(disk['Partitions']))) @@ -247,29 +242,29 @@ def prep_disk_for_formatting(disk=None): # Set Display and Warning Strings if len(disk['Partitions']) == 0: disk['Format Warnings'] += 'No partitions found\n' - for par in disk['Partitions']: + for partition in disk['Partitions']: display = ' Partition {num:>{width}}:\t{size} {fs}'.format( - num = par['Number'], + num = partition['Number'], width = width, - size = par['Size'], - fs = par['FileSystem']) + size = partition['Size'], + fs = partition['FileSystem']) - if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']): + if is_bad_partition(partition): # Set display string using partition description & OS type display += '\t\t{q}{name}{q}\t{desc} ({os})'.format( display = display, - q = '"' if par['Name'] != '' else '', - name = par['Name'], - desc = par['Description'], - os = par['OS']) + q = '"' if partition['Name'] != '' else '', + name = partition['Name'], + desc = partition['Description'], + os = partition['OS']) else: # List space used instead of partition description & OS type display += ' (Used: {used})\t{q}{name}{q}'.format( - used = par['Used Space'], - q = '"' if par['Name'] != '' else '', - name = par['Name']) + used = partition['Used Space'], + q = '"' if partition['Name'] != '' else '', + name = partition['Name']) # For all partitions - par['Display String'] = display + partition['Display String'] = display def reassign_volume_letter(letter, new_letter='I'): if not letter: @@ -281,7 +276,7 @@ def reassign_volume_letter(letter, new_letter='I'): script.write('select volume {}\n'.format(letter)) script.write('remove noerr\n') script.write('assign letter={}\n'.format(new_letter)) - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) except subprocess.CalledProcessError: pass else: @@ -293,12 +288,12 @@ def remove_volume_letters(keep=None): with open(DISKPART_SCRIPT, 'w') as script: for vol in get_volumes(): if vol['Letter'].upper() != keep.upper(): - script.write('select volume {Number}\n'.format(**vol)) + script.write('select volume {}\n'.format(vol['Number'])) script.write('remove noerr\n') # Run script try: - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) except subprocess.CalledProcessError: pass @@ -317,9 +312,9 @@ def scan_disks(): # Get partition info for disk disk['Partitions'] = get_partitions(disk) - for par in disk['Partitions']: + for partition in disk['Partitions']: # Get partition details - par.update(get_partition_details(disk, par)) + partition.update(get_partition_details(disk, partition)) # Done return disks @@ -331,23 +326,25 @@ def select_disk(title='Which disk?', disks): for disk in disks: display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: + for partition in disk['Partitions']: # Main text p_name = 'Partition {num:>{width}}: {size} ({fs})'.format( - num = par['Number'], + num = partition['Number'], width = pwidth, - size = par['Size'], - fs = par['FileSystem']) - if par['Name']: - p_name += '\t"{}"'.format(par['Name']) + size = partition['Size'], + fs = partition['FileSystem']) + if partition['Name']: + p_name += '\t"{}"'.format(partition['Name']) # Show unsupported partition(s) - if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']): - p_display_name = '{YELLOW}{display}{CLEAR}'.format(display=p_name, **COLORS) + if is_bad_partition(partition): + p_display_name = '{YELLOW}{display}{CLEAR}'.format( + display=p_name, **COLORS) display_name += '\n\t\t\t{}'.format(display_name) if not disk['Partitions']: - display_name += '\n\t\t\t{YELLOW}No partitions found.{CLEAR}'.format(**COLORS) + display_name += '\n\t\t\t{}No partitions found.{}'.format( + COLORS['YELLOW'], COLORS['CLEAR']) disk_options.append({'Name': display_name, 'Disk': disk}) actions = [ From c09d7ab603ba206e1305bcfffb3f40a2c1dc1ff0 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Thu, 30 Nov 2017 23:06:41 -0800 Subject: [PATCH 57/85] updated functions\backup.py --- Scripts/functions/backup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Scripts/functions/backup.py b/Scripts/functions/backup.py index c0e31370..a562f4f5 100644 --- a/Scripts/functions/backup.py +++ b/Scripts/functions/backup.py @@ -1,9 +1,8 @@ # Wizard Kit PE: Functions - Backup -from functions.common import * +from functions.disk import * # Regex -REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) REGEX_BAD_PATH_NAMES = re.compile( r'([<>:"/\\\|\?\*]' r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' @@ -37,7 +36,7 @@ def prep_disk_for_backup(destination, disk, ticket_number): # Get partition totals disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] - if 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem'])] + if is_bad_partition(partition)] num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) disk['Valid Partitions'] = num_valid_partitions if disk['Valid Partitions'] <= 0: From 33924c183e08bcdc9c16e92682d18182fd8337e6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 09:59:19 -0800 Subject: [PATCH 58/85] Updated find_windows_image() & setup_windows() * Merged File and Ext dict entries * Using psutil instead of mountvol --- Scripts/functions/windows_setup.py | 91 ++++++++++++++---------------- Scripts/functions/winpe_menus.py | 6 +- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index aa1ced35..008c649d 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -43,48 +43,48 @@ WINDOWS_VERSIONS = [ 'Family': '10'}, ] -def find_windows_image(bin, windows_version): - """Search for a Windows source image file on local drives and network drives (in that order)""" +def find_windows_image(windows_version): + """Search for a Windows source image file, returns dict. + + Searches on local drives and then the WINDOWS_SERVER share.""" image = {} imagefile = windows_version['Image File'] + imagename = windows_version['Image Name'] # Search local source - process_return = run_program('mountvol') - for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): + for d in psutil.disk_partitions(): for ext in ['esd', 'wim', 'swm']: - filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) - filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) - if os.path.isfile(filename_ext): - if wim_contains_image(bin, filename_ext, windows_version['Image Name']): - image['Ext'] = ext - image['File'] = filename - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = tmp[0] - break + path = '{}images\{}.{}'.format(d.mountpoint, imagefile, ext) + if os.path.isfile(path) and wim_contains_image(path, imagename): + image['Path'] = path + image['Source'] = letter + if ext == 'swm': + image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) + break - # Check for network source (if necessary) + # Check for network source if not image: mount_windows_share() if not WINDOWS_SERVER['Mounted']: return None for ext in ['esd', 'wim', 'swm']: - filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) - filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) - if os.path.isfile(filename_ext): - if wim_contains_image(bin, filename_ext, windows_version['Image Name']): - image['Ext'] = ext - image['File'] = filename - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = None - break + path = r'\\{}\{}\images\{}.ext'.format( + WINDOWS_SERVER['IP'], WINDOWS_SERVER['Share'], imagefile, ext) + if os.path.isfile(path) and wim_contains_image(path, imagename): + image['Path'] = path + image['Source'] = None + if ext == 'swm': + image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) + break # Display image to be used (if any) and return - if any(image): - print_info('Using image: {File}.{Ext}'.format(**image)) + if image: + print_info('Using image: {}'.format(image['Path'])) return image else: - print_error('Failed to find Windows source image for {winver}'.format(winver=windows_version['Name'])) - abort_to_main_menu('Aborting Windows setup') + print_error('Failed to find Windows source image for {}'.format( + windows_version['Name'])) + raise GeneralAbort def format_gpt(disk=None, windows_family=None): """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" @@ -190,17 +190,15 @@ def select_windows_version(): elif selection == 'M': abort_to_main_menu() -def setup_windows(bin=None, windows_image=None, windows_version=None): - # Bail early - if bin is None: - raise Exception('bin path not specified.') - if windows_image is None: - raise Exception('Windows image not specified.') - if windows_version is None: - raise Exception('Windows version not specified.') - - # Apply image - cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) +def setup_windows(windows_image, windows_version): + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'apply', + windows_image['Path'], + windows_version['Image Name'], + 'W:\\'] + if 'Glob' in windows_image: + cmd.extend(windows_image['Glob']) run_program(cmd) def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T'): @@ -226,20 +224,15 @@ def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T') def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) -def wim_contains_image(bin=None, filename=None, imagename=None): - # Bail early - if bin is None: - raise Exception('bin not specified.') - if filename is None: - raise Exception('Filename not specified.') - if imagename is None: - raise Exception('Image Name not specified.') - - cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) +def wim_contains_image(filename, imagename): + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'info', + filename, + imagename] try: run_program(cmd) except subprocess.CalledProcessError: - print_error('Invalid image: {filename}'.format(filename=filename)) return False return True diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 69b551fe..4b7d873b 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -211,7 +211,7 @@ def menu_setup(): windows_version = select_windows_version() # Find Windows image - windows_image = find_windows_image(bin, windows_version) + windows_image = find_windows_image(windows_version) # Scan disks try_and_print(message='Assigning letters...', function=assign_volume_letters, other_results=other_results) @@ -237,7 +237,7 @@ def menu_setup(): print(' Installing: \t{winver}'.format(winver=windows_version['Name'])) print(' Boot Method:\t{_type}'.format( _type='UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')) - print(' Using Image:\t{File}.{Ext}'.format(**windows_image)) + print(' Using Image:\t{}'.format(windows_image['Path'])) print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk)) for par in dest_disk['Partitions']: print_warning(par['Display String']) @@ -275,7 +275,7 @@ def menu_setup(): # Apply Image print(' Applying Image... \t\t', end='', flush=True) try: - setup_windows(bin, windows_image, windows_version) + setup_windows(windows_image, windows_version) print_success('Complete.') except subprocess.CalledProcessError: print_error('Failed.') From deb7c76ffbb0e12d058aa95d4a14749113c88ecc Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 10:12:59 -0800 Subject: [PATCH 59/85] windows_setup.py done --- Scripts/functions/windows_setup.py | 81 +++++++++++++----------------- 1 file changed, 34 insertions(+), 47 deletions(-) diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index 008c649d..1830b4eb 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -86,25 +86,17 @@ def find_windows_image(windows_version): windows_version['Name'])) raise GeneralAbort -def format_gpt(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - # print_info('Drive will use a GPT (UEFI) layout.') +def format_gpt(disk, windows_family): + """Format disk for use as a Windows OS drive using the GPT layout.""" with open(DISKPART_SCRIPT, 'w') as script: # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('select disk {}\n'.format(disk['Number'])) script.write('clean\n') script.write('convert gpt\n') # System partition - script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives + # NOTE: ESP needs to be >= 260 for Advanced Format 4K drives + script.write('create partition efi size=500\n') script.write('format quick fs=fat32 label="System"\n') script.write('assign letter="S"\n') @@ -126,23 +118,14 @@ def format_gpt(disk=None, windows_family=None): script.write('gpt attributes=0x8000000000000001\n') # Run script - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) time.sleep(2) -def format_mbr(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - # print_info('Drive will use a MBR (legacy) layout.') +def format_mbr(disk, windows_family): + """Format disk for use as a Windows OS drive using the MBR layout.""" with open(DISKPART_SCRIPT, 'w') as script: # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('select disk {}\n'.format(disk['Number'])) script.write('clean\n') # System partition @@ -165,7 +148,7 @@ def format_mbr(disk=None, windows_family=None): script.write('set id=27\n') # Run script - run_program('diskpart /s {script}'.format(script=DISKPART_SCRIPT)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) time.sleep(2) def mount_windows_share(): @@ -177,7 +160,9 @@ def mount_windows_share(): mount_network_share(WINDOWS_SERVER) def select_windows_version(): - actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] # Menu loop selection = menu_select( @@ -188,7 +173,7 @@ def select_windows_version(): if selection.isnumeric(): return WINDOWS_VERSIONS[int(selection)-1] elif selection == 'M': - abort_to_main_menu() + raise GeneralAbort def setup_windows(windows_image, windows_version): cmd = [ @@ -201,28 +186,30 @@ def setup_windows(windows_image, windows_version): cmd.extend(windows_image['Glob']) run_program(cmd) -def setup_windows_re(windows_version=None, windows_letter='W', tools_letter='T'): - # Bail early - if windows_version is None: - raise Exception('Windows version not specified.') +def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): + win = r'{}:\Windows'.format(windows_letter) + winre = r'{}\System32\Recovery\WinRE.wim'.format(win) + dest = r'{}:\Recovery\WindowsRE'.format(tools_letter) - _win = '{win}:\\Windows'.format(win=windows_letter) - _winre = '{win}\\System32\\Recovery\\WinRE.wim'.format(win=_win) - _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) + # Copy WinRE.wim + os.makedirs(dest, exist_ok=True) + shutil.copy(winre, r'{}\WinRE.wim'.format(dest)) - if re.search(r'^(8|10)', windows_version['Family']): - # Copy WinRE.wim - os.makedirs(_dest, exist_ok=True) - shutil.copy(_winre, '{dest}\\WinRE.wim'.format(dest=_dest)) - - # Set location - run_program('{win}\\System32\\reagentc /setreimage /path {dest} /target {win}'.format(dest=_dest, win=_win)) - else: - # Only supported on Windows 8 and above - raise SetupError + # Set location + cmd = [ + r'{}\System32\ReAgentc.exe'.format(win), + '/setreimage', + '/path', dest, + '/target', win] + run_program(cmd) def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): - run_program('bcdboot {win}:\\Windows /s {sys}: /f {mode}'.format(win=windows_letter, sys=system_letter, mode=mode)) + cmd = [ + r'{}:\Windows\System32\bcdboot.exe'.format(windows_letter), + r'{}:\Windows'.format(windows_letter), + '/s', '{}:'.format(system_letter), + '/f', mode] + run_program(cmd) def wim_contains_image(filename, imagename): cmd = [ From 90c4189942ce73cbef5366b6f9dec970518d7b59 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 11:05:40 -0800 Subject: [PATCH 60/85] Updated winpe_menus.py & cleanup * Removed "Windows Family" logic * Win7 will now have recovery tools setup * Added format_disk() --- Scripts/functions/disk.py | 2 +- Scripts/functions/windows_setup.py | 71 ++++++------ Scripts/functions/winpe_menus.py | 179 +++++++++++++++-------------- 3 files changed, 125 insertions(+), 127 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 50277ca2..eb2bda4f 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -360,7 +360,7 @@ def select_disk(title='Which disk?', disks): if (selection.isnumeric()): return disk_options[int(selection)-1]['Disk'] elif (selection == 'M'): - abort_to_main_menu() + raise GeneralAbort if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index 1830b4eb..cbbe1525 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -7,46 +7,38 @@ DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) WINDOWS_VERSIONS = [ {'Name': 'Windows 7 Home Basic', 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEBASIC', - 'Family': '7'}, + 'Image Name': 'Windows 7 HOMEBASIC'}, {'Name': 'Windows 7 Home Premium', 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEPREMIUM', - 'Family': '7'}, + 'Image Name': 'Windows 7 HOMEPREMIUM'}, {'Name': 'Windows 7 Professional', 'Image File': 'Win7', - 'Image Name': 'Windows 7 PROFESSIONAL', - 'Family': '7'}, + 'Image Name': 'Windows 7 PROFESSIONAL'}, {'Name': 'Windows 7 Ultimate', 'Image File': 'Win7', - 'Image Name': 'Windows 7 ULTIMATE', - 'Family': '7'}, + 'Image Name': 'Windows 7 ULTIMATE'}, {'Name': 'Windows 8.1', 'Image File': 'Win8', - 'Image Name': 'Windows 8.1', - 'Family': '8', + 'Image Name': 'Windows 8.1', 'CRLF': True}, {'Name': 'Windows 8.1 Pro', 'Image File': 'Win8', - 'Image Name': 'Windows 8.1 Pro', - 'Family': '8'}, + 'Image Name': 'Windows 8.1 Pro'}, {'Name': 'Windows 10 Home', 'Image File': 'Win10', - 'Image Name': 'Windows 10 Home', - 'Family': '10', + 'Image Name': 'Windows 10 Home', 'CRLF': True}, {'Name': 'Windows 10 Pro', 'Image File': 'Win10', - 'Image Name': 'Windows 10 Pro', - 'Family': '10'}, + 'Image Name': 'Windows 10 Pro'}, ] def find_windows_image(windows_version): """Search for a Windows source image file, returns dict. - Searches on local drives and then the WINDOWS_SERVER share.""" + Searches on local disks and then the WINDOWS_SERVER share.""" image = {} imagefile = windows_version['Image File'] imagename = windows_version['Image Name'] @@ -86,8 +78,15 @@ def find_windows_image(windows_version): windows_version['Name'])) raise GeneralAbort -def format_gpt(disk, windows_family): - """Format disk for use as a Windows OS drive using the GPT layout.""" +def format_disk(disk, use_gpt): + """Format disk for use as a Windows OS disk.""" + if use_gpt: + format_gpt(disk) + else: + format_mbr(disk) + +def format_gpt(disk): + """Format disk for use as a Windows OS disk using the GPT layout.""" with open(DISKPART_SCRIPT, 'w') as script: # Partition table script.write('select disk {}\n'.format(disk['Number'])) @@ -95,7 +94,7 @@ def format_gpt(disk, windows_family): script.write('convert gpt\n') # System partition - # NOTE: ESP needs to be >= 260 for Advanced Format 4K drives + # NOTE: ESP needs to be >= 260 for Advanced Format 4K disks script.write('create partition efi size=500\n') script.write('format quick fs=fat32 label="System"\n') script.write('assign letter="S"\n') @@ -108,21 +107,20 @@ def format_gpt(disk, windows_family): script.write('format quick fs=ntfs label="Windows"\n') script.write('assign letter="W"\n') - # Recovery Tools partition (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery Tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') + # Recovery Tools partition + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery Tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') # Run script run_program(['diskpart', '/s', DISKPART_SCRIPT]) time.sleep(2) -def format_mbr(disk, windows_family): - """Format disk for use as a Windows OS drive using the MBR layout.""" +def format_mbr(disk): + """Format disk for use as a Windows OS disk using the MBR layout.""" with open(DISKPART_SCRIPT, 'w') as script: # Partition table script.write('select disk {}\n'.format(disk['Number'])) @@ -139,13 +137,12 @@ def format_mbr(disk, windows_family): script.write('format fs=ntfs quick label="Windows"\n') script.write('assign letter="W"\n') - # Recovery Tools partition (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery"\n') - script.write('assign letter="T"\n') - script.write('set id=27\n') + # Recovery Tools partition + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery"\n') + script.write('assign letter="T"\n') + script.write('set id=27\n') # Run script run_program(['diskpart', '/s', DISKPART_SCRIPT]) diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 4b7d873b..c6ba4e8c 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -5,7 +5,7 @@ from functions.disk import * from functions.windows_setup import * # STATIC VARIABLES -FAST_COPY_ARGS = [ +FAST_COPY_PE_ARGS = [ '/cmd=noexist_only', '/utf8', '/skip_empty_dir', @@ -20,7 +20,7 @@ PE_TOOLS = { }, 'FastCopy': { 'Path': r'FastCopy\FastCopy.exe', - 'Args': FAST_COPY_ARGS, + 'Args': FAST_COPY_PE_ARGS, }, 'HWiNFO': { 'Path': r'HWiNFO\HWiNFO.exe', @@ -51,7 +51,7 @@ PE_TOOLS = { } def menu_backup(): - """Take backup images of partition(s) in the WIM format and save them to a backup share""" + """Take backup images of partition(s) in the WIM format.""" errors = False other_results = { 'Error': { @@ -65,7 +65,7 @@ def menu_backup(): set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) # Set ticket Number - os.system('cls') + clear_screen() ticket_number = get_ticket_number() # Mount backup shares @@ -75,8 +75,14 @@ def menu_backup(): destination = select_backup_destination() # Scan disks - try_and_print(message='Assigning letters...', function=assign_volume_letters, other_results=other_results) - result = try_and_print(message='Getting drive info...', function=scan_disks, other_results=other_results) + try_and_print( + message = 'Assigning letters...', + function = assign_volume_letters, + other_results = other_results) + result = try_and_print( + message = 'Getting disk info...', + function = scan_disks, + other_results = other_results) if result['CS']: disks = result['Out'] else: @@ -84,7 +90,7 @@ def menu_backup(): raise GenericAbort # Select disk to backup - disk = select_disk('For which drive are we creating backups?', disks) + disk = select_disk('For which disk are we creating backups?', disks) if not disk: raise GenericAbort @@ -92,9 +98,8 @@ def menu_backup(): prep_disk_for_backup(destination, disk, ticket_number) # Display details for backup task - os.system('cls') + clear_screen() print_info('Create Backup - Details:\n') - # def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): show_info(message='Ticket:', info=ticket_number) show_info( message = 'Source:', @@ -115,9 +120,12 @@ def menu_backup(): # Backup partition(s) print_info('\n\nStarting task.\n') for par in disk['Partitions']: - message = 'Partition {} Backup...'.format(par['Number']) - result = try_and_print(message=message, function=backup_partition, - other_results=other_results, disk=disk, partition=par) + result = try_and_print( + message = 'Partition {} Backup...'.format(par['Number']), + function = backup_partition, + other_results = other_results, + disk = disk, + partition = par) if not result['CS']: errors = True par['Error'] = result['Error'] @@ -128,9 +136,11 @@ def menu_backup(): for par in disk['Partitions']: if par['Number'] in disk['Bad Partitions']: continue # Skip verification - message = 'Partition {} Image...'.format(par['Number']) - result = try_and_print(message=message, function=verify_wim_backup, - other_results=other_results, partition=par) + result = try_and_print( + message = 'Partition {} Image...'.format(par['Number']), + function = verify_wim_backup, + other_results = other_results, + partition = par) if not result['CS']: errors = True par['Error'] = result['Error'] @@ -199,12 +209,12 @@ def menu_root(): exit_script() def menu_setup(): - """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" + """Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" errors = False set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) # Set ticket ID - os.system('cls') + clear_screen() ticket_number = get_ticket_number() # Select the version of Windows to apply @@ -214,16 +224,22 @@ def menu_setup(): windows_image = find_windows_image(windows_version) # Scan disks - try_and_print(message='Assigning letters...', function=assign_volume_letters, other_results=other_results) - result = try_and_print(message='Getting drive info...', function=scan_disks, other_results=other_results) + try_and_print( + message = 'Assigning letters...', + function = assign_volume_letters, + other_results = other_results) + result = try_and_print( + message = 'Getting disk info...', + function = scan_disks, + other_results = other_results) if result['CS']: disks = result['Out'] else: print_error('ERROR: No disks found.') raise GenericAbort - # Select drive to use as the OS drive - dest_disk = select_disk('To which drive are we installing Windows?', disks) + # Select disk to use as the OS disk + dest_disk = select_disk('To which disk are we installing Windows?', disks) if not disk: raise GenericAbort @@ -231,92 +247,77 @@ def menu_setup(): prep_disk_for_formatting(dest_disk) # Display details for setup task - os.system('cls') - print('Setup Windows - Details:\n') - print(' Ticket: \t{ticket_number}'.format(ticket_number=ticket_number)) - print(' Installing: \t{winver}'.format(winver=windows_version['Name'])) - print(' Boot Method:\t{_type}'.format( - _type='UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')) - print(' Using Image:\t{}'.format(windows_image['Path'])) - print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk)) + clear_screen() + print_info('Setup Windows - Details:\n') + show_info(message='Ticket:', info=ticket_number) + show_info(message='Installing:', info=windows_version['Name']) + show_info( + message = 'Boot Method:', + info = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') + show_info(message='Using Image:', info=windows_version['Path']) + print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format( + **dest_disk)) for par in dest_disk['Partitions']: print_warning(par['Display String']) print_warning(dest_disk['Format Warnings']) if (not ask('Is this correct?')): - abort_to_main_menu('Aborting Windows setup') + raise GeneralAbort - # Safety check - print('\nSAFETY CHECK') - print_warning('All data will be DELETED from the drive and partition(s) listed above.') - print_warning('This is irreversible and will lead to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) + # Safety check + print_standard('\nSAFETY CHECK') + print_warning('All data will be DELETED from the ' + 'disk & partition(s) listed above.') + print_warning('This is irreversible and will lead ' + 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) if (not ask('Asking again to confirm, is this correct?')): - abort_to_main_menu('Aborting Windows setup') + raise GeneralAbort - # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) + # Remove volume letters so S, T, & W can be used below remove_volume_letters(keep=windows_image['Source']) new_letter = reassign_volume_letter(letter=windows_image['Source']) if new_letter: windows_image['Source'] = new_letter - # Format and partition drive - print('\n Formatting Drive... \t\t', end='', flush=True) - try: - if (dest_disk['Use GPT']): - format_gpt(dest_disk, windows_version['Family']) - else: - format_mbr(dest_disk, windows_version['Family']) - print_success('Complete.') - except: - # We need to crash as the drive is in an unknown state - print_error('Failed.') - raise + # Format and partition disk + result = try_and_print( + message = 'Formatting disk...', + function = format_disk, + other_results = other_results, + disk = dest_disk, + use_gpt = dest_disk['Use GPT']) + if not result['CS']: + # We need to crash as the disk is in an unknown state + print_error('ERROR: Failed to format disk.') + raise GenericAbort # Apply Image - print(' Applying Image... \t\t', end='', flush=True) - try: - setup_windows(windows_image, windows_version) - print_success('Complete.') - except subprocess.CalledProcessError: - print_error('Failed.') - errors = True - except: - # We need to crash as the OS is in an unknown state - print_error('Failed.') - raise + result = try_and_print( + message = 'Applying image...', + function = setup_windows, + other_results = other_results, + windows_image = windows_image, + windows_version = windows_version) + if not result['CS']: + # We need to crash as the disk is in an unknown state + print_error('ERROR: Failed to apply image.') + raise GenericAbort # Create Boot files - print(' Update Boot Partition...\t\t', end='', flush=True) - try: - update_boot_partition() - print_success('Complete.') - except subprocess.CalledProcessError: - # Don't need to crash as this is (potentially) recoverable - print_error('Failed.') - errors = True - except: - print_error('Failed.') - raise + try_and_print( + message = 'Updating boot files...', + function = update_boot_partition, + other_results = other_results) # Setup WinRE - print(' Update Recovery Tools...\t\t', end='', flush=True) - try: - setup_windows_re(windows_version) - print_success('Complete.') - except SetupError: - print('Skipped.') - except: - # Don't need to crash as this is (potentially) recoverable - print_error('Failed.') - errors = True + try_and_print( + message = 'Updating recovery tools...', + function = setup_windows_re, + other_results = other_results, + windows_version = windows_version) # Print summary - if errors: - print_warning('\nErrors were encountered during setup.') - time.sleep(30) - else: - print_success('\nNo errors were encountered during setup.') - time.sleep(5) + print_standard('\nDone.') pause('\nPress Enter to return to main menu... ') def menu_tools(): @@ -359,9 +360,9 @@ def select_minidump_path(): # Remove RAMDisk letter if 'X' in tmp: tmp.remove('X') - for drive in tmp: - if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): - dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) + for disk in tmp: + if os.path.exists('{}:\\Windows\\MiniDump'.format(disk)): + dumps.append({'Name': '{}:\\Windows\\MiniDump'.format(disk)}) # Check results before showing menu if len(dumps) == 0: From 1b00c1c9a38f94c6cd089b8fb919d68ab6d57fc3 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 11:36:35 -0800 Subject: [PATCH 61/85] New folder layout * Main ideas * Match WizardKit layout * Keep original folders clean * Build work is now done in $Root\BUILD * $Temp is now set to $Root\BUILD\Temp * New iso files are put in $Root\OUT_PE --- .bin/Scripts/build_pe.ps1 | 125 +- {Scripts => .bin/Scripts}/functions/backup.py | 306 +- {Scripts => .bin/Scripts}/functions/common.py | 1402 ++++----- {Scripts => .bin/Scripts}/functions/data.py | 1214 ++++---- {Scripts => .bin/Scripts}/functions/disk.py | 732 ++--- .../Scripts}/functions/partition_uids.py | 650 ++-- .../Scripts}/functions/windows_setup.py | 450 +-- .../Scripts}/functions/winpe_menus.py | 760 ++--- {Scripts => .bin/Scripts}/settings/main.py | 136 +- {Scripts => .bin/Scripts}/settings/tools.py | 110 +- {Scripts => .bin/Scripts}/winpe_root_menu.py | 46 +- .gitignore | 11 +- {System32 => .pe_items/System32}/Winpeshl.ini | 12 +- .pe_items/System32/menu.cmd | 2 + {WK => .pe_items}/_include/CPU-Z/cpuz.ini | 40 +- {WK => .pe_items}/_include/ConEmu/ConEmu.xml | 1530 ++++----- {WK => .pe_items}/_include/HWiNFO/HWiNFO.INI | 1342 ++++---- .../_include/NotepadPlusPlus/config.xml | 112 +- .../_include/NotepadPlusPlus/npp.cmd | 4 +- .../NotepadPlusPlus/stylers.model.xml | 2742 ++++++++--------- {WK => .pe_items}/_include/Q-Dir/Q-Dir.ini | 136 +- System32/menu.cmd | 2 - 22 files changed, 5931 insertions(+), 5933 deletions(-) rename {Scripts => .bin/Scripts}/functions/backup.py (97%) rename {Scripts => .bin/Scripts}/functions/common.py (97%) rename {Scripts => .bin/Scripts}/functions/data.py (97%) rename {Scripts => .bin/Scripts}/functions/disk.py (97%) rename {Scripts => .bin/Scripts}/functions/partition_uids.py (98%) rename {Scripts => .bin/Scripts}/functions/windows_setup.py (97%) rename {Scripts => .bin/Scripts}/functions/winpe_menus.py (96%) rename {Scripts => .bin/Scripts}/settings/main.py (97%) rename {Scripts => .bin/Scripts}/settings/tools.py (96%) rename {Scripts => .bin/Scripts}/winpe_root_menu.py (95%) rename {System32 => .pe_items/System32}/Winpeshl.ini (97%) create mode 100644 .pe_items/System32/menu.cmd rename {WK => .pe_items}/_include/CPU-Z/cpuz.ini (92%) rename {WK => .pe_items}/_include/ConEmu/ConEmu.xml (98%) rename {WK => .pe_items}/_include/HWiNFO/HWiNFO.INI (95%) rename {WK => .pe_items}/_include/NotepadPlusPlus/config.xml (98%) rename {WK => .pe_items}/_include/NotepadPlusPlus/npp.cmd (98%) rename {WK => .pe_items}/_include/NotepadPlusPlus/stylers.model.xml (99%) rename {WK => .pe_items}/_include/Q-Dir/Q-Dir.ini (99%) delete mode 100644 System32/menu.cmd diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index bb03acb1..26d8ace4 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -10,11 +10,11 @@ $Host.UI.RawUI.WindowTitle = "Wizard Kit: Windows PE Build Tool" $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName $Root = (Get-Item $Bin -Force).Parent.FullName -$Temp = "$Bin\tmp" +$Build = "$Root\BUILD" +$Temp = "$Build\Temp" $Date = Get-Date -UFormat "%Y-%m-%d" $Host.UI.RawUI.BackgroundColor = "Black" $Host.UI.RawUI.ForegroundColor = "White" -# $ProgressPreference = "silentlyContinue" $HostSystem32 = "{0}\System32" -f $Env:SystemRoot $DISM = "{0}\DISM.exe" -f $Env:DISMRoot @@ -40,8 +40,8 @@ function Abort { } function MakeClean { $Folders = @( - "$Root\Mount", - "$Root\PEFiles") + "$Build\Mount", + "$Build\PEFiles") $Clean = $false foreach ($f in $Folders) { if (Test-Path $f) { @@ -185,17 +185,17 @@ if ($MyInvocation.InvocationName -ne ".") { Start-Process -FilePath "$HostSystem32\msiexec.exe" -ArgumentList $ArgumentList -Wait $SevenZip = "$Temp\7zi\Files\7-Zip\7z.exe" $ArgumentList = @( - "e", "$Temp\7z-extra.7z", "-o$Root\WK\amd64\7-Zip", + "e", "$Temp\7z-extra.7z", "-o$Build\bin\amd64\7-Zip", "-aoa", "-bso0", "-bse0", "-bsp0", "x64\7za.exe", "*.txt") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "e", "$Temp\7z-extra.7z", "-o$Root\WK\x86\7-Zip", + "e", "$Temp\7z-extra.7z", "-o$Build\bin\x86\7-Zip", "-aoa", "-bso0", "-bse0", "-bsp0", "7za.exe", "*.txt") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\7z*" -Recurse - $SevenZip = "$Root\WK\x86\7-Zip\7za.exe" + $SevenZip = "$Build\bin\x86\7-Zip\7za.exe" } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" @@ -205,11 +205,11 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: BlueScreenView" try { $ArgumentList = @( - "x", "$Temp\bluescreenview64.zip", "-o$Root\WK\amd64\BlueScreenView", + "x", "$Temp\bluescreenview64.zip", "-o$Build\bin\amd64\BlueScreenView", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\bluescreenview32.zip", "-o$Root\WK\x86\BlueScreenView", + "x", "$Temp\bluescreenview32.zip", "-o$Build\bin\x86\BlueScreenView", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\bluescreenview*" @@ -222,19 +222,19 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: ConEmu" try { $ArgumentList = @( - "x", "$Temp\ConEmuPack.7z", "-o$Root\WK\amd64\ConEmu", + "x", "$Temp\ConEmuPack.7z", "-o$Build\bin\amd64\ConEmu", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.exe" - Remove-Item "$Root\WK\amd64\ConEmu\ConEmu.map" - Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.exe" "$Root\WK\amd64\ConEmu\ConEmu.exe" -Force - Move-Item "$Root\WK\amd64\ConEmu\ConEmu64.map" "$Root\WK\amd64\ConEmu\ConEmu.map" -Force + Remove-Item "$Build\bin\amd64\ConEmu\ConEmu.exe" + Remove-Item "$Build\bin\amd64\ConEmu\ConEmu.map" + Move-Item "$Build\bin\amd64\ConEmu\ConEmu64.exe" "$Build\bin\amd64\ConEmu\ConEmu.exe" -Force + Move-Item "$Build\bin\amd64\ConEmu\ConEmu64.map" "$Build\bin\amd64\ConEmu\ConEmu.map" -Force $ArgumentList = @( - "x", "$Temp\ConEmuPack.7z", "-o$Root\WK\x86\ConEmu", + "x", "$Temp\ConEmuPack.7z", "-o$Build\bin\x86\ConEmu", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.exe" - Remove-Item "$Root\WK\x86\ConEmu\ConEmu64.map" + Remove-Item "$Build\bin\x86\ConEmu\ConEmu64.exe" + Remove-Item "$Build\bin\x86\ConEmu\ConEmu64.map" Remove-Item "$Temp\ConEmuPack*" } catch { @@ -245,12 +245,12 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: FastCopy" try { $ArgumentList = @( - "x", "$Temp\fastcopy64.zip", "-o$Root\WK\amd64\FastCopy", + "x", "$Temp\fastcopy64.zip", "-o$Build\bin\amd64\FastCopy", "-aoa", "-bso0", "-bse0", "-bsp0", "-x!setup.exe", "-x!*.dll") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "e", "$Temp\fastcopy32.zip", "-o$Root\WK\x86\FastCopy", + "e", "$Temp\fastcopy32.zip", "-o$Build\bin\x86\FastCopy", "-aoa", "-bso0", "-bse0", "-bsp0", "-x!setup.exe", "-x!*.dll") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -264,12 +264,12 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Killer Network Driver" try { $ArgumentList = @( - "e", "$Temp\killerinf.zip", "-o$Root\Drivers\amd64\Killer", + "e", "$Temp\killerinf.zip", "-o$Build\Drivers\amd64\Killer", "-aoa", "-bso0", "-bse0", "-bsp0", "Production\Windows10-x64\Eth\*") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "e", "$Temp\killerinf.zip", "-o$Root\Drivers\x86\Killer", + "e", "$Temp\killerinf.zip", "-o$Build\Drivers\x86\Killer", "-aoa", "-bso0", "-bse0", "-bsp0", "Production\Windows10-x86\Eth\*") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -283,16 +283,16 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: HWiNFO" try { $ArgumentList = @( - "e", "$Temp\hwinfo64.zip", "-o$Root\WK\amd64\HWiNFO", + "e", "$Temp\hwinfo64.zip", "-o$Build\bin\amd64\HWiNFO", "-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO64.exe") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "e", "$Temp\hwinfo32.zip", "-o$Root\WK\x86\HWiNFO", + "e", "$Temp\hwinfo32.zip", "-o$Build\bin\x86\HWiNFO", "-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO32.exe") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\hwinfo*" - Move-Item "$Root\WK\amd64\HWiNFO\HWiNFO64.exe" "$Root\WK\amd64\HWiNFO\HWiNFO.exe" -Force - Move-Item "$Root\WK\x86\HWiNFO\HWiNFO32.exe" "$Root\WK\x86\HWiNFO\HWiNFO.exe" -Force + Move-Item "$Build\bin\amd64\HWiNFO\HWiNFO64.exe" "$Build\bin\amd64\HWiNFO\HWiNFO.exe" -Force + Move-Item "$Build\bin\x86\HWiNFO\HWiNFO32.exe" "$Build\bin\x86\HWiNFO\HWiNFO.exe" -Force } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" @@ -302,16 +302,16 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Notepad++" try { $ArgumentList = @( - "x", "$Temp\npp_amd64.7z", "-o$Root\WK\amd64\NotepadPlusPlus", + "x", "$Temp\npp_amd64.7z", "-o$Build\bin\amd64\NotepadPlusPlus", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\npp_x86.7z", "-o$Root\WK\x86\NotepadPlusPlus", + "x", "$Temp\npp_x86.7z", "-o$Build\bin\x86\NotepadPlusPlus", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\npp*" - Move-Item "$Root\WK\amd64\NotepadPlusPlus\notepad++.exe" "$Root\WK\amd64\NotepadPlusPlus\notepadplusplus.exe" -Force - Move-Item "$Root\WK\x86\NotepadPlusPlus\notepad++.exe" "$Root\WK\x86\NotepadPlusPlus\notepadplusplus.exe" -Force + Move-Item "$Build\bin\amd64\NotepadPlusPlus\notepad++.exe" "$Build\bin\amd64\NotepadPlusPlus\notepadplusplus.exe" -Force + Move-Item "$Build\bin\x86\NotepadPlusPlus\notepad++.exe" "$Build\bin\x86\NotepadPlusPlus\notepadplusplus.exe" -Force } catch { Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red" @@ -321,13 +321,13 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: NT Password Editor" try { $ArgumentList = @( - "e", "$Temp\ntpwed.zip", ('-o"{0}\WK\amd64\NT Password Editor"' -f $Root), + "e", "$Temp\ntpwed.zip", ('-o"{0}\bin\amd64\NT Password Editor"' -f $Build), "-aoa", "-bso0", "-bse0", "-bsp0", "ntpwedit64.exe", "*.txt") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Move-Item "$Root\WK\amd64\NT Password Editor\ntpwedit64.exe" "$Root\WK\amd64\NT Password Editor\ntpwedit.exe" -Force + Move-Item "$Build\bin\amd64\NT Password Editor\ntpwedit64.exe" "$Build\bin\amd64\NT Password Editor\ntpwedit.exe" -Force $ArgumentList = @( - "e", "$Temp\ntpwed.zip", ('-o"{0}\WK\x86\NT Password Editor"' -f $Root), + "e", "$Temp\ntpwed.zip", ('-o"{0}\bin\x86\NT Password Editor"' -f $Build), "-aoa", "-bso0", "-bse0", "-bsp0", "ntpwedit.exe", "*.txt") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -341,21 +341,21 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: PhotoRec / TestDisk" try { $ArgumentList = @( - "x", "$Temp\testdisk64.zip", "-o$Root\WK\amd64\TestDisk", + "x", "$Temp\testdisk64.zip", "-o$Build\bin\amd64\TestDisk", "-aoa", "-bso0", "-bse0", "-bsp0") # Remove destination since Move-Item -Force can't handle this recursive merge - Remove-Item "$Root\WK\amd64\TestDisk" -Recurse -Force + Remove-Item "$Build\bin\amd64\TestDisk" -Recurse -Force 2>&1 | Out-Null Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Move-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\amd64\TestDisk" -Force - Remove-Item "$Root\WK\amd64\TestDisk\testdisk-7.1-WIP" -Recurse -Force + Move-Item "$Build\bin\amd64\TestDisk\testdisk-7.1-WIP\*" "$Build\bin\amd64\TestDisk" -Force + Remove-Item "$Build\bin\amd64\TestDisk\testdisk-7.1-WIP" -Recurse -Force $ArgumentList = @( - "x", "$Temp\testdisk32.zip", "-o$Root\WK\x86\TestDisk", + "x", "$Temp\testdisk32.zip", "-o$Build\bin\x86\TestDisk", "-aoa", "-bso0", "-bse0", "-bsp0") # Remove destination since Move-Item -Force can't handle this recursive merge - Remove-Item "$Root\WK\x86\TestDisk" -Recurse -Force + Remove-Item "$Build\bin\x86\TestDisk" -Recurse -Force 2>&1 | Out-Null Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait - Move-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP\*" "$Root\WK\x86\TestDisk" -Force - Remove-Item "$Root\WK\x86\TestDisk\testdisk-7.1-WIP" -Recurse -Force + Move-Item "$Build\bin\x86\TestDisk\testdisk-7.1-WIP\*" "$Build\bin\x86\TestDisk" -Force + Remove-Item "$Build\bin\x86\TestDisk\testdisk-7.1-WIP" -Recurse -Force Remove-Item "$Temp\testdisk*" } catch { @@ -366,11 +366,11 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Prime95" try { $ArgumentList = @( - "x", "$Temp\prime95_64.zip", "-o$Root\WK\amd64\Prime95", + "x", "$Temp\prime95_64.zip", "-o$Build\bin\amd64\Prime95", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\prime95_32.zip", "-o$Root\WK\x86\Prime95", + "x", "$Temp\prime95_32.zip", "-o$Build\bin\x86\Prime95", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\prime95*" @@ -382,11 +382,11 @@ if ($MyInvocation.InvocationName -ne ".") { # ProduKey try { $ArgumentList = @( - "x", "$Temp\produkey64.zip", "-o$Root\WK\amd64\ProduKey", + "x", "$Temp\produkey64.zip", "-o$Build\bin\amd64\ProduKey", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\produkey32.zip", "-o$Root\WK\x86\ProduKey", + "x", "$Temp\produkey32.zip", "-o$Build\bin\x86\ProduKey", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\produkey*" @@ -399,11 +399,11 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Python (x64)" try { $ArgumentList = @( - "x", "$Temp\python64.zip", "-o$Root\WK\amd64\python", + "x", "$Temp\python64.zip", "-o$Build\bin\amd64\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\psutil64.whl", "-o$Root\WK\amd64\python", + "x", "$Temp\psutil64.whl", "-o$Build\bin\amd64\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -416,11 +416,11 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Python (x32)" try { $ArgumentList = @( - "x", "$Temp\python32.zip", "-o$Root\WK\x86\python", + "x", "$Temp\python32.zip", "-o$Build\bin\x86\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\psutil32.whl", "-o$Root\WK\x86\python", + "x", "$Temp\psutil32.whl", "-o$Build\bin\x86\python", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -435,11 +435,11 @@ if ($MyInvocation.InvocationName -ne ".") { Write-Host "Extracting: Q-Dir" try { $ArgumentList = @( - "x", "$Temp\qdir64.zip", "-o$Root\WK\amd64", + "x", "$Temp\qdir64.zip", "-o$Build\bin\amd64", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\qdir32.zip", "-o$Root\WK\x86", + "x", "$Temp\qdir32.zip", "-o$Build\bin\x86", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\qdir*" @@ -451,11 +451,11 @@ if ($MyInvocation.InvocationName -ne ".") { # wimlib-imagex try { $ArgumentList = @( - "x", "$Temp\wimlib64.zip", "-o$Root\WK\amd64\wimlib", + "x", "$Temp\wimlib64.zip", "-o$Build\bin\amd64\wimlib", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @( - "x", "$Temp\wimlib32.zip", "-o$Root\WK\x86\wimlib", + "x", "$Temp\wimlib32.zip", "-o$Build\bin\x86\wimlib", "-aoa", "-bso0", "-bse0", "-bsp0") Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait Remove-Item "$Temp\wimlib*" @@ -467,9 +467,9 @@ if ($MyInvocation.InvocationName -ne ".") { ## Build ## foreach ($Arch in @("amd64", "x86")) { - $Drivers = "$Root\Drivers\$Arch" - $Mount = "$Root\Mount" - $PEFiles = "$Root\PEFiles\$Arch" + $Drivers = "$Build\Drivers\$Arch" + $Mount = "$Build\Mount" + $PEFiles = "$Build\PEFiles\$Arch" # Copy WinPE files Write-Host "Copying files..." @@ -520,8 +520,8 @@ if ($MyInvocation.InvocationName -ne ".") { # Add tools Write-Host "Copying tools..." - Copy-Item -Path "$Root\WK\$Arch" -Destination "$Mount\.bin" -Recurse -Force - Copy-Item -Path "$Root\WK\_include\*" -Destination "$Mount\.bin" -Recurse -Force + Copy-Item -Path "$Build\bin\$Arch" -Destination "$Mount\.bin" -Recurse -Force + Copy-Item -Path "$Root\.pe_items\_include\*" -Destination "$Mount\.bin" -Recurse -Force if ($Arch -eq "amd64") { $DestIni = "$Mount\.bin\HWiNFO\HWiNFO64.INI" } else { @@ -529,11 +529,11 @@ if ($MyInvocation.InvocationName -ne ".") { } Move-Item -Path "$Mount\.bin\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\.bin\ConEmu\ConEmu.jpg" -Recurse -Force - Copy-Item -Path "$Root\Scripts" -Destination "$Mount\.bin\Scripts" -Recurse -Force + Copy-Item -Path "$Bin\Scripts" -Destination "$Mount\.bin\Scripts" -Recurse -Force # Add System32 items $HostSystem32 = "{0}\System32" -f $Env:SystemRoot - Copy-Item -Path "$Root\System32\*" -Destination "$Mount\Windows\System32" -Recurse -Force + Copy-Item -Path "$Root\.pe_items\System32\*" -Destination "$Mount\Windows\System32" -Recurse -Force $ArgumentList = @("/f", "$Mount\Windows\System32\winpe.jpg", "/a") Start-Process -FilePath "$HostSystem32\takeown.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @("$Mount\Windows\System32\winpe.jpg", "/grant", "Administrators:F") @@ -583,10 +583,15 @@ if ($MyInvocation.InvocationName -ne ".") { Dismount-WindowsImage -Path $Mount -Save # Create ISO - $ArgumentList = @("/iso", $PEFiles, "$Root\wk-winpe-$Date-$Arch.iso") + New-Item -Type Directory "$Root\OUT_PE" 2>&1 | Out-Null + $ArgumentList = @("/iso", $PEFiles, "$Root\OUT_PE\wk-winpe-$Date-$Arch.iso") $Cmd = "{0}\MakeWinPEMedia.cmd" -f $Env:WinPERoot Start-Process -FilePath $Cmd -ArgumentList $ArgumentList -NoNewWindow -Wait } + + ## Cleanup ## + Remove-Item -Path "$Build\Mount" -Recurse -Force + Remove-Item -Path "$Build\PEFiles" -Recurse -Force ## Done ## Pop-Location diff --git a/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py similarity index 97% rename from Scripts/functions/backup.py rename to .bin/Scripts/functions/backup.py index a562f4f5..c916a0e3 100644 --- a/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -1,153 +1,153 @@ -# Wizard Kit PE: Functions - Backup - -from functions.disk import * - -# Regex -REGEX_BAD_PATH_NAMES = re.compile( - r'([<>:"/\\\|\?\*]' - r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' - r'|^\s+' - r'|[\s\.]+$', - re.IGNORECASE) - -def backup_partition(disk, partition): - if par['Image Exists'] or par['Number'] in disk['Bad Partitions']: - raise GenericAbort - - cmd = [ - global_vars['Tools']['wimlib-imagex'], - 'capture' - '{}:\\'.format(par['Letter']), - par['Image Path'], - par['Image Name'], # Image name - par['Image Name'], # Image description - ' --compress=none', - ] - dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE) - os.makedirs(dest_dir, exist_ok=True) - run_program(cmd) - -def fix_path(path): - return REGEX_BAD_PATH_NAMES.sub('_', path) - -def prep_disk_for_backup(destination, disk, ticket_number): - disk['Clobber Risk'] = [] - width = len(str(len(disk['Partitions']))) - - # Get partition totals - disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] - if is_bad_partition(partition)] - num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) - disk['Valid Partitions'] = num_valid_partitions - if disk['Valid Partitions'] <= 0: - print_error('ERROR: No partitions can be backed up for this disk') - raise GenericAbort - - # Prep partitions - for par in disk['Partitions']: - display = 'Partition {num:>{width}}:\t{size} {fs}'.format( - num = par['Number'], - width = width, - size = par['Size'], - fs = par['FileSystem']) - - if par['Number'] in disk['Bad Partitions']: - # Set display string using partition description & OS type - display = ' * {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( - display = display, - q = '"' if par['Name'] != '' else '', - name = par['Name'], - desc = par['Description'], - os = par['OS']) - display = '{YELLOW}{display}{CLEAR}'.format( - display=display, **COLORS) - else: - # Update info for WIM capturing - par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' - if 'IP' in destination: - par['Image Path'] = r'\\{}\{}\{}'.format( - destination['IP'], destination['Share'], ticket_number) - else: - par['Image Path'] = r'{}:\{}'.format( - ticket_number, destination['Letter']) - par['Image Path'] += r'\{}_{}.wim'.format( - par['Number'], par['Image Name']) - par['Image Path'] = fix_path(par['Image Path']) - - # Check for existing backups - par['Image Exists'] = os.path.exists(par['Image Path']) - if par['Image Exists']: - disk['Clobber Risk'].append(par['Number']) - display = '{} + {}'.format(COLORS['BLUE'], display) - else: - display = '{} {}'.format(COLORS['CLEAR'], display) - - # Append rest of Display String for valid/clobber partitions - display += ' (Used: {used})\t{q}{name}{q}{CLEAR}'.format( - used = par['Used Space'], - q = '"' if par['Name'] != '' else '', - name = par['Name'], - **COLORS) - # For all partitions - par['Display String'] = display - - # Set description for bad partitions - warnings = '\n' - if disk['Bad Partitions']: - warnings += '{} * Unsupported filesystem{}\n'.format( - COLORS['YELLOW'], COLORS['CLEAR']) - if disk['Clobber Risk']: - warnings += '{} + Backup exists on {}{}\n'.format( - COLORS['BLUE'], destination['Name'], COLORS['CLEAR']) - if disk['Bad Partitions'] or disk['Clobber Risk']: - warnings += '\n{}Marked partition(s) will NOT be backed up.{}\n'.format( - COLORS['YELLOW'], COLORS['CLEAR']) - disk['Backup Warnings'] = warnings - -def select_backup_destination(auto_select=True): - # Build menu - destinations = [s for s in BACKUP_SERVERS if s['Mounted']] - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Size check - for dest in destinations: - if 'IP' in dest: - dest['Usage'] = shutil.disk_usage(r'\\{IP}\{Share}'.format(**dest)) - else: - dest['Usage'] = shutil.disk_usage('{}:\\'.format(dest['Letter'])) - dest['Free Space'] = human_readable_size(dest['Usage'].free) - dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) - - # Bail - if not destinations: - print_warning('No backup destinations found.') - raise GenericAbort - - # Skip menu? - if len(destinations) == 1 and auto_select: - return destinations[0] - - selection = menu_select( - title = 'Where are we backing up to?', - main_entries = destinations, - action_entries = actions) - if selection == 'M': - raise GenericAbort - else: - return destinations[int(selection)-1] - -def verify_wim_backup(partition): - if not os.path.exists(partition['Image Path']): - raise PathNotFoundError - cmd = [ - global_vars['Tools']['wimlib-imagex'], - 'verify', - partition['Image Path'], - ' --nocheck', - ] - run_program(cmd) - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - Backup + +from functions.disk import * + +# Regex +REGEX_BAD_PATH_NAMES = re.compile( + r'([<>:"/\\\|\?\*]' + r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' + r'|^\s+' + r'|[\s\.]+$', + re.IGNORECASE) + +def backup_partition(disk, partition): + if par['Image Exists'] or par['Number'] in disk['Bad Partitions']: + raise GenericAbort + + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'capture' + '{}:\\'.format(par['Letter']), + par['Image Path'], + par['Image Name'], # Image name + par['Image Name'], # Image description + ' --compress=none', + ] + dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE) + os.makedirs(dest_dir, exist_ok=True) + run_program(cmd) + +def fix_path(path): + return REGEX_BAD_PATH_NAMES.sub('_', path) + +def prep_disk_for_backup(destination, disk, ticket_number): + disk['Clobber Risk'] = [] + width = len(str(len(disk['Partitions']))) + + # Get partition totals + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] + if is_bad_partition(partition)] + num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) + disk['Valid Partitions'] = num_valid_partitions + if disk['Valid Partitions'] <= 0: + print_error('ERROR: No partitions can be backed up for this disk') + raise GenericAbort + + # Prep partitions + for par in disk['Partitions']: + display = 'Partition {num:>{width}}:\t{size} {fs}'.format( + num = par['Number'], + width = width, + size = par['Size'], + fs = par['FileSystem']) + + if par['Number'] in disk['Bad Partitions']: + # Set display string using partition description & OS type + display = ' * {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( + display = display, + q = '"' if par['Name'] != '' else '', + name = par['Name'], + desc = par['Description'], + os = par['OS']) + display = '{YELLOW}{display}{CLEAR}'.format( + display=display, **COLORS) + else: + # Update info for WIM capturing + par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' + if 'IP' in destination: + par['Image Path'] = r'\\{}\{}\{}'.format( + destination['IP'], destination['Share'], ticket_number) + else: + par['Image Path'] = r'{}:\{}'.format( + ticket_number, destination['Letter']) + par['Image Path'] += r'\{}_{}.wim'.format( + par['Number'], par['Image Name']) + par['Image Path'] = fix_path(par['Image Path']) + + # Check for existing backups + par['Image Exists'] = os.path.exists(par['Image Path']) + if par['Image Exists']: + disk['Clobber Risk'].append(par['Number']) + display = '{} + {}'.format(COLORS['BLUE'], display) + else: + display = '{} {}'.format(COLORS['CLEAR'], display) + + # Append rest of Display String for valid/clobber partitions + display += ' (Used: {used})\t{q}{name}{q}{CLEAR}'.format( + used = par['Used Space'], + q = '"' if par['Name'] != '' else '', + name = par['Name'], + **COLORS) + # For all partitions + par['Display String'] = display + + # Set description for bad partitions + warnings = '\n' + if disk['Bad Partitions']: + warnings += '{} * Unsupported filesystem{}\n'.format( + COLORS['YELLOW'], COLORS['CLEAR']) + if disk['Clobber Risk']: + warnings += '{} + Backup exists on {}{}\n'.format( + COLORS['BLUE'], destination['Name'], COLORS['CLEAR']) + if disk['Bad Partitions'] or disk['Clobber Risk']: + warnings += '\n{}Marked partition(s) will NOT be backed up.{}\n'.format( + COLORS['YELLOW'], COLORS['CLEAR']) + disk['Backup Warnings'] = warnings + +def select_backup_destination(auto_select=True): + # Build menu + destinations = [s for s in BACKUP_SERVERS if s['Mounted']] + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Size check + for dest in destinations: + if 'IP' in dest: + dest['Usage'] = shutil.disk_usage(r'\\{IP}\{Share}'.format(**dest)) + else: + dest['Usage'] = shutil.disk_usage('{}:\\'.format(dest['Letter'])) + dest['Free Space'] = human_readable_size(dest['Usage'].free) + dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) + + # Bail + if not destinations: + print_warning('No backup destinations found.') + raise GenericAbort + + # Skip menu? + if len(destinations) == 1 and auto_select: + return destinations[0] + + selection = menu_select( + title = 'Where are we backing up to?', + main_entries = destinations, + action_entries = actions) + if selection == 'M': + raise GenericAbort + else: + return destinations[int(selection)-1] + +def verify_wim_backup(partition): + if not os.path.exists(partition['Image Path']): + raise PathNotFoundError + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'verify', + partition['Image Path'], + ' --nocheck', + ] + run_program(cmd) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/common.py b/.bin/Scripts/functions/common.py similarity index 97% rename from Scripts/functions/common.py rename to .bin/Scripts/functions/common.py index 59826f0f..2c299628 100644 --- a/Scripts/functions/common.py +++ b/.bin/Scripts/functions/common.py @@ -1,701 +1,701 @@ -# Wizard Kit PE: Functions - Common - -import os -import psutil -import re -import shutil -import subprocess -import sys -import time -import traceback -import winreg - -from subprocess import CalledProcessError - -from settings.main import * -from settings.tools import * - -# Global variables -global_vars = {} - -# STATIC VARIABLES -COLORS = { - 'CLEAR': '\033[0m', - 'RED': '\033[31m', - 'GREEN': '\033[32m', - 'YELLOW': '\033[33m', - 'BLUE': '\033[34m' -} -HKU = winreg.HKEY_USERS -HKCU = winreg.HKEY_CURRENT_USER -HKLM = winreg.HKEY_LOCAL_MACHINE - -# Error Classes -class BIOSKeyNotFoundError(Exception): - pass - -class BinNotFoundError(Exception): - pass - -class GenericAbort(Exception): - pass - -class GenericError(Exception): - pass - -class GenericRepair(Exception): - pass - -class MultipleInstallationsError(Exception): - pass - -class NotInstalledError(Exception): - pass - -class NoProfilesError(Exception): - pass - -class PathNotFoundError(Exception): - pass - -class UnsupportedOSError(Exception): - pass - -# General functions -def abort(): - """Abort script.""" - print_warning('Aborted.') - sleep(5) - exit_script() - -def ask(prompt='Kotaero!'): - """Prompt the user with a Y/N question, log answer, and return a bool.""" - answer = None - prompt = '{} [Y/N]: '.format(prompt) - while answer is None: - tmp = input(prompt) - if re.search(r'^y(es|)$', tmp, re.IGNORECASE): - answer = True - elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE): - answer = False - message = '{prompt}{answer_text}'.format( - prompt = prompt, - answer_text = 'Yes' if answer else 'No') - print_log(message=message) - return answer - -def clear_screen(): - """Simple wrapper for cls.""" - os.system('cls') - -def convert_to_bytes(size): - """Convert human-readable size str to bytes and return an int.""" - size = str(size) - tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) - if tmp: - size = int(tmp.group(1)) - units = tmp.group(2) - if units == 'TB': - size *= 1099511627776 - elif units == 'GB': - size *= 1073741824 - elif units == 'MB': - size *= 1048576 - elif units == 'KB': - size *= 1024 - else: - return -1 - - return size - -def exit_script(return_value=0): - """Exits the script after some cleanup and opens the log (if set).""" - # Remove dirs (if empty) - for dir in ['BackupDir', 'LogDir', 'TmpDir']: - try: - dir = global_vars[dir] - os.rmdir(dir) - except Exception: - pass - - # Open Log (if it exists) - log = global_vars.get('LogFile', '') - if log and os.path.exists(log): - try: - extract_item('NotepadPlusPlus', silent=True) - popen_program( - [global_vars['Tools']['NotepadPlusPlus'], - global_vars['LogFile']]) - except Exception: - print_error('ERROR: Failed to extract Notepad++ and open log.') - pause('Press Enter to exit...') - - # Kill Caffeine if still running - kill_process('caffeine.exe') - - # Exit - sys.exit(return_value) - -def extract_item(item, filter='', silent=False): - """Extract item from .cbin into .bin.""" - cmd = [ - global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0', - '-p{ArchivePassword}'.format(**global_vars), - r'-o{BinDir}\{item}'.format(item=item, **global_vars), - r'{CBinDir}\{item}.7z'.format(item=item, **global_vars), - filter] - if not silent: - print_standard('Extracting "{item}"...'.format(item=item)) - try: - run_program(cmd) - except subprocess.CalledProcessError: - if not silent: - print_warning('WARNING: Errors encountered while exctracting data') - -def get_ticket_number(): - """Get TicketNumber from user, save in LogDir, and return as str.""" - ticket_number = None - while ticket_number is None: - _input = input('Enter ticket number: ') - if re.match(r'^([0-9]+([-_]?\w+|))$', _input): - ticket_number = _input - with open(r'{LogDir}\TicketNumber'.format(**global_vars), 'w') as f: - f.write(ticket_number) - return ticket_number - -def human_readable_size(size, decimals=0): - """Convert size in bytes to a human-readable format and return a str.""" - # Prep string formatting - width = 3+decimals - if decimals > 0: - width += 1 - - # Convert size to int - try: - size = int(size) - except ValueError: - size = convert_to_bytes(size) - - # Verify we have a valid size - if size < 0: - return '{size:>{width}} b'.format(size='???', width=width) - - # Convert to sensible units - if size >= 1099511627776: - size /= 1099511627776 - units = 'Tb' - elif size >= 1073741824: - size /= 1073741824 - units = 'Gb' - elif size >= 1048576: - size /= 1048576 - units = 'Mb' - elif size >= 1024: - size /= 1024 - units = 'Kb' - else: - units = ' b' - - # Return - return '{size:>{width}.{decimals}f} {units}'.format( - size=size, width=width, decimals=decimals, units=units) - -def kill_process(name): - """Kill any running caffeine.exe processes.""" - for proc in psutil.process_iter(): - if proc.name() == name: - proc.kill() - -def major_exception(): - """Display traceback and exit""" - print_error('Major exception') - print_warning(SUPPORT_MESSAGE) - print(traceback.format_exc()) - print_log(traceback.format_exc()) - sleep(30) - pause('Press Enter to exit...') - exit_script(1) - -def menu_select(title='~ Untitled Menu ~', - prompt='Please make a selection', secret_exit=False, - main_entries=[], action_entries=[], disabled_label='DISABLED'): - """Display options in a menu and return selected option as a str.""" - # Bail early - if not main_entries and not action_entries: - raise Exception("MenuError: No items given") - - # Set title - if 'Title' in global_vars: - title = '{}\n\n{}'.format(global_vars['Title']) - - # Build menu - menu_splash = '{}\n\n'.format(title) - width = len(str(len(main_entries))) - valid_answers = [] - if (secret_exit): - valid_answers.append('Q') - - # Add main entries - for i in range(len(main_entries)): - entry = main_entries[i] - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - entry_str = '{number:>{width}}: {name}'.format( - number = i+1, - width = width, - name = entry.get('Display Name', entry['Name'])) - if entry.get('Disabled', False): - entry_str = '{YELLOW}{entry_str} ({disabled}){CLEAR}'.format( - entry_str = entry_str, - disabled = disabled_label, - **COLORS) - else: - valid_answers.append(str(i+1)) - menu_splash += '{}\n'.format(entry_str) - menu_splash += '\n' - - # Add action entries - for entry in action_entries: - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(entry['Letter']) - menu_splash += '{letter:>{width}}: {name}\n'.format( - letter = entry['Letter'].upper(), - width = len(str(len(action_entries))), - name = entry['Name']) - menu_splash += '\n' - - answer = '' - - while (answer.upper() not in valid_answers): - os.system('cls') - print(menu_splash) - answer = input('{}: '.format(prompt)) - - return answer.upper() - -def non_clobber_rename(full_path): - """Append suffix to path, if necessary, to avoid clobbering path""" - new_path = full_path - _i = 1; - while os.path.exists(new_path): - new_path = '{path}_{i}'.format(i=_i, path=full_path) - _i += 1 - - return new_path - -def pause(prompt='Press Enter to continue... '): - """Simple pause implementation.""" - input(prompt) - -def ping(addr='google.com'): - """Attempt to ping addr.""" - cmd = ['ping', '-n', '2', addr] - run_program(cmd) - -def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs): - """Run program and return a subprocess.Popen object.""" - startupinfo=None - if minimized: - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW - startupinfo.wShowWindow = 6 - - if pipe: - popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo) - - return popen_obj - -def print_error(*args, **kwargs): - """Prints message to screen in RED.""" - print_standard(*args, color=COLORS['RED'], **kwargs) - -def print_info(*args, **kwargs): - """Prints message to screen in BLUE.""" - print_standard(*args, color=COLORS['BLUE'], **kwargs) - -def print_standard(message='Generic info', - color=None, end='\n', timestamp=True, **kwargs): - """Prints message to screen and log (if set).""" - display_message = message - if color: - display_message = color + message + COLORS['CLEAR'] - # **COLORS is used below to support non-"standard" color printing - print(display_message.format(**COLORS), end=end, **kwargs) - print_log(message, end, timestamp) - -def print_success(*args, **kwargs): - """Prints message to screen in GREEN.""" - print_standard(*args, color=COLORS['GREEN'], **kwargs) - -def print_warning(*args, **kwargs): - """Prints message to screen in YELLOW.""" - print_standard(*args, color=COLORS['YELLOW'], **kwargs) - -def print_log(message='', end='\n', timestamp=True): - time_str = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else '' - if 'LogFile' in global_vars and global_vars['LogFile'] is not None: - with open(global_vars['LogFile'], 'a') as f: - for line in message.splitlines(): - f.write('{timestamp}{line}{end}'.format( - timestamp = time_str, - line = line, - end = end)) - -def run_program(cmd, args=[], check=True, pipe=True, shell=False): - """Run program and return a subprocess.CompletedProcess object.""" - if args: - # Deprecated so let's raise an exception to find & fix all occurances - print_error('ERROR: Using args is no longer supported.') - raise Exception - cmd = [c for c in cmd if c] - if shell: - cmd = ' '.join(cmd) - - if pipe: - process_return = subprocess.run(cmd, check=check, shell=shell, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - process_return = subprocess.run(cmd, check=check, shell=shell) - - return process_return - -def set_title(title='~Some Title~'): - """Set title. - - Used for window title and menu titles.""" - global_vars['Title'] = title - os.system('title {}'.format(title)) - -def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): - """Display info with formatting.""" - print_standard('{indent}{message:<{width}}{info}'.format( - indent=' '*indent, width=width, message=message, info=info)) - -def sleep(seconds=2): - """Wait for a while.""" - time.sleep(seconds) - -def stay_awake(): - """Prevent the system from sleeping or hibernating.""" - # Bail if caffeine is already running - for proc in psutil.process_iter(): - if proc.name() == 'caffeine.exe': - return - # Extract and run - extract_item('Caffeine', silent=True) - try: - popen_program(global_vars['Tools']['Caffeine']) - except Exception: - print_error('ERROR: No caffeine available.') - print_warning('Please set the power setting to High Performance.') - -def get_exception(s): - """Get exception by name, returns Exception object.""" - return getattr(sys.modules[__name__], s) - -def try_and_print(message='Trying...', - function=None, cs='CS', ns='NS', other_results={}, - catch_all=True, print_return=False, silent_function=True, - indent=8, width=32, *args, **kwargs): - """Run function, print if successful or not, and return dict. - - other_results is in the form of - { - 'Warning': {'ExceptionClassName': 'Result Message'}, - 'Error': {'ExceptionClassName': 'Result Message'} - } - The the ExceptionClassNames will be excepted conditions - and the result string will be printed in the correct color. - catch_all=False will result in unspecified exceptions being re-raised.""" - err = None - out = None - w_exceptions = other_results.get('Warning', {}).keys() - w_exceptions = tuple(get_exception(e) for e in w_exceptions) - e_exceptions = other_results.get('Error', {}).keys() - e_exceptions = tuple(get_exception(e) for e in e_exceptions) - w_results = other_results.get('Warning', {}) - e_results = other_results.get('Error', {}) - - # Run function and catch errors - print_standard('{indent}{message:<{width}}'.format( - indent=' '*indent, message=message, width=width), end='', flush=True) - try: - out = function(*args, **kwargs) - if print_return: - print_standard(out[0], timestamp=False) - for item in out[1:]: - print_standard('{indent}{item}'.format( - indent=' '*(indent+width), item=item)) - elif silent_function: - print_success(cs, timestamp=False) - except w_exceptions as e: - _result = w_results.get(e.__class__.__name__, 'Warning') - print_warning(_result, timestamp=False) - err = e - except e_exceptions as e: - _result = e_results.get(e.__class__.__name__, 'Error') - print_error(_result, timestamp=False) - err = e - except Exception: - print_error(ns, timestamp=False) - err = traceback.format_exc() - - # Return or raise? - if err and not catch_all: - raise - else: - return {'CS': not bool(err), 'Error': err, 'Out': out} - -def upload_data(path, file): - """Add CLIENT_INFO_SERVER to authorized connections and upload file.""" - if not ENABLED_UPLOAD_DATA: - raise GenericError('Feature disabled.') - - extract_item('PuTTY', filter='wizkit.ppk psftp.exe', silent=True) - - # Authorize connection to the server - winreg.CreateKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys') - with winreg.OpenKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys', - access=winreg.KEY_WRITE) as key: - winreg.SetValueEx(key, - 'rsa2@22:{IP}'.format(**CLIENT_INFO_SERVER), 0, - winreg.REG_SZ, CLIENT_INFO_SERVER['RegEntry']) - - # Write batch file - with open(r'{TmpDir}\psftp.batch'.format(**global_vars), - 'w', encoding='ascii') as f: - f.write('lcd "{path}"\n'.format(path=path)) - f.write('cd "{Share}"\n'.format(**CLIENT_INFO_SERVER)) - f.write('mkdir {TicketNumber}\n'.format(**global_vars)) - f.write('cd {TicketNumber}\n'.format(**global_vars)) - f.write('put "{file}"\n'.format(file=file)) - - # Upload Info - cmd = [ - global_vars['Tools']['PuTTY-PSFTP'], - '-noagent', - '-i', r'{BinDir}\PuTTY\wizkit.ppk'.format(**global_vars), - '{User}@{IP}'.format(**CLIENT_INFO_SERVER), - '-b', r'{TmpDir}\psftp.batch'.format(**global_vars)] - run_program(cmd) - -def upload_info(): - """Upload compressed Info file to the NAS as set in settings.main.py.""" - if not ENABLED_UPLOAD_DATA: - raise GenericError('Feature disabled.') - - path = '{ClientDir}'.format(**global_vars) - file = 'Info_{Date-Time}.7z'.format(**global_vars) - upload_data(path, file) - -def compress_info(): - """Compress ClientDir info folders with 7-Zip for upload_info().""" - path = '{ClientDir}'.format(**global_vars) - file = 'Info_{Date-Time}.7z'.format(**global_vars) - _cmd = [ - global_vars['Tools']['SevenZip'], - 'a', '-t7z', '-mx=9', '-bso0', '-bse0', - r'{}\{}'.format(path, file), - r'{ClientDir}\Info'.format(**global_vars)] - run_program(_cmd) - -def wait_for_process(name, poll_rate=3): - """Wait for process by name.""" - running = True - while running: - sleep(poll_rate) - running = False - for proc in psutil.process_iter(): - if re.search(r'^{}'.format(name), proc.name(), re.IGNORECASE): - running = True - sleep(1) - -# global_vars functions -def init_global_vars(): - """Sets global variables based on system info.""" - print_info('Initializing') - os.system('title Wizard Kit') - init_functions = [ - ['Checking .bin...', find_bin], - ['Checking environment...', set_common_vars], - ['Checking OS...', check_os], - ['Checking tools...', check_tools], - ['Creating folders...', make_tmp_dirs], - ['Clearing collisions...', clean_env_vars], - ] - try: - for f in init_functions: - try_and_print( - message=f[0], function=f[1], - cs='Done', ns='Error', catch_all=False) - except: - major_exception() - -def check_os(): - """Set OS specific variables.""" - tmp = {} - - # Query registry - _reg_path = winreg.OpenKey( - HKLM, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') - for key in ['CSDVersion', 'CurrentBuild', 'CurrentBuildNumber', - 'CurrentVersion', 'ProductName']: - try: - tmp[key] = winreg.QueryValueEx(_reg_path, key)[0] - if key in ['CurrentBuild', 'CurrentBuildNumber']: - tmp[key] = int(tmp[key]) - except ValueError: - # Couldn't convert Build to int so this should be interesting... - tmp[key] = 0 - except Exception: - tmp[key] = 'Unknown' - - # Determine OS bit depth - tmp['Arch'] = 32 - if 'PROGRAMFILES(X86)' in global_vars['Env']: - tmp['Arch'] = 64 - - # Determine OS Name - tmp['Name'] = '{ProductName} {CSDVersion}'.format(**tmp) - if tmp['CurrentBuild'] == 9600: - tmp['Name'] += ' Update' # Win 8.1u - if tmp['CurrentBuild'] == 10240: - tmp['Name'] += ' Release 1507 "Threshold 1"' - if tmp['CurrentBuild'] == 10586: - tmp['Name'] += ' Release 1511 "Threshold 2"' - if tmp['CurrentBuild'] == 14393: - tmp['Name'] += ' Release 1607 "Redstone 1" / "Anniversary Update"' - if tmp['CurrentBuild'] == 15063: - tmp['Name'] += ' Release 1703 "Redstone 2" / "Creators Update"' - if tmp['CurrentBuild'] == 16299: - tmp['Name'] += ' Release 1709 "Redstone 3" / "Fall Creators Update"' - tmp['Name'] = tmp['Name'].replace('Service Pack ', 'SP') - tmp['Name'] = tmp['Name'].replace('Unknown Release', 'Release') - tmp['Name'] = re.sub(r'\s+', ' ', tmp['Name']) - - # Determine OS version - name = '{Name} x{Arch}'.format(**tmp) - if tmp['CurrentVersion'] == '6.0': - tmp['Version'] = 'Vista' - name += ' (very outdated)' - elif tmp['CurrentVersion'] == '6.1': - tmp['Version'] = '7' - if tmp['CSDVersion'] == 'Service Pack 1': - name += ' (outdated)' - else: - name += ' (very outdated)' - elif tmp['CurrentVersion'] in ['6.2', '6.3']: - if int(tmp['CurrentBuildNumber']) <= 9600: - tmp['Version'] = '8' - elif int(tmp['CurrentBuildNumber']) >= 10240: - tmp['Version'] = '10' - if tmp['CurrentBuild'] in [9200, 10240, 10586]: - name += ' (very outdated)' - elif tmp['CurrentBuild'] in [9600, 14393, 15063]: - name += ' (outdated)' - elif tmp['CurrentBuild'] == 16299: - pass # Current Win10 - else: - name += ' (unrecognized)' - tmp['DisplayName'] = name - - # == vista == - # 6.0.6000 - # 6.0.6001 - # 6.0.6002 - # ==== 7 ==== - # 6.1.7600 - # 6.1.7601 - # 6.1.7602 - # ==== 8 ==== - # 6.2.9200 - # === 8.1 === - # 6.3.9200 - # === 8.1u == - # 6.3.9600 - # === 10 v1507 "Threshold 1" == - # 6.3.10240 - # === 10 v1511 "Threshold 2" == - # 6.3.10586 - # === 10 v1607 "Redstone 1" "Anniversary Update" == - # 6.3.14393 - # === 10 v1703 "Redstone 2" "Creators Update" == - # 6.3.15063 - # === 10 v1709 "Redstone 3" "Fall Creators Update" == - # 6.3.16299 - global_vars['OS'] = tmp - -def check_tools(): - """Set tool variables based on OS bit-depth and tool availability.""" - if global_vars['OS'].get('Arch', 32) == 64: - global_vars['Tools'] = { - k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()} - else: - global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()} - - # Fix paths - global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v) - for (k, v) in global_vars['Tools'].items()} - -def clean_env_vars(): - """Remove conflicting global_vars and env variables. - - This fixes an issue where both global_vars and - global_vars['Env'] are expanded at the same time.""" - for key in global_vars.keys(): - global_vars['Env'].pop(key, None) - -def find_bin(): - """Find .bin folder in the cwd or it's parents.""" - wd = os.getcwd() - base = None - while base is None: - if os.path.exists('.bin'): - base = os.getcwd() - break - if re.fullmatch(r'\w:\\', os.getcwd()): - break - os.chdir('..') - os.chdir(wd) - if base is None: - raise BinNotFoundError - global_vars['BaseDir'] = base - -def make_tmp_dirs(): - """Make temp directories.""" - os.makedirs(global_vars['BackupDir'], exist_ok=True) - os.makedirs(global_vars['LogDir'], exist_ok=True) - os.makedirs(global_vars['TmpDir'], exist_ok=True) - -def set_common_vars(): - """Set common variables.""" - global_vars['Date'] = time.strftime("%Y-%m-%d") - global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z") - global_vars['Env'] = os.environ.copy() - - global_vars['ArchivePassword'] = ARCHIVE_PASSWORD - global_vars['BinDir'] = r'{BaseDir}\.bin'.format( - **global_vars) - global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format( - **global_vars) - global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format( - prefix=KIT_NAME_SHORT, **global_vars['Env']) - global_vars['BackupDir'] = r'{ClientDir}\Backups\{Date}'.format( - **global_vars) - global_vars['LogDir'] = r'{ClientDir}\Info\{Date}'.format( - **global_vars) - global_vars['ProgBackupDir'] = r'{ClientDir}\Backups'.format( - **global_vars) - global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format( - **global_vars) - global_vars['TmpDir'] = r'{BinDir}\tmp'.format( - **global_vars) - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - Common + +import os +import psutil +import re +import shutil +import subprocess +import sys +import time +import traceback +import winreg + +from subprocess import CalledProcessError + +from settings.main import * +from settings.tools import * + +# Global variables +global_vars = {} + +# STATIC VARIABLES +COLORS = { + 'CLEAR': '\033[0m', + 'RED': '\033[31m', + 'GREEN': '\033[32m', + 'YELLOW': '\033[33m', + 'BLUE': '\033[34m' +} +HKU = winreg.HKEY_USERS +HKCU = winreg.HKEY_CURRENT_USER +HKLM = winreg.HKEY_LOCAL_MACHINE + +# Error Classes +class BIOSKeyNotFoundError(Exception): + pass + +class BinNotFoundError(Exception): + pass + +class GenericAbort(Exception): + pass + +class GenericError(Exception): + pass + +class GenericRepair(Exception): + pass + +class MultipleInstallationsError(Exception): + pass + +class NotInstalledError(Exception): + pass + +class NoProfilesError(Exception): + pass + +class PathNotFoundError(Exception): + pass + +class UnsupportedOSError(Exception): + pass + +# General functions +def abort(): + """Abort script.""" + print_warning('Aborted.') + sleep(5) + exit_script() + +def ask(prompt='Kotaero!'): + """Prompt the user with a Y/N question, log answer, and return a bool.""" + answer = None + prompt = '{} [Y/N]: '.format(prompt) + while answer is None: + tmp = input(prompt) + if re.search(r'^y(es|)$', tmp, re.IGNORECASE): + answer = True + elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE): + answer = False + message = '{prompt}{answer_text}'.format( + prompt = prompt, + answer_text = 'Yes' if answer else 'No') + print_log(message=message) + return answer + +def clear_screen(): + """Simple wrapper for cls.""" + os.system('cls') + +def convert_to_bytes(size): + """Convert human-readable size str to bytes and return an int.""" + size = str(size) + tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) + if tmp: + size = int(tmp.group(1)) + units = tmp.group(2) + if units == 'TB': + size *= 1099511627776 + elif units == 'GB': + size *= 1073741824 + elif units == 'MB': + size *= 1048576 + elif units == 'KB': + size *= 1024 + else: + return -1 + + return size + +def exit_script(return_value=0): + """Exits the script after some cleanup and opens the log (if set).""" + # Remove dirs (if empty) + for dir in ['BackupDir', 'LogDir', 'TmpDir']: + try: + dir = global_vars[dir] + os.rmdir(dir) + except Exception: + pass + + # Open Log (if it exists) + log = global_vars.get('LogFile', '') + if log and os.path.exists(log): + try: + extract_item('NotepadPlusPlus', silent=True) + popen_program( + [global_vars['Tools']['NotepadPlusPlus'], + global_vars['LogFile']]) + except Exception: + print_error('ERROR: Failed to extract Notepad++ and open log.') + pause('Press Enter to exit...') + + # Kill Caffeine if still running + kill_process('caffeine.exe') + + # Exit + sys.exit(return_value) + +def extract_item(item, filter='', silent=False): + """Extract item from .cbin into .bin.""" + cmd = [ + global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0', + '-p{ArchivePassword}'.format(**global_vars), + r'-o{BinDir}\{item}'.format(item=item, **global_vars), + r'{CBinDir}\{item}.7z'.format(item=item, **global_vars), + filter] + if not silent: + print_standard('Extracting "{item}"...'.format(item=item)) + try: + run_program(cmd) + except subprocess.CalledProcessError: + if not silent: + print_warning('WARNING: Errors encountered while exctracting data') + +def get_ticket_number(): + """Get TicketNumber from user, save in LogDir, and return as str.""" + ticket_number = None + while ticket_number is None: + _input = input('Enter ticket number: ') + if re.match(r'^([0-9]+([-_]?\w+|))$', _input): + ticket_number = _input + with open(r'{LogDir}\TicketNumber'.format(**global_vars), 'w') as f: + f.write(ticket_number) + return ticket_number + +def human_readable_size(size, decimals=0): + """Convert size in bytes to a human-readable format and return a str.""" + # Prep string formatting + width = 3+decimals + if decimals > 0: + width += 1 + + # Convert size to int + try: + size = int(size) + except ValueError: + size = convert_to_bytes(size) + + # Verify we have a valid size + if size < 0: + return '{size:>{width}} b'.format(size='???', width=width) + + # Convert to sensible units + if size >= 1099511627776: + size /= 1099511627776 + units = 'Tb' + elif size >= 1073741824: + size /= 1073741824 + units = 'Gb' + elif size >= 1048576: + size /= 1048576 + units = 'Mb' + elif size >= 1024: + size /= 1024 + units = 'Kb' + else: + units = ' b' + + # Return + return '{size:>{width}.{decimals}f} {units}'.format( + size=size, width=width, decimals=decimals, units=units) + +def kill_process(name): + """Kill any running caffeine.exe processes.""" + for proc in psutil.process_iter(): + if proc.name() == name: + proc.kill() + +def major_exception(): + """Display traceback and exit""" + print_error('Major exception') + print_warning(SUPPORT_MESSAGE) + print(traceback.format_exc()) + print_log(traceback.format_exc()) + sleep(30) + pause('Press Enter to exit...') + exit_script(1) + +def menu_select(title='~ Untitled Menu ~', + prompt='Please make a selection', secret_exit=False, + main_entries=[], action_entries=[], disabled_label='DISABLED'): + """Display options in a menu and return selected option as a str.""" + # Bail early + if not main_entries and not action_entries: + raise Exception("MenuError: No items given") + + # Set title + if 'Title' in global_vars: + title = '{}\n\n{}'.format(global_vars['Title']) + + # Build menu + menu_splash = '{}\n\n'.format(title) + width = len(str(len(main_entries))) + valid_answers = [] + if (secret_exit): + valid_answers.append('Q') + + # Add main entries + for i in range(len(main_entries)): + entry = main_entries[i] + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + entry_str = '{number:>{width}}: {name}'.format( + number = i+1, + width = width, + name = entry.get('Display Name', entry['Name'])) + if entry.get('Disabled', False): + entry_str = '{YELLOW}{entry_str} ({disabled}){CLEAR}'.format( + entry_str = entry_str, + disabled = disabled_label, + **COLORS) + else: + valid_answers.append(str(i+1)) + menu_splash += '{}\n'.format(entry_str) + menu_splash += '\n' + + # Add action entries + for entry in action_entries: + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(entry['Letter']) + menu_splash += '{letter:>{width}}: {name}\n'.format( + letter = entry['Letter'].upper(), + width = len(str(len(action_entries))), + name = entry['Name']) + menu_splash += '\n' + + answer = '' + + while (answer.upper() not in valid_answers): + os.system('cls') + print(menu_splash) + answer = input('{}: '.format(prompt)) + + return answer.upper() + +def non_clobber_rename(full_path): + """Append suffix to path, if necessary, to avoid clobbering path""" + new_path = full_path + _i = 1; + while os.path.exists(new_path): + new_path = '{path}_{i}'.format(i=_i, path=full_path) + _i += 1 + + return new_path + +def pause(prompt='Press Enter to continue... '): + """Simple pause implementation.""" + input(prompt) + +def ping(addr='google.com'): + """Attempt to ping addr.""" + cmd = ['ping', '-n', '2', addr] + run_program(cmd) + +def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs): + """Run program and return a subprocess.Popen object.""" + startupinfo=None + if minimized: + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW + startupinfo.wShowWindow = 6 + + if pipe: + popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=startupinfo) + + return popen_obj + +def print_error(*args, **kwargs): + """Prints message to screen in RED.""" + print_standard(*args, color=COLORS['RED'], **kwargs) + +def print_info(*args, **kwargs): + """Prints message to screen in BLUE.""" + print_standard(*args, color=COLORS['BLUE'], **kwargs) + +def print_standard(message='Generic info', + color=None, end='\n', timestamp=True, **kwargs): + """Prints message to screen and log (if set).""" + display_message = message + if color: + display_message = color + message + COLORS['CLEAR'] + # **COLORS is used below to support non-"standard" color printing + print(display_message.format(**COLORS), end=end, **kwargs) + print_log(message, end, timestamp) + +def print_success(*args, **kwargs): + """Prints message to screen in GREEN.""" + print_standard(*args, color=COLORS['GREEN'], **kwargs) + +def print_warning(*args, **kwargs): + """Prints message to screen in YELLOW.""" + print_standard(*args, color=COLORS['YELLOW'], **kwargs) + +def print_log(message='', end='\n', timestamp=True): + time_str = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else '' + if 'LogFile' in global_vars and global_vars['LogFile'] is not None: + with open(global_vars['LogFile'], 'a') as f: + for line in message.splitlines(): + f.write('{timestamp}{line}{end}'.format( + timestamp = time_str, + line = line, + end = end)) + +def run_program(cmd, args=[], check=True, pipe=True, shell=False): + """Run program and return a subprocess.CompletedProcess object.""" + if args: + # Deprecated so let's raise an exception to find & fix all occurances + print_error('ERROR: Using args is no longer supported.') + raise Exception + cmd = [c for c in cmd if c] + if shell: + cmd = ' '.join(cmd) + + if pipe: + process_return = subprocess.run(cmd, check=check, shell=shell, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + process_return = subprocess.run(cmd, check=check, shell=shell) + + return process_return + +def set_title(title='~Some Title~'): + """Set title. + + Used for window title and menu titles.""" + global_vars['Title'] = title + os.system('title {}'.format(title)) + +def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): + """Display info with formatting.""" + print_standard('{indent}{message:<{width}}{info}'.format( + indent=' '*indent, width=width, message=message, info=info)) + +def sleep(seconds=2): + """Wait for a while.""" + time.sleep(seconds) + +def stay_awake(): + """Prevent the system from sleeping or hibernating.""" + # Bail if caffeine is already running + for proc in psutil.process_iter(): + if proc.name() == 'caffeine.exe': + return + # Extract and run + extract_item('Caffeine', silent=True) + try: + popen_program(global_vars['Tools']['Caffeine']) + except Exception: + print_error('ERROR: No caffeine available.') + print_warning('Please set the power setting to High Performance.') + +def get_exception(s): + """Get exception by name, returns Exception object.""" + return getattr(sys.modules[__name__], s) + +def try_and_print(message='Trying...', + function=None, cs='CS', ns='NS', other_results={}, + catch_all=True, print_return=False, silent_function=True, + indent=8, width=32, *args, **kwargs): + """Run function, print if successful or not, and return dict. + + other_results is in the form of + { + 'Warning': {'ExceptionClassName': 'Result Message'}, + 'Error': {'ExceptionClassName': 'Result Message'} + } + The the ExceptionClassNames will be excepted conditions + and the result string will be printed in the correct color. + catch_all=False will result in unspecified exceptions being re-raised.""" + err = None + out = None + w_exceptions = other_results.get('Warning', {}).keys() + w_exceptions = tuple(get_exception(e) for e in w_exceptions) + e_exceptions = other_results.get('Error', {}).keys() + e_exceptions = tuple(get_exception(e) for e in e_exceptions) + w_results = other_results.get('Warning', {}) + e_results = other_results.get('Error', {}) + + # Run function and catch errors + print_standard('{indent}{message:<{width}}'.format( + indent=' '*indent, message=message, width=width), end='', flush=True) + try: + out = function(*args, **kwargs) + if print_return: + print_standard(out[0], timestamp=False) + for item in out[1:]: + print_standard('{indent}{item}'.format( + indent=' '*(indent+width), item=item)) + elif silent_function: + print_success(cs, timestamp=False) + except w_exceptions as e: + _result = w_results.get(e.__class__.__name__, 'Warning') + print_warning(_result, timestamp=False) + err = e + except e_exceptions as e: + _result = e_results.get(e.__class__.__name__, 'Error') + print_error(_result, timestamp=False) + err = e + except Exception: + print_error(ns, timestamp=False) + err = traceback.format_exc() + + # Return or raise? + if err and not catch_all: + raise + else: + return {'CS': not bool(err), 'Error': err, 'Out': out} + +def upload_data(path, file): + """Add CLIENT_INFO_SERVER to authorized connections and upload file.""" + if not ENABLED_UPLOAD_DATA: + raise GenericError('Feature disabled.') + + extract_item('PuTTY', filter='wizkit.ppk psftp.exe', silent=True) + + # Authorize connection to the server + winreg.CreateKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys') + with winreg.OpenKey(HKCU, r'Software\SimonTatham\PuTTY\SshHostKeys', + access=winreg.KEY_WRITE) as key: + winreg.SetValueEx(key, + 'rsa2@22:{IP}'.format(**CLIENT_INFO_SERVER), 0, + winreg.REG_SZ, CLIENT_INFO_SERVER['RegEntry']) + + # Write batch file + with open(r'{TmpDir}\psftp.batch'.format(**global_vars), + 'w', encoding='ascii') as f: + f.write('lcd "{path}"\n'.format(path=path)) + f.write('cd "{Share}"\n'.format(**CLIENT_INFO_SERVER)) + f.write('mkdir {TicketNumber}\n'.format(**global_vars)) + f.write('cd {TicketNumber}\n'.format(**global_vars)) + f.write('put "{file}"\n'.format(file=file)) + + # Upload Info + cmd = [ + global_vars['Tools']['PuTTY-PSFTP'], + '-noagent', + '-i', r'{BinDir}\PuTTY\wizkit.ppk'.format(**global_vars), + '{User}@{IP}'.format(**CLIENT_INFO_SERVER), + '-b', r'{TmpDir}\psftp.batch'.format(**global_vars)] + run_program(cmd) + +def upload_info(): + """Upload compressed Info file to the NAS as set in settings.main.py.""" + if not ENABLED_UPLOAD_DATA: + raise GenericError('Feature disabled.') + + path = '{ClientDir}'.format(**global_vars) + file = 'Info_{Date-Time}.7z'.format(**global_vars) + upload_data(path, file) + +def compress_info(): + """Compress ClientDir info folders with 7-Zip for upload_info().""" + path = '{ClientDir}'.format(**global_vars) + file = 'Info_{Date-Time}.7z'.format(**global_vars) + _cmd = [ + global_vars['Tools']['SevenZip'], + 'a', '-t7z', '-mx=9', '-bso0', '-bse0', + r'{}\{}'.format(path, file), + r'{ClientDir}\Info'.format(**global_vars)] + run_program(_cmd) + +def wait_for_process(name, poll_rate=3): + """Wait for process by name.""" + running = True + while running: + sleep(poll_rate) + running = False + for proc in psutil.process_iter(): + if re.search(r'^{}'.format(name), proc.name(), re.IGNORECASE): + running = True + sleep(1) + +# global_vars functions +def init_global_vars(): + """Sets global variables based on system info.""" + print_info('Initializing') + os.system('title Wizard Kit') + init_functions = [ + ['Checking .bin...', find_bin], + ['Checking environment...', set_common_vars], + ['Checking OS...', check_os], + ['Checking tools...', check_tools], + ['Creating folders...', make_tmp_dirs], + ['Clearing collisions...', clean_env_vars], + ] + try: + for f in init_functions: + try_and_print( + message=f[0], function=f[1], + cs='Done', ns='Error', catch_all=False) + except: + major_exception() + +def check_os(): + """Set OS specific variables.""" + tmp = {} + + # Query registry + _reg_path = winreg.OpenKey( + HKLM, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion') + for key in ['CSDVersion', 'CurrentBuild', 'CurrentBuildNumber', + 'CurrentVersion', 'ProductName']: + try: + tmp[key] = winreg.QueryValueEx(_reg_path, key)[0] + if key in ['CurrentBuild', 'CurrentBuildNumber']: + tmp[key] = int(tmp[key]) + except ValueError: + # Couldn't convert Build to int so this should be interesting... + tmp[key] = 0 + except Exception: + tmp[key] = 'Unknown' + + # Determine OS bit depth + tmp['Arch'] = 32 + if 'PROGRAMFILES(X86)' in global_vars['Env']: + tmp['Arch'] = 64 + + # Determine OS Name + tmp['Name'] = '{ProductName} {CSDVersion}'.format(**tmp) + if tmp['CurrentBuild'] == 9600: + tmp['Name'] += ' Update' # Win 8.1u + if tmp['CurrentBuild'] == 10240: + tmp['Name'] += ' Release 1507 "Threshold 1"' + if tmp['CurrentBuild'] == 10586: + tmp['Name'] += ' Release 1511 "Threshold 2"' + if tmp['CurrentBuild'] == 14393: + tmp['Name'] += ' Release 1607 "Redstone 1" / "Anniversary Update"' + if tmp['CurrentBuild'] == 15063: + tmp['Name'] += ' Release 1703 "Redstone 2" / "Creators Update"' + if tmp['CurrentBuild'] == 16299: + tmp['Name'] += ' Release 1709 "Redstone 3" / "Fall Creators Update"' + tmp['Name'] = tmp['Name'].replace('Service Pack ', 'SP') + tmp['Name'] = tmp['Name'].replace('Unknown Release', 'Release') + tmp['Name'] = re.sub(r'\s+', ' ', tmp['Name']) + + # Determine OS version + name = '{Name} x{Arch}'.format(**tmp) + if tmp['CurrentVersion'] == '6.0': + tmp['Version'] = 'Vista' + name += ' (very outdated)' + elif tmp['CurrentVersion'] == '6.1': + tmp['Version'] = '7' + if tmp['CSDVersion'] == 'Service Pack 1': + name += ' (outdated)' + else: + name += ' (very outdated)' + elif tmp['CurrentVersion'] in ['6.2', '6.3']: + if int(tmp['CurrentBuildNumber']) <= 9600: + tmp['Version'] = '8' + elif int(tmp['CurrentBuildNumber']) >= 10240: + tmp['Version'] = '10' + if tmp['CurrentBuild'] in [9200, 10240, 10586]: + name += ' (very outdated)' + elif tmp['CurrentBuild'] in [9600, 14393, 15063]: + name += ' (outdated)' + elif tmp['CurrentBuild'] == 16299: + pass # Current Win10 + else: + name += ' (unrecognized)' + tmp['DisplayName'] = name + + # == vista == + # 6.0.6000 + # 6.0.6001 + # 6.0.6002 + # ==== 7 ==== + # 6.1.7600 + # 6.1.7601 + # 6.1.7602 + # ==== 8 ==== + # 6.2.9200 + # === 8.1 === + # 6.3.9200 + # === 8.1u == + # 6.3.9600 + # === 10 v1507 "Threshold 1" == + # 6.3.10240 + # === 10 v1511 "Threshold 2" == + # 6.3.10586 + # === 10 v1607 "Redstone 1" "Anniversary Update" == + # 6.3.14393 + # === 10 v1703 "Redstone 2" "Creators Update" == + # 6.3.15063 + # === 10 v1709 "Redstone 3" "Fall Creators Update" == + # 6.3.16299 + global_vars['OS'] = tmp + +def check_tools(): + """Set tool variables based on OS bit-depth and tool availability.""" + if global_vars['OS'].get('Arch', 32) == 64: + global_vars['Tools'] = { + k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()} + else: + global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()} + + # Fix paths + global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v) + for (k, v) in global_vars['Tools'].items()} + +def clean_env_vars(): + """Remove conflicting global_vars and env variables. + + This fixes an issue where both global_vars and + global_vars['Env'] are expanded at the same time.""" + for key in global_vars.keys(): + global_vars['Env'].pop(key, None) + +def find_bin(): + """Find .bin folder in the cwd or it's parents.""" + wd = os.getcwd() + base = None + while base is None: + if os.path.exists('.bin'): + base = os.getcwd() + break + if re.fullmatch(r'\w:\\', os.getcwd()): + break + os.chdir('..') + os.chdir(wd) + if base is None: + raise BinNotFoundError + global_vars['BaseDir'] = base + +def make_tmp_dirs(): + """Make temp directories.""" + os.makedirs(global_vars['BackupDir'], exist_ok=True) + os.makedirs(global_vars['LogDir'], exist_ok=True) + os.makedirs(global_vars['TmpDir'], exist_ok=True) + +def set_common_vars(): + """Set common variables.""" + global_vars['Date'] = time.strftime("%Y-%m-%d") + global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z") + global_vars['Env'] = os.environ.copy() + + global_vars['ArchivePassword'] = ARCHIVE_PASSWORD + global_vars['BinDir'] = r'{BaseDir}\.bin'.format( + **global_vars) + global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format( + **global_vars) + global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format( + prefix=KIT_NAME_SHORT, **global_vars['Env']) + global_vars['BackupDir'] = r'{ClientDir}\Backups\{Date}'.format( + **global_vars) + global_vars['LogDir'] = r'{ClientDir}\Info\{Date}'.format( + **global_vars) + global_vars['ProgBackupDir'] = r'{ClientDir}\Backups'.format( + **global_vars) + global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format( + **global_vars) + global_vars['TmpDir'] = r'{BinDir}\tmp'.format( + **global_vars) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/data.py b/.bin/Scripts/functions/data.py similarity index 97% rename from Scripts/functions/data.py rename to .bin/Scripts/functions/data.py index d180c699..e6fa9ce2 100644 --- a/Scripts/functions/data.py +++ b/.bin/Scripts/functions/data.py @@ -1,607 +1,607 @@ -# Wizard Kit PE: Functions - Data - -import ctypes - -from operator import itemgetter - -from functions.common import * - -# Classes -class LocalDisk(): - def __init__(self, disk): - self.disk = disk - self.name = disk.mountpoint.upper() - self.path = self.name - def is_dir(self): - # Should always be true - return True - -# Regex -REGEX_EXCL_ITEMS = re.compile( - r'^(\.(AppleDB|AppleDesktop|AppleDouble' - r'|com\.apple\.timemachine\.supported|dbfseventsd' - r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' - r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' - r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' - r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' - r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' - r'|Thumbs\.db)$', - re.IGNORECASE) -REGEX_EXCL_ROOT_ITEMS = re.compile( - r'^\\?(boot(mgr|nxt)$|Config.msi' - r'|(eula|globdata|install|vc_?red)' - r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' - r'|\$?Win(dows(.old.*|\.~BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' - r'|PerfLogs|Program Files|SYSTEM.SAV' - r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', - re.IGNORECASE) -REGEX_INCL_ROOT_ITEMS = re.compile( - r'^\\?(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' - r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' - r'|{prefix}(-?Info|-?Transfer|)' - r'|(ProgramData|Recovery|Temp.*|Users)$' - r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' - r''.format(prefix=KIT_NAME_SHORT), - re.IGNORECASE) -REGEX_WIM_FILE = re.compile( - r'\.wim$', - re.IGNORECASE) -REGEX_WINDOWS_OLD = re.compile( - r'^\\Win(dows|)\.old', - re.IGNORECASE) - -# STATIC VARIABLES -FAST_COPY_EXCLUDES = [ - r'\*.esd', - r'\*.swm', - r'\*.wim', - r'\*.dd', - r'\*.dd.tgz', - r'\*.dd.txz', - r'\*.map', - r'\*.dmg', - r'\*.image', - r'$RECYCLE.BIN', - r'$Recycle.Bin', - r'.AppleDB', - r'.AppleDesktop', - r'.AppleDouble', - r'.com.apple.timemachine.supported', - r'.dbfseventsd', - r'.DocumentRevisions-V100*', - r'.DS_Store', - r'.fseventsd', - r'.PKInstallSandboxManager', - r'.Spotlight*', - r'.SymAV*', - r'.symSchedScanLockxz', - r'.TemporaryItems', - r'.Trash*', - r'.vol', - r'.VolumeIcon.icns', - r'desktop.ini', - r'Desktop?DB', - r'Desktop?DF', - r'hiberfil.sys', - r'lost+found', - r'Network?Trash?Folder', - r'pagefile.sys', - r'Recycled', - r'RECYCLER', - r'System?Volume?Information', - r'Temporary?Items', - r'Thumbs.db', - ] -FAST_COPY_ARGS = [ - '/cmd=noexist_only', - '/utf8', - '/skip_empty_dir', - '/linkdest', - '/no_ui', - '/auto_close', - '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), - ] -# Code borrowed from: https://stackoverflow.com/a/29075319 -SEM_NORMAL = ctypes.c_uint() -SEM_FAILCRITICALERRORS = 1 -SEM_NOOPENFILEERRORBOX = 0x8000 -SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS - -def cleanup_transfer(dest_path): - """Fix attributes and move extraneous items outside the Transfer folder.""" - try: - # Remove dest_path if empty - os.rmdir(dest_path) - except OSError: - pass - if not os.path.exists(dest_path): - # Bail if dest_path was empty and removed - raise Exception - - # Fix attributes - cmd = ['attrib', '-a', '-h', '-r', '-s', dest_path] - run_program(cmd, check=False) - - for root, dirs, files in os.walk(dest_path, topdown=False): - for name in dirs: - # Remove empty directories and junction points - try: - os.rmdir(os.path.join(root, name)) - except OSError: - pass - for name in files: - # "Remove" files based on exclusion regex - if REGEX_EXCL_ITEMS.search(name): - # Make dest folder - dest_name = root.replace(dest_path, dest_path+'.Removed') - os.makedirs(dest_name, exist_ok=True) - # Set dest filename - dest_name = os.path.join(dest_name, name) - dest_name = non_clobber_rename(dest_name) - source_name = os.path.join(root, name) - try: - shutil.move(source_name, dest_name) - except Exception: - pass - -def is_valid_wim_file(item): - """Checks if the provided os.DirEntry is a valid WIM file, returns bool.""" - valid = bool(item.is_file() and REGEX_WIM_FILE.search(item.name)) - if valid: - extract_item('wimlib', silent=True) - cmd = [global_vars['Tools']['wimlib-imagex'], 'info', item.path] - try: - run_program(cmd) - except subprocess.CalledProcessError: - valid = False - print_log('WARNING: Image "{}" damaged.'.format(item.name)) - return valid - -def mount_backup_shares(): - """Mount the backup shares unless labeled as already mounted.""" - for server in BACKUP_SERVERS: - # Blindly skip if we mounted earlier - if server['Mounted']: - continue - - mount_network_share(server) - -def mount_network_share(server): - """Mount a network share defined by server.""" - # Test connection - try: - ping(server['IP']) - except subprocess.CalledProcessError: - print_error( - r'Failed to mount \\{Name}\{Share}, {IP} unreachable.'.format( - **server)) - sleep(1) - return False - - # Mount - cmd = r'net use \\{IP}\{Share} /user:{User} {Pass}'.format(**server) - cmd = cmd.split(' ') - try: - run_program(cmd) - except Exception: - print_warning(r'Failed to mount \\{Name}\{Share} ({IP})'.format( - **server)) - sleep(1) - else: - print_info('Mounted {Name}'.format(**server)) - server['Mounted'] = True - -def run_fast_copy(items, dest): - """Copy items to dest using FastCopy.""" - if not items: - raise Exception - - cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS] - if 'LogFile' in global_vars: - cmd.append('/logfile={LogFile}'.format(**global_vars)) - cmd.extend(items) - cmd.append('/to={}\\'.format(dest)) - - run_program(cmd) - -def run_wimextract(source, items, dest): - """Extract items from source WIM to dest folder.""" - if not items: - raise Exception - extract_item('wimlib', silent=True) - - # Write files.txt - with open(r'{TmpDir}\wim_files.txt'.format(**global_vars), 'w') as f: - # Defaults - for item in items: - f.write('{item}\n'.format(item=item)) - sleep(1) # For safety? - - # Extract files - cmd = [ - global_vars['Tools']['wimlib-imagex'], - 'extract', - source, '1', - r'@{TmpDir}\wim_files.txt'.format(**global_vars), - '--dest-dir={}\\'.format(dest), - '--no-acls', - '--nullglob'] - run_program(cmd) - -def scan_source(source_obj, dest_path): - """Scan source for files/folders to transfer.""" - selected_items = [] - - if source_obj.is_dir(): - # File-Based - print_standard('Scanning source (folder): {}'.format(source_obj.path)) - selected_items = scan_source_path(source_obj.path, dest_path) - else: - # Image-Based - if REGEX_WIM_FILE.search(source_obj.name): - print_standard('Scanning source (image): {}'.format( - source_obj.path)) - selected_items = scan_source_wim(source_obj.path, dest_path) - else: - print_error('ERROR: Unsupported image: {}'.format( - source_obj.path)) - raise GenericError - - return selected_items - -def scan_source_path(source_path, dest_path, rel_path=None, interactive=True): - """Scan source folder for files/folders to transfer, returns list. - - This will scan the root and (recursively) any Windows.old folders.""" - rel_path = '\\' + rel_path if rel_path else '' - if rel_path: - dest_path = dest_path + rel_path - selected_items = [] - win_olds = [] - - # Root items - root_items = [] - for item in os.scandir(source_path): - if REGEX_INCL_ROOT_ITEMS.search(item.name): - root_items.append(item.path) - elif not REGEX_EXCL_ROOT_ITEMS.search(item.name): - if (not interactive - or ask('Copy: "{}{}" ?'.format(rel_path, item.name))): - root_items.append(item.path) - if REGEX_WINDOWS_OLD.search(item.name): - win_olds.append(item) - if root_items: - selected_items.append({ - 'Message': '{}Root Items...'.format(rel_path), - 'Items': root_items.copy(), - 'Destination': dest_path}) - - # Fonts - if os.path.exists(r'{}\Windows\Fonts'.format(source_path)): - selected_items.append({ - 'Message': '{}Fonts...'.format(rel_path), - 'Items': [r'{}\Windows\Fonts'.format(rel_path)], - 'Destination': r'{}\Windows'.format(dest_path)}) - - # Registry - registry_items = [] - for folder in ['config', 'OEM']: - folder = r'Windows\System32\{}'.format(folder) - folder = os.path.join(source_path, folder) - if os.path.exists(folder): - registry_items.append(folder) - if registry_items: - selected_items.append({ - 'Message': '{}Registry...'.format(rel_path), - 'Items': registry_items.copy(), - 'Destination': r'{}\Windows\System32'.format(dest_path)}) - - # Windows.old(s) - for old in win_olds: - selected_items.append( - scan_source_path( - old.path, dest_path, rel_path=old.name, interactive=False)) - - # Done - return selected_items - -def scan_source_wim(source_wim, dest_path, rel_path=None, interactive=True): - """Scan source WIM file for files/folders to transfer, returns list. - - This will scan the root and (recursively) any Windows.old folders.""" - rel_path = '\\' + rel_path if rel_path else '' - selected_items = [] - win_olds = [] - - # Scan source - extract_item('wimlib', silent=True) - cmd = [ - global_vars['Tools']['wimlib-imagex'], 'dir', - source_wim, '1'] - try: - file_list = run_program(cmd) - except subprocess.CalledProcessError: - print_error('ERROR: Failed to get file list.') - raise - - # Root Items - file_list = [i.strip() - for i in file_list.stdout.decode('utf-8', 'ignore').splitlines() - if i.count('\\') == 1 and i.strip() != '\\'] - root_items = [] - if rel_path: - file_list = [i.replace(rel_path, '') for i in file_list] - for item in file_list: - if REGEX_INCL_ROOT_ITEMS.search(item): - root_items.append(item) - elif not REGEX_EXCL_ROOT_ITEMS.search(item): - if (not interactive - or ask('Extract: "{}{}" ?'.format(rel_path, item))): - root_items.append('{}{}'.format(rel_path, item)) - if REGEX_WINDOWS_OLD.search(item): - win_olds.append(item) - if root_items: - selected_items.append({ - 'Message': '{}Root Items...'.format(rel_path), - 'Items': root_items.copy(), - 'Destination': dest_path}) - - # Fonts - if wim_contains(source_wim, r'{}Windows\Fonts'.format(rel_path)): - selected_items.append({ - 'Message': '{}Fonts...'.format(rel_path), - 'Items': [r'{}\Windows\Fonts'.format(rel_path)], - 'Destination': dest_path}) - - # Registry - registry_items = [] - for folder in ['config', 'OEM']: - folder = r'{}Windows\System32\{}'.format(rel_path, folder) - if wim_contains(source_wim, folder): - registry_items.append(folder) - if registry_items: - selected_items.append({ - 'Message': '{}Registry...'.format(rel_path), - 'Items': registry_items.copy(), - 'Destination': dest_path}) - - # Windows.old(s) - for old in win_olds: - scan_source_wim(source_wim, dest_path, rel_path=old, interactive=False) - - # Done - return selected_items - -def select_destination(folder_path, prompt='Select destination'): - """Select destination drive, returns path as string.""" - disk = select_volume(prompt) - if 'fixed' not in disk['Disk'].opts: - folder_path = folder_path.replace('\\', '-') - path = '{disk}{folder_path}_{Date}'.format( - disk = disk['Disk'].mountpoint, - folder_path = folder_path, - **global_vars) - - # Avoid merging with existing folder - path = non_clobber_rename(path) - os.makedirs(path, exist_ok=True) - - return path - -def select_source(ticket_number): - """Select backup from those found on the BACKUP_SERVERS for the ticket.""" - selected_source = None - sources = [] - mount_backup_shares() - - # Check for ticket folders on servers - for server in BACKUP_SERVERS: - if server['Mounted']: - print_standard('Scanning {}...'.format(server['Name'])) - for d in os.scandir(r'\\{IP}\{Share}'.format(**server)): - if (d.is_dir() - and d.name.lower().startswith(ticket_number.lower())): - # Add folder to sources - sources.append({ - 'Name': '{:9}| File-Based: [DIR] {}'.format( - server['Name'], d.name), - 'Server': server, - 'Source': d}) - - # Check for images and subfolders - for ticket_path in sources.copy(): - for item in os.scandir(ticket_path['Source'].path): - if item.is_dir(): - # Add folder to sources - sources.append({ - 'Name': r'{:9}| File-Based: [DIR] {}\{}'.format( - ticket_path['Server']['Name'], # Server - ticket_path['Source'].name, # Ticket folder - item.name, # Sub-folder - ), - 'Server': ticket_path['Server'], - 'Source': item}) - - # Check for images in folder - for subitem in os.scandir(item.path): - if REGEX_WIM_FILE.search(item.name): - # Add image to sources - try: - size = human_readable_size(item.stat().st_size) - except Exception: - size = ' ? ?' # unknown - sources.append({ - 'Disabled': bool(not is_valid_wim_file(subitem)), - 'Name': r'{:9}| Image-Based: {:>7} {}\{}\{}'.format( - ticket_path['Server']['Name'], # Server - size, # Size (duh) - ticket_path['Source'].name, # Ticket folder - item.name, # Sub-folder - subitem.name, # Image file - ), - 'Server': ticket_path['Server'], - 'Source': subitem}) - elif REGEX_WIM_FILE.search(item.name): - # Add image to sources - try: - size = human_readable_size(item.stat().st_size) - except Exception: - size = ' ? ?' # unknown - sources.append({ - 'Disabled': bool(not is_valid_wim_file(item)), - 'Name': r'{:9}| Image-Based: {:>7} {}\{}'.format( - ticket_path['Server']['Name'], # Server - size, # Size (duh) - ticket_path['Source'].name, # Ticket folder - item.name, # Image file - ), - 'Server': ticket_path['Server'], - 'Source': item}) - # Check for local sources - print_standard('Scanning for local sources...') - set_thread_error_mode(silent=True) # Prevents "No disk" popups - sys_drive = global_vars['Env']['SYSTEMDRIVE'] - for d in psutil.disk_partitions(): - if re.search(r'^{}'.format(sys_drive), d.mountpoint, re.IGNORECASE): - # Skip current OS drive - continue - if 'fixed' in d.opts: - # Skip DVD, etc - sources.append({ - 'Name': '{:9}| File-Based: [DISK] {}'.format( - ' Local', d.mountpoint), - 'Source': LocalDisk(d)}) - set_thread_error_mode(silent=False) # Return to normal - - # Build Menu - sources.sort(key=itemgetter('Name')) - actions = [{'Name': 'Quit', 'Letter': 'Q'}] - - # Select backup from sources - if len(sources) > 0: - selection = menu_select( - 'Which backup are we using?', - main_entries=sources, - action_entries=actions, - disabled_label='DAMAGED') - if selection == 'Q': - umount_backup_shares() - exit_script() - else: - selected_source = sources[int(selection)-1]['Source'] - else: - print_error('ERROR: No backups found for ticket: {}.'.format( - ticket_number)) - umount_backup_shares() - pause("Press Enter to exit...") - exit_script() - - # Done - return selected_source - -def select_volume(title='Select disk', auto_select=True): - """Select disk from attached disks. returns dict.""" - actions = [{'Name': 'Quit', 'Letter': 'Q'}] - disks = [] - - # Build list of disks - set_thread_error_mode(silent=True) # Prevents "No disk" popups - for d in psutil.disk_partitions(): - info = { - 'Disk': d, - 'Name': d.mountpoint} - try: - usage = psutil.disk_usage(d.device) - free = '{free} / {total} available'.format( - free = human_readable_size(usage.free, 2), - total = human_readable_size(usage.total, 2)) - except Exception: - # Meh, leaving unsupported destinations out - pass - # free = 'Unknown' - # info['Disabled'] = True - else: - info['Display Name'] = '{} ({})'.format(info['Name'], free) - disks.append(info) - set_thread_error_mode(silent=False) # Return to normal - - # Skip menu? - if len(disks) == 1 and auto_select: - return disks[0] - - # Show menu - selection = menu_select(title, main_entries=disks, action_entries=actions) - if selection == 'Q': - exit_script() - else: - return disks[int(selection)-1] - -def set_thread_error_mode(silent=True): - """Disable or Enable Windows error message dialogs. - - Disable when scanning for disks to avoid popups for empty cardreaders, etc - """ - # Code borrowed from: https://stackoverflow.com/a/29075319 - kernel32 = ctypes.WinDLL('kernel32') - - if silent: - kernel32.SetThreadErrorMode(SEM_FAIL, ctypes.byref(SEM_NORMAL)) - else: - kernel32.SetThreadErrorMode(SEM_NORMAL, ctypes.byref(SEM_NORMAL)) - -def transfer_source(source_obj, dest_path, selected_items): - """Transfer, or extract, files/folders from source to destination.""" - if source_obj.is_dir(): - # Run FastCopy for each selection "group" - for group in selected_items: - try_and_print(message=group['Message'], - function=run_fast_copy, cs='Done', - items=group['Items'], - dest=group['Destination']) - else: - if REGEX_WIM_FILE.search(source_obj.name): - # Extract files from WIM - for group in selected_items: - try_and_print(message=group['Message'], - function=run_wimextract, cs='Done', - source=source_obj.path, - items=group['Items'], - dest=group['Destination']) - else: - print_error('ERROR: Unsupported image: {}'.format(source_obj.path)) - raise GenericError - -def umount_backup_shares(): - """Unnount the backup shares regardless of current status.""" - for server in BACKUP_SERVERS: - umount_network_share(server) - -def umount_network_share(server): - """Unnount a network share defined by server.""" - cmd = r'net use \\{IP}\{Share} /delete'.format(**server) - cmd = cmd.split(' ') - try: - run_program(cmd) - except Exception: - print_error(r'Failed to umount \\{Name}\{Share}.'.format(**server)) - sleep(1) - else: - print_info('Umounted {Name}'.format(**server)) - server['Mounted'] = False - -def wim_contains(source_path, file_path): - """Check if the WIM contains a file or folder.""" - _cmd = [ - global_vars['Tools']['wimlib-imagex'], 'dir', - source_path, '1', - '--path={}'.format(file_path), - '--one-file-only'] - try: - run_program(_cmd) - except subprocess.CalledProcessError: - return False - else: - return True - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - Data + +import ctypes + +from operator import itemgetter + +from functions.common import * + +# Classes +class LocalDisk(): + def __init__(self, disk): + self.disk = disk + self.name = disk.mountpoint.upper() + self.path = self.name + def is_dir(self): + # Should always be true + return True + +# Regex +REGEX_EXCL_ITEMS = re.compile( + r'^(\.(AppleDB|AppleDesktop|AppleDouble' + r'|com\.apple\.timemachine\.supported|dbfseventsd' + r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' + r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' + r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' + r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' + r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' + r'|Thumbs\.db)$', + re.IGNORECASE) +REGEX_EXCL_ROOT_ITEMS = re.compile( + r'^\\?(boot(mgr|nxt)$|Config.msi' + r'|(eula|globdata|install|vc_?red)' + r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' + r'|\$?Win(dows(.old.*|\.~BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' + r'|PerfLogs|Program Files|SYSTEM.SAV' + r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', + re.IGNORECASE) +REGEX_INCL_ROOT_ITEMS = re.compile( + r'^\\?(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' + r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' + r'|{prefix}(-?Info|-?Transfer|)' + r'|(ProgramData|Recovery|Temp.*|Users)$' + r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' + r''.format(prefix=KIT_NAME_SHORT), + re.IGNORECASE) +REGEX_WIM_FILE = re.compile( + r'\.wim$', + re.IGNORECASE) +REGEX_WINDOWS_OLD = re.compile( + r'^\\Win(dows|)\.old', + re.IGNORECASE) + +# STATIC VARIABLES +FAST_COPY_EXCLUDES = [ + r'\*.esd', + r'\*.swm', + r'\*.wim', + r'\*.dd', + r'\*.dd.tgz', + r'\*.dd.txz', + r'\*.map', + r'\*.dmg', + r'\*.image', + r'$RECYCLE.BIN', + r'$Recycle.Bin', + r'.AppleDB', + r'.AppleDesktop', + r'.AppleDouble', + r'.com.apple.timemachine.supported', + r'.dbfseventsd', + r'.DocumentRevisions-V100*', + r'.DS_Store', + r'.fseventsd', + r'.PKInstallSandboxManager', + r'.Spotlight*', + r'.SymAV*', + r'.symSchedScanLockxz', + r'.TemporaryItems', + r'.Trash*', + r'.vol', + r'.VolumeIcon.icns', + r'desktop.ini', + r'Desktop?DB', + r'Desktop?DF', + r'hiberfil.sys', + r'lost+found', + r'Network?Trash?Folder', + r'pagefile.sys', + r'Recycled', + r'RECYCLER', + r'System?Volume?Information', + r'Temporary?Items', + r'Thumbs.db', + ] +FAST_COPY_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] +# Code borrowed from: https://stackoverflow.com/a/29075319 +SEM_NORMAL = ctypes.c_uint() +SEM_FAILCRITICALERRORS = 1 +SEM_NOOPENFILEERRORBOX = 0x8000 +SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS + +def cleanup_transfer(dest_path): + """Fix attributes and move extraneous items outside the Transfer folder.""" + try: + # Remove dest_path if empty + os.rmdir(dest_path) + except OSError: + pass + if not os.path.exists(dest_path): + # Bail if dest_path was empty and removed + raise Exception + + # Fix attributes + cmd = ['attrib', '-a', '-h', '-r', '-s', dest_path] + run_program(cmd, check=False) + + for root, dirs, files in os.walk(dest_path, topdown=False): + for name in dirs: + # Remove empty directories and junction points + try: + os.rmdir(os.path.join(root, name)) + except OSError: + pass + for name in files: + # "Remove" files based on exclusion regex + if REGEX_EXCL_ITEMS.search(name): + # Make dest folder + dest_name = root.replace(dest_path, dest_path+'.Removed') + os.makedirs(dest_name, exist_ok=True) + # Set dest filename + dest_name = os.path.join(dest_name, name) + dest_name = non_clobber_rename(dest_name) + source_name = os.path.join(root, name) + try: + shutil.move(source_name, dest_name) + except Exception: + pass + +def is_valid_wim_file(item): + """Checks if the provided os.DirEntry is a valid WIM file, returns bool.""" + valid = bool(item.is_file() and REGEX_WIM_FILE.search(item.name)) + if valid: + extract_item('wimlib', silent=True) + cmd = [global_vars['Tools']['wimlib-imagex'], 'info', item.path] + try: + run_program(cmd) + except subprocess.CalledProcessError: + valid = False + print_log('WARNING: Image "{}" damaged.'.format(item.name)) + return valid + +def mount_backup_shares(): + """Mount the backup shares unless labeled as already mounted.""" + for server in BACKUP_SERVERS: + # Blindly skip if we mounted earlier + if server['Mounted']: + continue + + mount_network_share(server) + +def mount_network_share(server): + """Mount a network share defined by server.""" + # Test connection + try: + ping(server['IP']) + except subprocess.CalledProcessError: + print_error( + r'Failed to mount \\{Name}\{Share}, {IP} unreachable.'.format( + **server)) + sleep(1) + return False + + # Mount + cmd = r'net use \\{IP}\{Share} /user:{User} {Pass}'.format(**server) + cmd = cmd.split(' ') + try: + run_program(cmd) + except Exception: + print_warning(r'Failed to mount \\{Name}\{Share} ({IP})'.format( + **server)) + sleep(1) + else: + print_info('Mounted {Name}'.format(**server)) + server['Mounted'] = True + +def run_fast_copy(items, dest): + """Copy items to dest using FastCopy.""" + if not items: + raise Exception + + cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS] + if 'LogFile' in global_vars: + cmd.append('/logfile={LogFile}'.format(**global_vars)) + cmd.extend(items) + cmd.append('/to={}\\'.format(dest)) + + run_program(cmd) + +def run_wimextract(source, items, dest): + """Extract items from source WIM to dest folder.""" + if not items: + raise Exception + extract_item('wimlib', silent=True) + + # Write files.txt + with open(r'{TmpDir}\wim_files.txt'.format(**global_vars), 'w') as f: + # Defaults + for item in items: + f.write('{item}\n'.format(item=item)) + sleep(1) # For safety? + + # Extract files + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'extract', + source, '1', + r'@{TmpDir}\wim_files.txt'.format(**global_vars), + '--dest-dir={}\\'.format(dest), + '--no-acls', + '--nullglob'] + run_program(cmd) + +def scan_source(source_obj, dest_path): + """Scan source for files/folders to transfer.""" + selected_items = [] + + if source_obj.is_dir(): + # File-Based + print_standard('Scanning source (folder): {}'.format(source_obj.path)) + selected_items = scan_source_path(source_obj.path, dest_path) + else: + # Image-Based + if REGEX_WIM_FILE.search(source_obj.name): + print_standard('Scanning source (image): {}'.format( + source_obj.path)) + selected_items = scan_source_wim(source_obj.path, dest_path) + else: + print_error('ERROR: Unsupported image: {}'.format( + source_obj.path)) + raise GenericError + + return selected_items + +def scan_source_path(source_path, dest_path, rel_path=None, interactive=True): + """Scan source folder for files/folders to transfer, returns list. + + This will scan the root and (recursively) any Windows.old folders.""" + rel_path = '\\' + rel_path if rel_path else '' + if rel_path: + dest_path = dest_path + rel_path + selected_items = [] + win_olds = [] + + # Root items + root_items = [] + for item in os.scandir(source_path): + if REGEX_INCL_ROOT_ITEMS.search(item.name): + root_items.append(item.path) + elif not REGEX_EXCL_ROOT_ITEMS.search(item.name): + if (not interactive + or ask('Copy: "{}{}" ?'.format(rel_path, item.name))): + root_items.append(item.path) + if REGEX_WINDOWS_OLD.search(item.name): + win_olds.append(item) + if root_items: + selected_items.append({ + 'Message': '{}Root Items...'.format(rel_path), + 'Items': root_items.copy(), + 'Destination': dest_path}) + + # Fonts + if os.path.exists(r'{}\Windows\Fonts'.format(source_path)): + selected_items.append({ + 'Message': '{}Fonts...'.format(rel_path), + 'Items': [r'{}\Windows\Fonts'.format(rel_path)], + 'Destination': r'{}\Windows'.format(dest_path)}) + + # Registry + registry_items = [] + for folder in ['config', 'OEM']: + folder = r'Windows\System32\{}'.format(folder) + folder = os.path.join(source_path, folder) + if os.path.exists(folder): + registry_items.append(folder) + if registry_items: + selected_items.append({ + 'Message': '{}Registry...'.format(rel_path), + 'Items': registry_items.copy(), + 'Destination': r'{}\Windows\System32'.format(dest_path)}) + + # Windows.old(s) + for old in win_olds: + selected_items.append( + scan_source_path( + old.path, dest_path, rel_path=old.name, interactive=False)) + + # Done + return selected_items + +def scan_source_wim(source_wim, dest_path, rel_path=None, interactive=True): + """Scan source WIM file for files/folders to transfer, returns list. + + This will scan the root and (recursively) any Windows.old folders.""" + rel_path = '\\' + rel_path if rel_path else '' + selected_items = [] + win_olds = [] + + # Scan source + extract_item('wimlib', silent=True) + cmd = [ + global_vars['Tools']['wimlib-imagex'], 'dir', + source_wim, '1'] + try: + file_list = run_program(cmd) + except subprocess.CalledProcessError: + print_error('ERROR: Failed to get file list.') + raise + + # Root Items + file_list = [i.strip() + for i in file_list.stdout.decode('utf-8', 'ignore').splitlines() + if i.count('\\') == 1 and i.strip() != '\\'] + root_items = [] + if rel_path: + file_list = [i.replace(rel_path, '') for i in file_list] + for item in file_list: + if REGEX_INCL_ROOT_ITEMS.search(item): + root_items.append(item) + elif not REGEX_EXCL_ROOT_ITEMS.search(item): + if (not interactive + or ask('Extract: "{}{}" ?'.format(rel_path, item))): + root_items.append('{}{}'.format(rel_path, item)) + if REGEX_WINDOWS_OLD.search(item): + win_olds.append(item) + if root_items: + selected_items.append({ + 'Message': '{}Root Items...'.format(rel_path), + 'Items': root_items.copy(), + 'Destination': dest_path}) + + # Fonts + if wim_contains(source_wim, r'{}Windows\Fonts'.format(rel_path)): + selected_items.append({ + 'Message': '{}Fonts...'.format(rel_path), + 'Items': [r'{}\Windows\Fonts'.format(rel_path)], + 'Destination': dest_path}) + + # Registry + registry_items = [] + for folder in ['config', 'OEM']: + folder = r'{}Windows\System32\{}'.format(rel_path, folder) + if wim_contains(source_wim, folder): + registry_items.append(folder) + if registry_items: + selected_items.append({ + 'Message': '{}Registry...'.format(rel_path), + 'Items': registry_items.copy(), + 'Destination': dest_path}) + + # Windows.old(s) + for old in win_olds: + scan_source_wim(source_wim, dest_path, rel_path=old, interactive=False) + + # Done + return selected_items + +def select_destination(folder_path, prompt='Select destination'): + """Select destination drive, returns path as string.""" + disk = select_volume(prompt) + if 'fixed' not in disk['Disk'].opts: + folder_path = folder_path.replace('\\', '-') + path = '{disk}{folder_path}_{Date}'.format( + disk = disk['Disk'].mountpoint, + folder_path = folder_path, + **global_vars) + + # Avoid merging with existing folder + path = non_clobber_rename(path) + os.makedirs(path, exist_ok=True) + + return path + +def select_source(ticket_number): + """Select backup from those found on the BACKUP_SERVERS for the ticket.""" + selected_source = None + sources = [] + mount_backup_shares() + + # Check for ticket folders on servers + for server in BACKUP_SERVERS: + if server['Mounted']: + print_standard('Scanning {}...'.format(server['Name'])) + for d in os.scandir(r'\\{IP}\{Share}'.format(**server)): + if (d.is_dir() + and d.name.lower().startswith(ticket_number.lower())): + # Add folder to sources + sources.append({ + 'Name': '{:9}| File-Based: [DIR] {}'.format( + server['Name'], d.name), + 'Server': server, + 'Source': d}) + + # Check for images and subfolders + for ticket_path in sources.copy(): + for item in os.scandir(ticket_path['Source'].path): + if item.is_dir(): + # Add folder to sources + sources.append({ + 'Name': r'{:9}| File-Based: [DIR] {}\{}'.format( + ticket_path['Server']['Name'], # Server + ticket_path['Source'].name, # Ticket folder + item.name, # Sub-folder + ), + 'Server': ticket_path['Server'], + 'Source': item}) + + # Check for images in folder + for subitem in os.scandir(item.path): + if REGEX_WIM_FILE.search(item.name): + # Add image to sources + try: + size = human_readable_size(item.stat().st_size) + except Exception: + size = ' ? ?' # unknown + sources.append({ + 'Disabled': bool(not is_valid_wim_file(subitem)), + 'Name': r'{:9}| Image-Based: {:>7} {}\{}\{}'.format( + ticket_path['Server']['Name'], # Server + size, # Size (duh) + ticket_path['Source'].name, # Ticket folder + item.name, # Sub-folder + subitem.name, # Image file + ), + 'Server': ticket_path['Server'], + 'Source': subitem}) + elif REGEX_WIM_FILE.search(item.name): + # Add image to sources + try: + size = human_readable_size(item.stat().st_size) + except Exception: + size = ' ? ?' # unknown + sources.append({ + 'Disabled': bool(not is_valid_wim_file(item)), + 'Name': r'{:9}| Image-Based: {:>7} {}\{}'.format( + ticket_path['Server']['Name'], # Server + size, # Size (duh) + ticket_path['Source'].name, # Ticket folder + item.name, # Image file + ), + 'Server': ticket_path['Server'], + 'Source': item}) + # Check for local sources + print_standard('Scanning for local sources...') + set_thread_error_mode(silent=True) # Prevents "No disk" popups + sys_drive = global_vars['Env']['SYSTEMDRIVE'] + for d in psutil.disk_partitions(): + if re.search(r'^{}'.format(sys_drive), d.mountpoint, re.IGNORECASE): + # Skip current OS drive + continue + if 'fixed' in d.opts: + # Skip DVD, etc + sources.append({ + 'Name': '{:9}| File-Based: [DISK] {}'.format( + ' Local', d.mountpoint), + 'Source': LocalDisk(d)}) + set_thread_error_mode(silent=False) # Return to normal + + # Build Menu + sources.sort(key=itemgetter('Name')) + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + + # Select backup from sources + if len(sources) > 0: + selection = menu_select( + 'Which backup are we using?', + main_entries=sources, + action_entries=actions, + disabled_label='DAMAGED') + if selection == 'Q': + umount_backup_shares() + exit_script() + else: + selected_source = sources[int(selection)-1]['Source'] + else: + print_error('ERROR: No backups found for ticket: {}.'.format( + ticket_number)) + umount_backup_shares() + pause("Press Enter to exit...") + exit_script() + + # Done + return selected_source + +def select_volume(title='Select disk', auto_select=True): + """Select disk from attached disks. returns dict.""" + actions = [{'Name': 'Quit', 'Letter': 'Q'}] + disks = [] + + # Build list of disks + set_thread_error_mode(silent=True) # Prevents "No disk" popups + for d in psutil.disk_partitions(): + info = { + 'Disk': d, + 'Name': d.mountpoint} + try: + usage = psutil.disk_usage(d.device) + free = '{free} / {total} available'.format( + free = human_readable_size(usage.free, 2), + total = human_readable_size(usage.total, 2)) + except Exception: + # Meh, leaving unsupported destinations out + pass + # free = 'Unknown' + # info['Disabled'] = True + else: + info['Display Name'] = '{} ({})'.format(info['Name'], free) + disks.append(info) + set_thread_error_mode(silent=False) # Return to normal + + # Skip menu? + if len(disks) == 1 and auto_select: + return disks[0] + + # Show menu + selection = menu_select(title, main_entries=disks, action_entries=actions) + if selection == 'Q': + exit_script() + else: + return disks[int(selection)-1] + +def set_thread_error_mode(silent=True): + """Disable or Enable Windows error message dialogs. + + Disable when scanning for disks to avoid popups for empty cardreaders, etc + """ + # Code borrowed from: https://stackoverflow.com/a/29075319 + kernel32 = ctypes.WinDLL('kernel32') + + if silent: + kernel32.SetThreadErrorMode(SEM_FAIL, ctypes.byref(SEM_NORMAL)) + else: + kernel32.SetThreadErrorMode(SEM_NORMAL, ctypes.byref(SEM_NORMAL)) + +def transfer_source(source_obj, dest_path, selected_items): + """Transfer, or extract, files/folders from source to destination.""" + if source_obj.is_dir(): + # Run FastCopy for each selection "group" + for group in selected_items: + try_and_print(message=group['Message'], + function=run_fast_copy, cs='Done', + items=group['Items'], + dest=group['Destination']) + else: + if REGEX_WIM_FILE.search(source_obj.name): + # Extract files from WIM + for group in selected_items: + try_and_print(message=group['Message'], + function=run_wimextract, cs='Done', + source=source_obj.path, + items=group['Items'], + dest=group['Destination']) + else: + print_error('ERROR: Unsupported image: {}'.format(source_obj.path)) + raise GenericError + +def umount_backup_shares(): + """Unnount the backup shares regardless of current status.""" + for server in BACKUP_SERVERS: + umount_network_share(server) + +def umount_network_share(server): + """Unnount a network share defined by server.""" + cmd = r'net use \\{IP}\{Share} /delete'.format(**server) + cmd = cmd.split(' ') + try: + run_program(cmd) + except Exception: + print_error(r'Failed to umount \\{Name}\{Share}.'.format(**server)) + sleep(1) + else: + print_info('Umounted {Name}'.format(**server)) + server['Mounted'] = False + +def wim_contains(source_path, file_path): + """Check if the WIM contains a file or folder.""" + _cmd = [ + global_vars['Tools']['wimlib-imagex'], 'dir', + source_path, '1', + '--path={}'.format(file_path), + '--one-file-only'] + try: + run_program(_cmd) + except subprocess.CalledProcessError: + return False + else: + return True + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py similarity index 97% rename from Scripts/functions/disk.py rename to .bin/Scripts/functions/disk.py index eb2bda4f..78d08c3c 100644 --- a/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -1,366 +1,366 @@ -# Wizard Kit PE: Functions - Disk - -from functions.common import * -import partition_uids - -# Regex -REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) -REGEX_DISK_GPT = re.compile( - r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', - re.IGNORECASE) -REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) -REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) - -def assign_volume_letters(): - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - script.write('select volume {}\n'.format(vol['Number'])) - script.write('assign\n') - - # Remove current letters - remove_volume_letters() - - # Run script - try: - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - except subprocess.CalledProcessError: - pass - -def get_boot_mode(): - boot_mode = 'Legacy' - try: - reg_key = winreg.OpenKey( - winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Control') - reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] - if reg_value == 2: - boot_mode = 'UEFI' - except: - boot_mode = 'Unknown' - - return boot_mode - -def get_disk_details(disk): - details = {} - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('detail disk\n') - - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines - tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] - # Set disk name - details['Name'] = tmp[4] - # Split each line on ':' skipping those without ':' - tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - return details - -def get_disks(): - disks = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list disk\n') - - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append disk numbers - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output): - num = tmp[0] - size = human_readable_size(tmp[1]) - disks.append({'Number': num, 'Size': size}) - - return disks - -def get_partition_details(disk, partition): - details = {} - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('select partition {}\n'.format(partition['Number'])) - script.write('detail partition\n') - - # Diskpart details - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Get volume letter or RAW status - tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output) - if tmp: - if tmp.group(1).upper() == 'RAW': - details['FileSystem'] = RAW - else: - details['Letter'] = tmp.group(1) - # Remove empty lines from output - tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] - # Split each line on ':' skipping those without ':' - tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Get MBR type / GPT GUID for extra details on "Unknown" partitions - guid = partition_uids.lookup_guid(details['Type']) - if guid: - details.update({ - 'Description': guid.get('Description', ''), - 'OS': guid.get('OS', '')}) - - if 'Letter' in details: - # Disk usage - tmp = shutil.disk_usage('{}:\\'.format(details['Letter'])) - details['Used Space'] = human_readable_size(tmp.used) - - # fsutil details - cmd = [ - 'fsutil', - 'fsinfo', - 'volumeinfo', - '{}:'.format(details['Letter']) - ] - try: - output = run_program(cmd) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Remove empty lines from output - tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] - # Add "Feature" lines - details['File System Features'] = [s.strip() for s in tmp - if ':' not in s] - # Split each line on ':' skipping those without ':' - tmp = [s.split(':') for s in tmp if ':' in s] - # Add key/value pairs to the details variable and return dict - details.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Set Volume Name - details['Name'] = details.get('Volume Name', '') - - # Set FileSystem Type - if details.get('FileSystem', '') != 'RAW': - details['FileSystem'] = details.get('File System Name', 'Unknown') - - return details - -def get_partitions(disk): - partitions = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('list partition\n') - - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append partition numbers - regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+' - for tmp in re.findall(regex, output, re.IGNORECASE): - num = tmp[0] - size = human_readable_size(tmp[1]) - partitions.append({'Number': num, 'Size': size}) - - return partitions - -def get_table_type(disk): - part_type = 'Unknown' - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('uniqueid disk\n') - - try: - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - if REGEX_DISK_GPT.search(output): - part_type = 'GPT' - elif REGEX_DISK_MBR.search(output): - part_type = 'MBR' - elif REGEX_DISK_RAW.search(output): - part_type = 'RAW' - else: - part_type = 'Unknown - - return part_type - -def get_volumes(): - vols = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list volume\n') - - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() - except subprocess.CalledProcessError: - pass - else: - # Append volume numbers - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output): - vols.append({'Number': tmp[0], 'Letter': tmp[1]}) - - return vols - -def is_bad_partition(par): - return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']) - -def prep_disk_for_formatting(disk=None): - disk['Format Warnings'] = '\n' - width = len(str(len(disk['Partitions']))) - - # Bail early - if disk is None: - raise Exception('Disk not provided.') - - # Set boot method and partition table type - disk['Use GPT'] = True - if (get_boot_mode() == 'UEFI'): - if (not ask("Setup Windows to use UEFI booting?")): - disk['Use GPT'] = False - else: - if (ask("Setup Windows to use BIOS/Legacy booting?")): - disk['Use GPT'] = False - - # Set Display and Warning Strings - if len(disk['Partitions']) == 0: - disk['Format Warnings'] += 'No partitions found\n' - for partition in disk['Partitions']: - display = ' Partition {num:>{width}}:\t{size} {fs}'.format( - num = partition['Number'], - width = width, - size = partition['Size'], - fs = partition['FileSystem']) - - if is_bad_partition(partition): - # Set display string using partition description & OS type - display += '\t\t{q}{name}{q}\t{desc} ({os})'.format( - display = display, - q = '"' if partition['Name'] != '' else '', - name = partition['Name'], - desc = partition['Description'], - os = partition['OS']) - else: - # List space used instead of partition description & OS type - display += ' (Used: {used})\t{q}{name}{q}'.format( - used = partition['Used Space'], - q = '"' if partition['Name'] != '' else '', - name = partition['Name']) - # For all partitions - partition['Display String'] = display - -def reassign_volume_letter(letter, new_letter='I'): - if not letter: - # Ignore - return None - try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select volume {}\n'.format(letter)) - script.write('remove noerr\n') - script.write('assign letter={}\n'.format(new_letter)) - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - except subprocess.CalledProcessError: - pass - else: - return new_letter - -def remove_volume_letters(keep=None): - if not keep: - keep = '' - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - if vol['Letter'].upper() != keep.upper(): - script.write('select volume {}\n'.format(vol['Number'])) - script.write('remove noerr\n') - - # Run script - try: - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - except subprocess.CalledProcessError: - pass - -def scan_disks(): - """Get details about the attached disks""" - disks = get_disks() - - # Get disk details - for disk in disks: - # Get partition style - disk['Table'] = get_table_type(disk) - - # Get disk name/model and physical details - disk.update(get_disk_details(disk)) - - # Get partition info for disk - disk['Partitions'] = get_partitions(disk) - - for partition in disk['Partitions']: - # Get partition details - partition.update(get_partition_details(disk, partition)) - - # Done - return disks - -def select_disk(title='Which disk?', disks): - """Select a disk from the attached disks""" - # Build menu - disk_options = [] - for disk in disks: - display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - pwidth=len(str(len(disk['Partitions']))) - for partition in disk['Partitions']: - # Main text - p_name = 'Partition {num:>{width}}: {size} ({fs})'.format( - num = partition['Number'], - width = pwidth, - size = partition['Size'], - fs = partition['FileSystem']) - if partition['Name']: - p_name += '\t"{}"'.format(partition['Name']) - - # Show unsupported partition(s) - if is_bad_partition(partition): - p_display_name = '{YELLOW}{display}{CLEAR}'.format( - display=p_name, **COLORS) - - display_name += '\n\t\t\t{}'.format(display_name) - if not disk['Partitions']: - display_name += '\n\t\t\t{}No partitions found.{}'.format( - COLORS['YELLOW'], COLORS['CLEAR']) - - disk_options.append({'Name': display_name, 'Disk': disk}) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select( - title = title, - main_entries = disk_options, - action_entries = actions) - - if (selection.isnumeric()): - return disk_options[int(selection)-1]['Disk'] - elif (selection == 'M'): - raise GeneralAbort - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - Disk + +from functions.common import * +import partition_uids + +# Regex +REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) +REGEX_DISK_GPT = re.compile( + r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', + re.IGNORECASE) +REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) +REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) + +def assign_volume_letters(): + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + script.write('select volume {}\n'.format(vol['Number'])) + script.write('assign\n') + + # Remove current letters + remove_volume_letters() + + # Run script + try: + run_program(['diskpart', '/s', DISKPART_SCRIPT]) + except subprocess.CalledProcessError: + pass + +def get_boot_mode(): + boot_mode = 'Legacy' + try: + reg_key = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + boot_mode = 'UEFI' + except: + boot_mode = 'Unknown' + + return boot_mode + +def get_disk_details(disk): + details = {} + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('detail disk\n') + + try: + # Run script + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] + # Set disk name + details['Name'] = tmp[4] + # Split each line on ':' skipping those without ':' + tmp = [s.split(':') for s in tmp if ':' in s] + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + return details + +def get_disks(): + disks = [] + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list disk\n') + + try: + # Run script + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append disk numbers + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output): + num = tmp[0] + size = human_readable_size(tmp[1]) + disks.append({'Number': num, 'Size': size}) + + return disks + +def get_partition_details(disk, partition): + details = {} + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('select partition {}\n'.format(partition['Number'])) + script.write('detail partition\n') + + # Diskpart details + try: + # Run script + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Get volume letter or RAW status + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output) + if tmp: + if tmp.group(1).upper() == 'RAW': + details['FileSystem'] = RAW + else: + details['Letter'] = tmp.group(1) + # Remove empty lines from output + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] + # Split each line on ':' skipping those without ':' + tmp = [s.split(':') for s in tmp if ':' in s] + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + guid = partition_uids.lookup_guid(details['Type']) + if guid: + details.update({ + 'Description': guid.get('Description', ''), + 'OS': guid.get('OS', '')}) + + if 'Letter' in details: + # Disk usage + tmp = shutil.disk_usage('{}:\\'.format(details['Letter'])) + details['Used Space'] = human_readable_size(tmp.used) + + # fsutil details + cmd = [ + 'fsutil', + 'fsinfo', + 'volumeinfo', + '{}:'.format(details['Letter']) + ] + try: + output = run_program(cmd) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines from output + tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] + # Add "Feature" lines + details['File System Features'] = [s.strip() for s in tmp + if ':' not in s] + # Split each line on ':' skipping those without ':' + tmp = [s.split(':') for s in tmp if ':' in s] + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Set Volume Name + details['Name'] = details.get('Volume Name', '') + + # Set FileSystem Type + if details.get('FileSystem', '') != 'RAW': + details['FileSystem'] = details.get('File System Name', 'Unknown') + + return details + +def get_partitions(disk): + partitions = [] + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('list partition\n') + + try: + # Run script + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append partition numbers + regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+' + for tmp in re.findall(regex, output, re.IGNORECASE): + num = tmp[0] + size = human_readable_size(tmp[1]) + partitions.append({'Number': num, 'Size': size}) + + return partitions + +def get_table_type(disk): + part_type = 'Unknown' + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select disk {}\n'.format(disk['Number'])) + script.write('uniqueid disk\n') + + try: + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + if REGEX_DISK_GPT.search(output): + part_type = 'GPT' + elif REGEX_DISK_MBR.search(output): + part_type = 'MBR' + elif REGEX_DISK_RAW.search(output): + part_type = 'RAW' + else: + part_type = 'Unknown + + return part_type + +def get_volumes(): + vols = [] + with open(DISKPART_SCRIPT, 'w') as script: + script.write('list volume\n') + + try: + # Run script + output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) + output = output.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append volume numbers + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output): + vols.append({'Number': tmp[0], 'Letter': tmp[1]}) + + return vols + +def is_bad_partition(par): + return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']) + +def prep_disk_for_formatting(disk=None): + disk['Format Warnings'] = '\n' + width = len(str(len(disk['Partitions']))) + + # Bail early + if disk is None: + raise Exception('Disk not provided.') + + # Set boot method and partition table type + disk['Use GPT'] = True + if (get_boot_mode() == 'UEFI'): + if (not ask("Setup Windows to use UEFI booting?")): + disk['Use GPT'] = False + else: + if (ask("Setup Windows to use BIOS/Legacy booting?")): + disk['Use GPT'] = False + + # Set Display and Warning Strings + if len(disk['Partitions']) == 0: + disk['Format Warnings'] += 'No partitions found\n' + for partition in disk['Partitions']: + display = ' Partition {num:>{width}}:\t{size} {fs}'.format( + num = partition['Number'], + width = width, + size = partition['Size'], + fs = partition['FileSystem']) + + if is_bad_partition(partition): + # Set display string using partition description & OS type + display += '\t\t{q}{name}{q}\t{desc} ({os})'.format( + display = display, + q = '"' if partition['Name'] != '' else '', + name = partition['Name'], + desc = partition['Description'], + os = partition['OS']) + else: + # List space used instead of partition description & OS type + display += ' (Used: {used})\t{q}{name}{q}'.format( + used = partition['Used Space'], + q = '"' if partition['Name'] != '' else '', + name = partition['Name']) + # For all partitions + partition['Display String'] = display + +def reassign_volume_letter(letter, new_letter='I'): + if not letter: + # Ignore + return None + try: + # Run script + with open(DISKPART_SCRIPT, 'w') as script: + script.write('select volume {}\n'.format(letter)) + script.write('remove noerr\n') + script.write('assign letter={}\n'.format(new_letter)) + run_program(['diskpart', '/s', DISKPART_SCRIPT]) + except subprocess.CalledProcessError: + pass + else: + return new_letter + +def remove_volume_letters(keep=None): + if not keep: + keep = '' + with open(DISKPART_SCRIPT, 'w') as script: + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.write('select volume {}\n'.format(vol['Number'])) + script.write('remove noerr\n') + + # Run script + try: + run_program(['diskpart', '/s', DISKPART_SCRIPT]) + except subprocess.CalledProcessError: + pass + +def scan_disks(): + """Get details about the attached disks""" + disks = get_disks() + + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for partition in disk['Partitions']: + # Get partition details + partition.update(get_partition_details(disk, partition)) + + # Done + return disks + +def select_disk(title='Which disk?', disks): + """Select a disk from the attached disks""" + # Build menu + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + pwidth=len(str(len(disk['Partitions']))) + for partition in disk['Partitions']: + # Main text + p_name = 'Partition {num:>{width}}: {size} ({fs})'.format( + num = partition['Number'], + width = pwidth, + size = partition['Size'], + fs = partition['FileSystem']) + if partition['Name']: + p_name += '\t"{}"'.format(partition['Name']) + + # Show unsupported partition(s) + if is_bad_partition(partition): + p_display_name = '{YELLOW}{display}{CLEAR}'.format( + display=p_name, **COLORS) + + display_name += '\n\t\t\t{}'.format(display_name) + if not disk['Partitions']: + display_name += '\n\t\t\t{}No partitions found.{}'.format( + COLORS['YELLOW'], COLORS['CLEAR']) + + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select( + title = title, + main_entries = disk_options, + action_entries = actions) + + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + raise GeneralAbort + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/partition_uids.py b/.bin/Scripts/functions/partition_uids.py similarity index 98% rename from Scripts/functions/partition_uids.py rename to .bin/Scripts/functions/partition_uids.py index e31117db..8c293f02 100644 --- a/Scripts/functions/partition_uids.py +++ b/.bin/Scripts/functions/partition_uids.py @@ -1,325 +1,325 @@ -# Wizard Kit PE: Functions - PARTITION UIDs -# sources: https://en.wikipedia.org/wiki/GUID_Partition_Table -# https://en.wikipedia.org/wiki/Partition_type - -PARTITION_UIDS = { - '00': {'OS': 'All', 'Description': 'Empty partition entry'}, - '01': {'OS': 'DOS 2.0+', 'Description': 'FAT12 as primary partition in first physical 32 MB of disk or as logical drive anywhere on disk (else use 06hinstead)'}, - '02': {'OS': 'XENIX', 'Description': 'XENIX root'}, - '03': {'OS': 'XENIX', 'Description': 'XENIX usr'}, - '04': {'OS': 'DOS 3.0+', 'Description': 'FAT16 with less than 65536 sectors (32 MB). As primary partition it must reside in first physical 32 MB of disk, or as logical drive anywhere on disk (else use 06h instead).'}, - '05': {'OS': 'DOS (3.2) 3.3+ / SpeedStor', 'Description': 'Extended partition with CHS addressing. It must reside in first physical 8 GB of disk, else use 0Fh instead / can occur in SpeedStor MBRs'}, - '06': {'OS': 'DOS 3.31+', 'Description': 'FAT16B with 65536 or more sectors. It must reside in first physical 8 GB of disk, unless used for logical drives in an 0Fh extended partition (else use 0Eh instead). Also used for FAT12 and FAT16 volumes in primary partitions if they are not residing in first physical 32 MB of disk.'}, - '07': {'OS': 'OS/2 1.2+ / OS/2 1.2+, Windows NT / Windows NT / Windows Embedded CE / QNX 2', 'Description': 'IFS / HPFS / NTFS / exFAT / QNX "qnx" (7) (pre-1988 only)'}, - '08': {'OS': 'Commodore MS-DOS 3.x / OS/2 1.0-1.3 / AIX / QNX 1.x/2.x', 'Description': 'Logical sectored FAT12 or FAT16 / OS/2 (FAT?) / AIX boot/split / SplitDrive / QNX "qny" (8) / partition spanning multiple drives'}, - '09': {'OS': 'AIX / QNX 1.x/2.x / Coherent / OS-9', 'Description': 'AIX data/boot / QNX "qnz" (9) / Coherent file system / OS-9 RBF'}, - '0A': {'OS': 'OS/2 / Coherent', 'Description': 'OS/2 Boot Manager / Coherent swap partition'}, - '0B': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with CHS addressing'}, - '0C': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with LBA'}, - '0D': {'OS': 'Silicon Safe', 'Description': 'Reserved'}, - '0E': {'OS': 'DOS 7.0+', 'Description': 'FAT16B with LBA'}, - '0F': {'OS': 'DOS 7.0+', 'Description': 'Extended partition with LBA'}, - '10': {'OS': 'OPUS', 'Description': 'Unknown'}, - '11': {'OS': 'Leading Edge MS-DOS 3.x / OS/2 Boot Manager', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT12 '}, - '12': {'OS': 'Compaq Contura', 'Description': 'configuration partition (bootable FAT) / configuration partition / hibernation partition / diagnostics and firmware partition (bootable FAT) / service partition (bootable FAT) / Rescue and Recovery partition'}, - '14': {'OS': 'AST MS-DOS 3.x / OS/2 Boot Manager / Maverick OS', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT16 / Omega file system'}, - '15': {'OS': 'OS/2 Boot Manager / Maverick OS', 'Description': 'Hidden extended partition with CHS addressing / swap'}, - '16': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16B '}, - '17': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden IFS / Hidden HPFS / Hidden NTFS / Hidden exFAT '}, - '18': {'OS': 'AST Windows', 'Description': 'AST Zero Volt Suspend or SmartSleep partition'}, - '19': {'OS': 'Willowtech Photon coS', 'Description': 'Willowtech Photon coS'}, - '1B': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 '}, - '1C': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 with LBA '}, - '1E': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16 with LBA '}, - '1F': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden extended partition with LBA addressing '}, - '20': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile update XIP / Willowsoft Overture File System (OFS1)'}, - '21': {'OS': 'Oxygen', 'Description': 'HP Volume Expansion (SpeedStor) / FSo2 (Oxygen File System)'}, - '22': {'OS': 'Oxygen', 'Description': 'Oxygen Extended Partition Table'}, - '23': {'OS': 'Windows Mobile', 'Description': 'Reserved / Windows Mobile boot XIP'}, - '24': {'OS': 'NEC MS-DOS 3.30', 'Description': 'Logical sectored FAT12 or FAT16 '}, - '25': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile IMGFS[citation needed]'}, - '26': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '27': {'OS': 'Windows / PQservice / MirOS BSD / RooterBOOT', 'Description': 'Windows Recovery Environment (RE) partition (hidden NTFS partition type 07h) / FAT32 or NTFS rescue partition / MirOS partition / RooterBOOT kernel partition (contains a raw ELF Linux kernel, no file system)'}, - '2A': {'OS': 'AtheOS', 'Description': 'AtheOS file system (AthFS, AFS) (an extension of BFS, see 2Bh and EBh) / Reserved'}, - '2B': {'OS': 'SyllableOS', 'Description': 'SyllableSecure (SylStor), a variant of AthFS (an extension of BFS, see 2Ah and EBh)'}, - '31': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '32': {'OS': 'NOS', 'Description': 'Unknown'}, - '33': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '34': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '35': {'OS': 'OS/2 Warp Server /eComStation', 'Description': 'JFS (OS/2 implementation of AIX Journaling File system)'}, - '36': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '38': {'OS': 'THEOS', 'Description': 'THEOS version 3.2, 2 GB partition'}, - '39': {'OS': 'Plan 9 / THEOS', 'Description': 'Plan 9 edition 3 partition (sub-partitions described in second sector of partition) / THEOS version 4 spanned partition'}, - '3A': {'OS': 'THEOS', 'Description': 'THEOS version 4, 4 GB partition'}, - '3B': {'OS': 'THEOS', 'Description': 'THEOS version 4 extended partition'}, - '3C': {'OS': 'PartitionMagic', 'Description': 'PqRP (PartitionMagic or DriveImage in progress)'}, - '3D': {'OS': 'PartitionMagic', 'Description': 'Hidden NetWare'}, - '3F': {'OS': 'OS/32', 'Description': 'Unknown'}, - '40': {'OS': 'PICK / Venix', 'Description': 'PICK R83 / Venix 80286'}, - '41': {'OS': 'Personal RISC / Linux / PowerPC', 'Description': 'Personal RISC Boot / Old Linux/Minix (disk shared with DR DOS 6.0) / PPC PReP (Power PC Reference Platform) Boot'}, - '42': {'OS': 'SFS / Linux / Windows 2000, XP, etc.', 'Description': 'Secure File system (SFS) / Old Linux swap (disk shared with DR DOS 6.0) / Dynamic extended partition marker'}, - '43': {'OS': 'Linux', 'Description': 'Old Linux native (disk shared with DR DOS 6.0) '}, - '44': {'OS': 'GoBack', 'Description': 'Norton GoBack, WildFile GoBack, Adaptec GoBack, Roxio GoBack'}, - '45': {'OS': 'Boot-US / EUMEL/ELAN', 'Description': 'Priam / Boot-US boot manager (1 cylinder) / EUMEL/ELAN (L2)'}, - '46': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, - '47': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, - '48': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2), ERGOS L3'}, - '4A': {'OS': 'AdaOS / ALFS/THIN', 'Description': 'Aquila / ALFS/THIN advanced lightweight file system for DOS'}, - '4C': {'OS': 'ETH Oberon', 'Description': 'Aos (A2) file system (76)'}, - '4D': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Primary QNX POSIX volume on disk (77)'}, - '4E': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Secondary QNX POSIX volume on disk (78)'}, - '4F': {'OS': 'QNX 4.x, Neutrino / ETH Oberon', 'Description': 'Tertiary QNX POSIX volume on disk (79) / boot / native file system (79)'}, - '50': {'OS': 'ETH Oberon / Disk Manager 4 / LynxOS / Novell', 'Description': 'Alternative native file system (80) / Read-only partition (old) / Lynx RTOS'}, - '51': {'OS': 'Disk Manager 4-6', 'Description': 'Read-write partition (Aux 1)'}, - '52': {'OS': 'CP/M-80 / System V/AT, V/386', 'Description': 'CP/M-80'}, - '53': {'OS': 'Disk Manager 6', 'Description': 'Auxiliary 3 (WO)'}, - '54': {'OS': 'Disk Manager 6', 'Description': 'Dynamic Drive Overlay (DDO)'}, - '55': {'OS': 'EZ-Drive', 'Description': 'EZ-Drive, Maxtor, MaxBlast, or DriveGuide INT 13h redirector volume'}, - '56': {'OS': 'AT&T MS-DOS 3.x / EZ-Drive / VFeature', 'Description': 'Logical sectored FAT12 or FAT16 / Disk Manager partition converted to EZ-BIOS / VFeature partitionned volume'}, - '57': {'OS': 'DrivePro', 'Description': 'VNDI partition'}, - '5C': {'OS': 'EDISK', 'Description': 'Priam EDisk Partitioned Volume '}, - '61': {'OS': 'SpeedStor', 'Description': 'Unknown'}, - '63': {'OS': 'Unix', 'Description': 'SCO Unix, ISC, UnixWare, AT&T System V/386, ix, MtXinu BSD 4.3 on Mach, GNU HURD'}, - '64': {'OS': 'SpeedStor / NetWare', 'Description': 'NetWare File System 286/2 / PC-ARMOUR'}, - '65': {'OS': 'NetWare', 'Description': 'NetWare File System 386'}, - '66': {'OS': 'NetWare / NetWare', 'Description': 'NetWare File System 386 / Storage Management Services (SMS)'}, - '67': {'OS': 'NetWare', 'Description': 'Wolf Mountain'}, - '68': {'OS': 'NetWare', 'Description': 'Unknown'}, - '69': {'OS': 'NetWare 5 / NetWare', 'Description': 'Novell Storage Services (NSS)'}, - '6E': {'Description': 'Unknown'}, - '70': {'OS': 'DiskSecure', 'Description': 'DiskSecure multiboot'}, - '71': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '72': {'OS': 'APTI conformant systems / Unix V7/x86', 'Description': 'APTI alternative FAT12 (CHS, SFN) / V7/x86'}, - '73': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '74': {'OS': 'Microsoft, IBM', 'Description': 'Reserved / Scramdisk'}, - '75': {'OS': 'PC/IX', 'Description': 'Unknown'}, - '76': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, - '77': {'OS': 'Novell', 'Description': 'VNDI, M2FS, M2CS'}, - '78': {'OS': 'Geurt Vos', 'Description': 'XOSL bootloader file system'}, - '79': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (CHS, SFN) '}, - '7A': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (LBA, SFN) '}, - '7B': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16B (CHS, SFN) '}, - '7C': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (LBA, SFN) '}, - '7D': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (CHS, SFN) '}, - '7E': {'OS': 'F.I.X. (claim) / PrimoCache', 'Description': 'Level 2 cache'}, - '7F': {'OS': 'Varies', 'Description': 'Alternative OS Development Partition Standard - reserved for individual or local use and temporary or experimental projects'}, - '80': {'OS': 'Minix 1.1-1.4a', 'Description': 'Minix file system (old)'}, - '81': {'OS': 'Minix 1.4b+ / Linux', 'Description': 'MINIX file system / Mitac Advanced Disk Manager'}, - '82': {'OS': 'Linux / Sun Microsystems', 'Description': 'Linux swap space / Solaris x86 (for Sun disklabels up to 2005) / Prime'}, - '83': {'OS': 'GNU/Linux', 'Description': 'Any native Linux file system '}, - '84': {'OS': 'OS/2 / Windows 7', 'Description': 'APM hibernation (suspend to disk, S2D) / Hidden C: (FAT16) / Rapid Start technology'}, - '85': {'OS': 'GNU/Linux', 'Description': 'Linux extended '}, - '86': {'OS': 'Windows NT 4 Server / Linux', 'Description': 'Fault-tolerant FAT16B mirrored volume set / Linux RAID superblock with auto-detect (old)'}, - '87': {'OS': 'Windows NT 4 Server', 'Description': 'Fault-tolerant HPFS/NTFS mirrored volume set '}, - '88': {'OS': 'GNU/Linux', 'Description': 'Linux plaintext partition table'}, - '8A': {'OS': 'AiR-BOOT', 'Description': 'Linux kernel image'}, - '8B': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, - '8C': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, - '8D': {'OS': 'Free FDISK', 'Description': 'Hidden FAT12 '}, - '8E': {'OS': 'Linux', 'Description': 'Linux LVM'}, - '90': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, - '91': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with CHS addressing '}, - '92': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16B '}, - '93': {'OS': 'Amoeba / Linux', 'Description': 'Amoeba native file system / Hidden Linux file system'}, - '94': {'OS': 'Amoeba', 'Description': 'Amoeba bad block table'}, - '95': {'OS': 'EXOPC', 'Description': 'EXOPC native'}, - '96': {'OS': 'CHRP', 'Description': 'ISO-9660 file system'}, - '97': {'OS': 'Free FDISK', 'Description': 'Hidden FAT32 '}, - '98': {'OS': 'Free FDISK / ROM-DOS', 'Description': 'Hidden FAT32 / service partition (bootable FAT) ROM-DOS SuperBoot / service partition (bootable FAT)'}, - '99': {'OS': 'early Unix', 'Description': 'Unknown'}, - '9A': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, - '9B': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with LBA '}, - '9E': {'OS': 'VSTA / ForthOS', 'Description': 'ForthOS (eForth port)'}, - '9F': {'OS': 'BSD/OS 3.0+, BSDI', 'Description': 'Unknown'}, - 'A0': {'OS': 'Hewlett Packard / Phoenix, IBM, Toshiba, Sony', 'Description': 'Diagnostic partition for HP laptops / Hibernate partition'}, - 'A1': {'OS': 'Hewlett Packard / Phoenix, NEC', 'Description': 'HP Volume Expansion (SpeedStor) / Hibernate partition'}, - 'A2': {'OS': 'Cyclone V', 'Description': 'Hard Processor System (HPS) ARM preloader'}, - 'A3': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, - 'A4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, - 'A5': {'OS': 'BSD', 'Description': 'BSD slice (BSD/386, 386BSD, NetBSD (old), FreeBSD)'}, - 'A6': {'OS': 'OpenBSD', 'Description': 'HP Volume Expansion (SpeedStor) / OpenBSD slice'}, - 'A7': {'OS': 'NeXT', 'Description': 'NeXTSTEP'}, - 'A8': {'OS': 'Darwin, Mac OS X', 'Description': 'Apple Darwin, Mac OS X UFS'}, - 'A9': {'OS': 'NetBSD', 'Description': 'NetBSD slice'}, - 'AA': {'OS': 'MS-DOS', 'Description': 'Olivetti MS-DOS FAT12 (1.44 MB) '}, - 'AB': {'OS': 'Darwin, Mac OS X / GO! OS', 'Description': 'Apple Darwin, Mac OS X boot / GO!'}, - 'AD': {'OS': 'RISC OS', 'Description': 'ADFS / FileCore format'}, - 'AE': {'OS': 'ShagOS', 'Description': 'ShagOS file system'}, - 'AF': {'OS': 'ShagOS', 'Description': 'Apple Mac OS X HFS and HFS+ / ShagOS swap'}, - 'B0': {'OS': 'Boot-Star', 'Description': 'Boot-Star dummy partition'}, - 'B1': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, - 'B2': {'OS': 'QNX 6.x', 'Description': 'QNX Neutrino power-safe file system'}, - 'B3': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, - 'B4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, - 'B6': {'OS': 'Windows NT 4 Server', 'Description': 'HP Volume Expansion (SpeedStor) / Corrupted fault-tolerant FAT16B mirrored master volume '}, - 'B7': {'OS': 'BSDI (before 3.0) / Windows NT 4 Server', 'Description': 'BSDI native file system / swap / Corrupted fault-tolerant HPFS/NTFS mirrored master volume '}, - 'B8': {'OS': 'BSDI (before 3.0)', 'Description': 'BSDI swap / native file system'}, - 'BB': {'OS': 'BootWizard, OS Selector / Acronis True Image / Windows NT 4 Server', 'Description': 'PTS BootWizard 4 / OS Selector 5 for hidden partitions other than 01h, 04h, 06h, 07h, 0Bh, 0Ch, 0Eh and unformatted partitions / OEM Secure Zone (corresponds to BCh) / Corrupted fault-tolerant FAT32 mirrored master volume '}, - 'BC': {'OS': 'Windows NT 4 Server / Acronis True Image / Backup Capsule', 'Description': 'Corrupted fault-tolerant FAT32 mirrored master volume / Acronis Secure Zone / Backup Capsule'}, - 'BD': {'OS': 'BonnyDOS/286', 'Description': 'Unknown'}, - 'BE': {'OS': 'Solaris 8', 'Description': 'Solaris 8 boot'}, - 'BF': {'OS': 'Solaris', 'Description': 'Solaris x86 (for Sun disklabels, since 2005)'}, - 'C0': {'OS': 'DR-DOS, Multiuser DOS,REAL/32', 'Description': 'Secured FAT partition (smaller than 32 MB)'}, - 'C1': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT12 '}, - 'C2': {'OS': 'Power Boot', 'Description': 'Hidden Linux native file system'}, - 'C3': {'OS': 'Power Boot', 'Description': 'Hidden Linux swap'}, - 'C4': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT16 '}, - 'C5': {'OS': 'DR DOS 6.0+', 'Description': 'Secured extended partition with CHS addressing '}, - 'C6': {'OS': 'DR DOS 6.0+ / Windows NT 4 Server', 'Description': 'Secured FAT16B / Corrupted fault-tolerant FAT16B mirrored slave volume '}, - 'C7': {'OS': 'Syrinx / Windows NT 4 Server', 'Description': 'Syrinx boot / Corrupted fault-tolerant HPFS/NTFS mirrored slave volume '}, - 'C8': {'Description': 'Reserved for DR-DOS since 1997'}, - 'C9': {'Description': 'Reserved for DR-DOS since 1997'}, - 'CA': {'Description': 'Reserved for DR-DOS since 1997'}, - 'CB': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, - 'CC': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, - 'CD': {'OS': 'CTOS', 'Description': 'Memory dump'}, - 'CE': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured FAT16B '}, - 'CF': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured extended partition with LBA '}, - 'D0': {'OS': 'Multiuser DOS, REAL/32', 'Description': 'Secured FAT partition (larger than 32 MB)'}, - 'D1': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT12 '}, - 'D4': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16 '}, - 'D5': {'OS': 'Multiuser DOS', 'Description': 'Secured extended partition with CHS addressing '}, - 'D6': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16B '}, - 'D8': {'OS': 'Digital Research', 'Description': 'CP/M-86 [citation needed]'}, - 'DA': {'OS': 'Powercopy Backup', 'Description': 'Non-file system data / Shielded disk'}, - 'DB': {'OS': 'CP/M-86,Concurrent CP/M-86,Concurrent DOS / CTOS / D800 / DRMK', 'Description': 'CP/M-86, Concurrent CP/M-86, Concurrent DOS / boot image for x86 supervisor CPU (SCPU) module / FAT32 system restore partition (DSR)'}, - 'DD': {'OS': 'CTOS', 'Description': 'Hidden memory dump'}, - 'DE': {'OS': 'Dell', 'Description': 'FAT16 utility/diagnostic partition'}, - 'DF': {'OS': 'DG/UX / BootIt / Aviion', 'Description': 'DG/UX virtual disk manager / EMBRM'}, - 'E0': {'OS': 'STMicroelectronics', 'Description': 'ST AVFS'}, - 'E1': {'OS': 'SpeedStor', 'Description': 'Extended FAT12 (> 1023 cylinder)'}, - 'E2': {'Description': 'DOS read-only (XFDISK)'}, - 'E3': {'OS': 'SpeedStor', 'Description': 'DOS read-only'}, - 'E4': {'OS': 'SpeedStor', 'Description': 'Extended FAT16 (< 1024 cylinder)'}, - 'E5': {'OS': 'Tandy MS-DOS', 'Description': 'Logical sectored FAT12 or FAT16'}, - 'E6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, - 'E8': {'OS': 'LUKS', 'Description': 'Linux Unified Key Setup'}, - 'EB': {'OS': 'BeOS, Haiku', 'Description': 'BFS'}, - 'EC': {'OS': 'SkyOS', 'Description': 'SkyFS'}, - 'ED': {'OS': 'Sprytix / EDD 4', 'Description': 'EDC loader / GPT hybrid MBR'}, - 'EE': {'OS': 'EFI', 'Description': 'GPT protective MBR'}, - 'EF': {'OS': 'EFI', 'Description': 'EFI system partition can be a FAT12, FAT16, FAT32 (or other) file system'}, - 'F0': {'OS': 'Linux / OS/32', 'Description': 'PA-RISC Linux boot loader. It must reside in first physical 2 GB. / floppy'}, - 'F1': {'OS': 'SpeedStor', 'Description': 'Unknown'}, - 'F2': {'OS': 'Sperry IT MS-DOS 3.x, Unisys MS-DOS 3.3, Digital ResearchDOS Plus 2.1', 'Description': 'Logical sectored FAT12 or FAT16 secondary partition'}, - 'F3': {'OS': 'SpeedStor', 'Description': 'Unknown'}, - 'F4': {'OS': 'SpeedStor / Prologue', 'Description': '"large" DOS partition / single volume partition for NGF or TwinFS'}, - 'F5': {'OS': 'Prologue', 'Description': 'MD0-MD9 multi volume partition for NGF or TwinFS'}, - 'F6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, - 'F7': {'OS': 'O.S.G. / X1', 'Description': 'EFAT / Solid State file system'}, - 'F9': {'OS': 'Linux', 'Description': 'pCache ext2/ext3 persistent cache'}, - 'FA': {'OS': 'Bochs', 'Description': 'x86 emulator'}, - 'FB': {'OS': 'VMware', 'Description': 'VMware VMFS file system partition'}, - 'FC': {'OS': 'VMware', 'Description': 'VMware swap / VMKCORE kernel dump partition'}, - 'FD': {'OS': 'Linux / FreeDOS', 'Description': 'Linux RAID superblock with auto-detect / Reserved for FreeDOS'}, - 'FE': {'OS': 'SpeedStor / LANstep / Windows NT / Linux', 'Description': 'partition > 1024 cylinder / PS/2 IML partition / PS/2 recovery partition (FAT12 reference disk floppy image), / Disk Administration hidden partition / old Linux LVM'}, - 'FF': {'OS': 'XENIX', 'Description': 'XENIX bad block table'}, - '00000000-0000-0000-0000-000000000000': {'Description': 'Unused entry'}, - '024DEE41-33E7-11D3-9D69-0008C781F39F': {'Description': 'MBR partition scheme'}, - 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B': {'Description': 'EFI System partition'}, - '21686148-6449-6E6F-744E-656564454649': {'Description': 'BIOS Boot partition'}, - 'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593': {'Description': 'Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)'}, - 'F4019732-066E-4E12-8273-346C5641494F': {'Description': 'Sony boot partition'}, - 'BFBFAFE7-A34F-448A-9A5B-6213EB736C22': {'Description': 'Lenovo boot partition'}, - 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE': {'OS': 'Windows', 'Description': 'Microsoft Reserved Partition (MSR)'}, - 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7': {'OS': 'Windows', 'Description': 'Basic data partition'}, - '5808C8AA-7E8F-42E0-85D2-E1E90434CFB3': {'OS': 'Windows', 'Description': 'Logical Disk Manager (LDM) metadata partition'}, - 'AF9B60A0-1431-4F62-BC68-3311714A69AD': {'OS': 'Windows', 'Description': 'Logical Disk Manager data partition'}, - 'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC': {'OS': 'Windows', 'Description': 'Windows Recovery Environment'}, - '37AFFC90-EF7D-4E96-91C3-2D7AE055B174': {'OS': 'Windows', 'Description': 'IBM General Parallel File System (GPFS) partition'}, - 'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D': {'OS': 'Windows', 'Description': 'Storage Spaces partition'}, - '75894C1E-3AEB-11D3-B7C1-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Data partition'}, - 'E2A1E728-32E3-11D6-A682-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Service Partition'}, - '0FC63DAF-8483-4772-8E79-3D69D8477DE4': {'OS': 'Linux', 'Description': 'Linux filesystem data'}, - 'A19D880F-05FC-4D3B-A006-743F0F84911E': {'OS': 'Linux', 'Description': 'RAID partition'}, - '44479540-F297-41B2-9AF7-D131D5F0458A': {'OS': 'Linux', 'Description': 'Root partition (x86)'}, - '4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709': {'OS': 'Linux', 'Description': 'Root partition (x86-64)'}, - '69DAD710-2CE4-4E3C-B16C-21A1D49ABED3': {'OS': 'Linux', 'Description': 'Root partition (32-bit ARM)'}, - 'B921B045-1DF0-41C3-AF44-4C6F280D3FAE': {'OS': 'Linux', 'Description': 'Root partition (64-bit ARM/AArch64)'}, - '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F': {'OS': 'Linux', 'Description': 'Swap partition'}, - 'E6D6D379-F507-44C2-A23C-238F2A3DF928': {'OS': 'Linux', 'Description': 'Logical Volume Manager (LVM) partition'}, - '933AC7E1-2EB4-4F13-B844-0E14E2AEF915': {'OS': 'Linux', 'Description': '/home partition'}, - '3B8F8425-20E0-4F3B-907F-1A25A76F98E8': {'OS': 'Linux', 'Description': '/srv (server data) partition'}, - '7FFEC5C9-2D00-49B7-8941-3EA10A5586B7': {'OS': 'Linux', 'Description': 'Plain dm-crypt partition'}, - 'CA7D7CCB-63ED-4C53-861C-1742536059CC': {'OS': 'Linux', 'Description': 'LUKS partition'}, - '8DA63339-0007-60C0-C436-083AC8230908': {'OS': 'Linux', 'Description': 'Reserved'}, - '83BD6B9D-7F41-11DC-BE0B-001560B84F0F': {'OS': 'FreeBSD', 'Description': 'Boot partition'}, - '516E7CB4-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Data partition'}, - '516E7CB5-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Swap partition'}, - '516E7CB6-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Unix File System (UFS) partition'}, - '516E7CB8-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Vinum volume manager partition'}, - '516E7CBA-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'ZFS partition'}, - '48465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Hierarchical File System Plus (HFS+) partition'}, - '55465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple UFS'}, - '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'OS X Darwin', 'Description': 'ZFS'}, - '52414944-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition'}, - '52414944-5F4F-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition, offline'}, - '426F6F74-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Boot partition (Recovery HD)'}, - '4C616265-6C00-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Label'}, - '5265636F-7665-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple TV Recovery partition'}, - '53746F72-6167-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Core Storage (i.e. Lion FileVault) partition'}, - '6A82CB45-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Boot partition'}, - '6A85CF4D-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Root partition'}, - '6A87C46F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Swap partition'}, - '6A8B642B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Backup partition'}, - '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/usr partition'}, - '6A8EF2E9-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/var partition'}, - '6A90BA39-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/home partition'}, - '6A9283A5-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Alternate sector'}, - '6A945A3B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Reserved partition'}, - '6A9630D1-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, - '6A980767-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, - '6A96237F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, - '6A8D2AC7-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, - '49F48D32-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Swap partition'}, - '49F48D5A-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'FFS partition'}, - '49F48D82-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'LFS partition'}, - '49F48DAA-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'RAID partition'}, - '2DB519C4-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Concatenated partition'}, - '2DB519EC-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Encrypted partition'}, - 'FE3A2A5D-4F32-41A7-B725-ACCC3285A309': {'OS': 'ChromeOS', 'Description': 'ChromeOS kernel'}, - '3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC': {'OS': 'ChromeOS', 'Description': 'ChromeOS rootfs'}, - '2E0A753D-9E48-43B0-8337-B15192CB1B5E': {'OS': 'ChromeOS', 'Description': 'ChromeOS future use'}, - '42465331-3BA3-10F1-802A-4861696B7521': {'OS': 'Haiku', 'Description': 'Haiku BFS'}, - '85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Boot partition'}, - '85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Data partition'}, - '85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Swap partition'}, - '0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Unix File System (UFS) partition'}, - '85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Vinum volume manager partition'}, - '85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'ZFS partition'}, - '45B0969E-9B03-4F30-B4C6-B4B80CEFF106': {'OS': 'Ceph', 'Description': 'Ceph Journal'}, - '45B0969E-9B03-4F30-B4C6-5EC00CEFF106': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt Encrypted Journal'}, - '4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph OSD'}, - '4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt OSD'}, - '89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph disk in creation'}, - '89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt disk in creation'}, - '824CC7A0-36A8-11E3-890A-952519AD3F61': {'OS': 'OpenBSD', 'Description': 'Data partition'}, - 'CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1': {'OS': 'QNX', 'Description': 'Power-safe (QNX6) file system'}, - 'C91818F9-8025-47AF-89D2-F030D7000C2C': {'OS': 'Plan 9', 'Description': 'Plan 9 partition'}, - '9D275380-40AD-11DB-BF97-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'vmkcore (coredump partition)'}, - 'AA31E02A-400F-11DB-9590-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMFS filesystem partition'}, - '9198EFFC-31C0-11DB-8F78-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMware Reserved'}, - '2568845D-2332-4675-BC39-8FA5A4748D15': {'OS': 'Android-IA', 'Description': 'Bootloader'}, - '114EAFFE-1552-4022-B26E-9B053604CF84': {'OS': 'Android-IA', 'Description': 'Bootloader2'}, - '49A4D17F-93A3-45C1-A0DE-F50B2EBE2599': {'OS': 'Android-IA', 'Description': 'Boot'}, - '4177C722-9E92-4AAB-8644-43502BFD5506': {'OS': 'Android-IA', 'Description': 'Recovery'}, - 'EF32A33B-A409-486C-9141-9FFB711F6266': {'OS': 'Android-IA', 'Description': 'Misc'}, - '20AC26BE-20B7-11E3-84C5-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Metadata'}, - '38F428E6-D326-425D-9140-6E0EA133647C': {'OS': 'Android-IA', 'Description': 'System'}, - 'A893EF21-E428-470A-9E55-0668FD91A2D9': {'OS': 'Android-IA', 'Description': 'Cache'}, - 'DC76DDA9-5AC1-491C-AF42-A82591580C0D': {'OS': 'Android-IA', 'Description': 'Data'}, - 'EBC597D0-2053-4B15-8B64-E0AAC75F4DB1': {'OS': 'Android-IA', 'Description': 'Persistent'}, - '8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80': {'OS': 'Android-IA', 'Description': 'Factory'}, - '767941D0-2085-11E3-AD3B-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Fastboot / Tertiary'}, - 'AC6D7924-EB71-4DF8-B48D-E267B27148FF': {'OS': 'Android-IA', 'Description': 'OEM'}, - '7412F7D5-A156-4B13-81DC-867174929325': {'OS': 'ONIE', 'Description': 'Boot'}, - 'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149': {'OS': 'ONIE', 'Description': 'Config'}, - '9E1A2D38-C612-4316-AA26-8B49521E5A8B': {'OS': 'PowerPC', 'Description': 'PReP boot'}, - 'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'}, -} - -def lookup_guid(guid): - return PARTITION_UIDS.get(guid.upper(), None) - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - PARTITION UIDs +# sources: https://en.wikipedia.org/wiki/GUID_Partition_Table +# https://en.wikipedia.org/wiki/Partition_type + +PARTITION_UIDS = { + '00': {'OS': 'All', 'Description': 'Empty partition entry'}, + '01': {'OS': 'DOS 2.0+', 'Description': 'FAT12 as primary partition in first physical 32 MB of disk or as logical drive anywhere on disk (else use 06hinstead)'}, + '02': {'OS': 'XENIX', 'Description': 'XENIX root'}, + '03': {'OS': 'XENIX', 'Description': 'XENIX usr'}, + '04': {'OS': 'DOS 3.0+', 'Description': 'FAT16 with less than 65536 sectors (32 MB). As primary partition it must reside in first physical 32 MB of disk, or as logical drive anywhere on disk (else use 06h instead).'}, + '05': {'OS': 'DOS (3.2) 3.3+ / SpeedStor', 'Description': 'Extended partition with CHS addressing. It must reside in first physical 8 GB of disk, else use 0Fh instead / can occur in SpeedStor MBRs'}, + '06': {'OS': 'DOS 3.31+', 'Description': 'FAT16B with 65536 or more sectors. It must reside in first physical 8 GB of disk, unless used for logical drives in an 0Fh extended partition (else use 0Eh instead). Also used for FAT12 and FAT16 volumes in primary partitions if they are not residing in first physical 32 MB of disk.'}, + '07': {'OS': 'OS/2 1.2+ / OS/2 1.2+, Windows NT / Windows NT / Windows Embedded CE / QNX 2', 'Description': 'IFS / HPFS / NTFS / exFAT / QNX "qnx" (7) (pre-1988 only)'}, + '08': {'OS': 'Commodore MS-DOS 3.x / OS/2 1.0-1.3 / AIX / QNX 1.x/2.x', 'Description': 'Logical sectored FAT12 or FAT16 / OS/2 (FAT?) / AIX boot/split / SplitDrive / QNX "qny" (8) / partition spanning multiple drives'}, + '09': {'OS': 'AIX / QNX 1.x/2.x / Coherent / OS-9', 'Description': 'AIX data/boot / QNX "qnz" (9) / Coherent file system / OS-9 RBF'}, + '0A': {'OS': 'OS/2 / Coherent', 'Description': 'OS/2 Boot Manager / Coherent swap partition'}, + '0B': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with CHS addressing'}, + '0C': {'OS': 'DOS 7.1+', 'Description': 'FAT32 with LBA'}, + '0D': {'OS': 'Silicon Safe', 'Description': 'Reserved'}, + '0E': {'OS': 'DOS 7.0+', 'Description': 'FAT16B with LBA'}, + '0F': {'OS': 'DOS 7.0+', 'Description': 'Extended partition with LBA'}, + '10': {'OS': 'OPUS', 'Description': 'Unknown'}, + '11': {'OS': 'Leading Edge MS-DOS 3.x / OS/2 Boot Manager', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT12 '}, + '12': {'OS': 'Compaq Contura', 'Description': 'configuration partition (bootable FAT) / configuration partition / hibernation partition / diagnostics and firmware partition (bootable FAT) / service partition (bootable FAT) / Rescue and Recovery partition'}, + '14': {'OS': 'AST MS-DOS 3.x / OS/2 Boot Manager / Maverick OS', 'Description': 'Logical sectored FAT12 or FAT16 / Hidden FAT16 / Omega file system'}, + '15': {'OS': 'OS/2 Boot Manager / Maverick OS', 'Description': 'Hidden extended partition with CHS addressing / swap'}, + '16': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16B '}, + '17': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden IFS / Hidden HPFS / Hidden NTFS / Hidden exFAT '}, + '18': {'OS': 'AST Windows', 'Description': 'AST Zero Volt Suspend or SmartSleep partition'}, + '19': {'OS': 'Willowtech Photon coS', 'Description': 'Willowtech Photon coS'}, + '1B': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 '}, + '1C': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT32 with LBA '}, + '1E': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden FAT16 with LBA '}, + '1F': {'OS': 'OS/2 Boot Manager', 'Description': 'Hidden extended partition with LBA addressing '}, + '20': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile update XIP / Willowsoft Overture File System (OFS1)'}, + '21': {'OS': 'Oxygen', 'Description': 'HP Volume Expansion (SpeedStor) / FSo2 (Oxygen File System)'}, + '22': {'OS': 'Oxygen', 'Description': 'Oxygen Extended Partition Table'}, + '23': {'OS': 'Windows Mobile', 'Description': 'Reserved / Windows Mobile boot XIP'}, + '24': {'OS': 'NEC MS-DOS 3.30', 'Description': 'Logical sectored FAT12 or FAT16 '}, + '25': {'OS': 'Windows Mobile', 'Description': 'Windows Mobile IMGFS[citation needed]'}, + '26': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '27': {'OS': 'Windows / PQservice / MirOS BSD / RooterBOOT', 'Description': 'Windows Recovery Environment (RE) partition (hidden NTFS partition type 07h) / FAT32 or NTFS rescue partition / MirOS partition / RooterBOOT kernel partition (contains a raw ELF Linux kernel, no file system)'}, + '2A': {'OS': 'AtheOS', 'Description': 'AtheOS file system (AthFS, AFS) (an extension of BFS, see 2Bh and EBh) / Reserved'}, + '2B': {'OS': 'SyllableOS', 'Description': 'SyllableSecure (SylStor), a variant of AthFS (an extension of BFS, see 2Ah and EBh)'}, + '31': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '32': {'OS': 'NOS', 'Description': 'Unknown'}, + '33': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '34': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '35': {'OS': 'OS/2 Warp Server /eComStation', 'Description': 'JFS (OS/2 implementation of AIX Journaling File system)'}, + '36': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '38': {'OS': 'THEOS', 'Description': 'THEOS version 3.2, 2 GB partition'}, + '39': {'OS': 'Plan 9 / THEOS', 'Description': 'Plan 9 edition 3 partition (sub-partitions described in second sector of partition) / THEOS version 4 spanned partition'}, + '3A': {'OS': 'THEOS', 'Description': 'THEOS version 4, 4 GB partition'}, + '3B': {'OS': 'THEOS', 'Description': 'THEOS version 4 extended partition'}, + '3C': {'OS': 'PartitionMagic', 'Description': 'PqRP (PartitionMagic or DriveImage in progress)'}, + '3D': {'OS': 'PartitionMagic', 'Description': 'Hidden NetWare'}, + '3F': {'OS': 'OS/32', 'Description': 'Unknown'}, + '40': {'OS': 'PICK / Venix', 'Description': 'PICK R83 / Venix 80286'}, + '41': {'OS': 'Personal RISC / Linux / PowerPC', 'Description': 'Personal RISC Boot / Old Linux/Minix (disk shared with DR DOS 6.0) / PPC PReP (Power PC Reference Platform) Boot'}, + '42': {'OS': 'SFS / Linux / Windows 2000, XP, etc.', 'Description': 'Secure File system (SFS) / Old Linux swap (disk shared with DR DOS 6.0) / Dynamic extended partition marker'}, + '43': {'OS': 'Linux', 'Description': 'Old Linux native (disk shared with DR DOS 6.0) '}, + '44': {'OS': 'GoBack', 'Description': 'Norton GoBack, WildFile GoBack, Adaptec GoBack, Roxio GoBack'}, + '45': {'OS': 'Boot-US / EUMEL/ELAN', 'Description': 'Priam / Boot-US boot manager (1 cylinder) / EUMEL/ELAN (L2)'}, + '46': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, + '47': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2)'}, + '48': {'OS': 'EUMEL/ELAN', 'Description': 'EUMEL/ELAN (L2), ERGOS L3'}, + '4A': {'OS': 'AdaOS / ALFS/THIN', 'Description': 'Aquila / ALFS/THIN advanced lightweight file system for DOS'}, + '4C': {'OS': 'ETH Oberon', 'Description': 'Aos (A2) file system (76)'}, + '4D': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Primary QNX POSIX volume on disk (77)'}, + '4E': {'OS': 'QNX 4.x, Neutrino', 'Description': 'Secondary QNX POSIX volume on disk (78)'}, + '4F': {'OS': 'QNX 4.x, Neutrino / ETH Oberon', 'Description': 'Tertiary QNX POSIX volume on disk (79) / boot / native file system (79)'}, + '50': {'OS': 'ETH Oberon / Disk Manager 4 / LynxOS / Novell', 'Description': 'Alternative native file system (80) / Read-only partition (old) / Lynx RTOS'}, + '51': {'OS': 'Disk Manager 4-6', 'Description': 'Read-write partition (Aux 1)'}, + '52': {'OS': 'CP/M-80 / System V/AT, V/386', 'Description': 'CP/M-80'}, + '53': {'OS': 'Disk Manager 6', 'Description': 'Auxiliary 3 (WO)'}, + '54': {'OS': 'Disk Manager 6', 'Description': 'Dynamic Drive Overlay (DDO)'}, + '55': {'OS': 'EZ-Drive', 'Description': 'EZ-Drive, Maxtor, MaxBlast, or DriveGuide INT 13h redirector volume'}, + '56': {'OS': 'AT&T MS-DOS 3.x / EZ-Drive / VFeature', 'Description': 'Logical sectored FAT12 or FAT16 / Disk Manager partition converted to EZ-BIOS / VFeature partitionned volume'}, + '57': {'OS': 'DrivePro', 'Description': 'VNDI partition'}, + '5C': {'OS': 'EDISK', 'Description': 'Priam EDisk Partitioned Volume '}, + '61': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + '63': {'OS': 'Unix', 'Description': 'SCO Unix, ISC, UnixWare, AT&T System V/386, ix, MtXinu BSD 4.3 on Mach, GNU HURD'}, + '64': {'OS': 'SpeedStor / NetWare', 'Description': 'NetWare File System 286/2 / PC-ARMOUR'}, + '65': {'OS': 'NetWare', 'Description': 'NetWare File System 386'}, + '66': {'OS': 'NetWare / NetWare', 'Description': 'NetWare File System 386 / Storage Management Services (SMS)'}, + '67': {'OS': 'NetWare', 'Description': 'Wolf Mountain'}, + '68': {'OS': 'NetWare', 'Description': 'Unknown'}, + '69': {'OS': 'NetWare 5 / NetWare', 'Description': 'Novell Storage Services (NSS)'}, + '6E': {'Description': 'Unknown'}, + '70': {'OS': 'DiskSecure', 'Description': 'DiskSecure multiboot'}, + '71': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '72': {'OS': 'APTI conformant systems / Unix V7/x86', 'Description': 'APTI alternative FAT12 (CHS, SFN) / V7/x86'}, + '73': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '74': {'OS': 'Microsoft, IBM', 'Description': 'Reserved / Scramdisk'}, + '75': {'OS': 'PC/IX', 'Description': 'Unknown'}, + '76': {'OS': 'Microsoft, IBM', 'Description': 'Reserved'}, + '77': {'OS': 'Novell', 'Description': 'VNDI, M2FS, M2CS'}, + '78': {'OS': 'Geurt Vos', 'Description': 'XOSL bootloader file system'}, + '79': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (CHS, SFN) '}, + '7A': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16 (LBA, SFN) '}, + '7B': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT16B (CHS, SFN) '}, + '7C': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (LBA, SFN) '}, + '7D': {'OS': 'APTI conformant systems', 'Description': 'APTI alternative FAT32 (CHS, SFN) '}, + '7E': {'OS': 'F.I.X. (claim) / PrimoCache', 'Description': 'Level 2 cache'}, + '7F': {'OS': 'Varies', 'Description': 'Alternative OS Development Partition Standard - reserved for individual or local use and temporary or experimental projects'}, + '80': {'OS': 'Minix 1.1-1.4a', 'Description': 'Minix file system (old)'}, + '81': {'OS': 'Minix 1.4b+ / Linux', 'Description': 'MINIX file system / Mitac Advanced Disk Manager'}, + '82': {'OS': 'Linux / Sun Microsystems', 'Description': 'Linux swap space / Solaris x86 (for Sun disklabels up to 2005) / Prime'}, + '83': {'OS': 'GNU/Linux', 'Description': 'Any native Linux file system '}, + '84': {'OS': 'OS/2 / Windows 7', 'Description': 'APM hibernation (suspend to disk, S2D) / Hidden C: (FAT16) / Rapid Start technology'}, + '85': {'OS': 'GNU/Linux', 'Description': 'Linux extended '}, + '86': {'OS': 'Windows NT 4 Server / Linux', 'Description': 'Fault-tolerant FAT16B mirrored volume set / Linux RAID superblock with auto-detect (old)'}, + '87': {'OS': 'Windows NT 4 Server', 'Description': 'Fault-tolerant HPFS/NTFS mirrored volume set '}, + '88': {'OS': 'GNU/Linux', 'Description': 'Linux plaintext partition table'}, + '8A': {'OS': 'AiR-BOOT', 'Description': 'Linux kernel image'}, + '8B': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, + '8C': {'OS': 'Windows NT 4 Server', 'Description': 'Legacy fault-tolerant FAT32 mirrored volume set '}, + '8D': {'OS': 'Free FDISK', 'Description': 'Hidden FAT12 '}, + '8E': {'OS': 'Linux', 'Description': 'Linux LVM'}, + '90': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, + '91': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with CHS addressing '}, + '92': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16B '}, + '93': {'OS': 'Amoeba / Linux', 'Description': 'Amoeba native file system / Hidden Linux file system'}, + '94': {'OS': 'Amoeba', 'Description': 'Amoeba bad block table'}, + '95': {'OS': 'EXOPC', 'Description': 'EXOPC native'}, + '96': {'OS': 'CHRP', 'Description': 'ISO-9660 file system'}, + '97': {'OS': 'Free FDISK', 'Description': 'Hidden FAT32 '}, + '98': {'OS': 'Free FDISK / ROM-DOS', 'Description': 'Hidden FAT32 / service partition (bootable FAT) ROM-DOS SuperBoot / service partition (bootable FAT)'}, + '99': {'OS': 'early Unix', 'Description': 'Unknown'}, + '9A': {'OS': 'Free FDISK', 'Description': 'Hidden FAT16 '}, + '9B': {'OS': 'Free FDISK', 'Description': 'Hidden extended partition with LBA '}, + '9E': {'OS': 'VSTA / ForthOS', 'Description': 'ForthOS (eForth port)'}, + '9F': {'OS': 'BSD/OS 3.0+, BSDI', 'Description': 'Unknown'}, + 'A0': {'OS': 'Hewlett Packard / Phoenix, IBM, Toshiba, Sony', 'Description': 'Diagnostic partition for HP laptops / Hibernate partition'}, + 'A1': {'OS': 'Hewlett Packard / Phoenix, NEC', 'Description': 'HP Volume Expansion (SpeedStor) / Hibernate partition'}, + 'A2': {'OS': 'Cyclone V', 'Description': 'Hard Processor System (HPS) ARM preloader'}, + 'A3': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'A4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'A5': {'OS': 'BSD', 'Description': 'BSD slice (BSD/386, 386BSD, NetBSD (old), FreeBSD)'}, + 'A6': {'OS': 'OpenBSD', 'Description': 'HP Volume Expansion (SpeedStor) / OpenBSD slice'}, + 'A7': {'OS': 'NeXT', 'Description': 'NeXTSTEP'}, + 'A8': {'OS': 'Darwin, Mac OS X', 'Description': 'Apple Darwin, Mac OS X UFS'}, + 'A9': {'OS': 'NetBSD', 'Description': 'NetBSD slice'}, + 'AA': {'OS': 'MS-DOS', 'Description': 'Olivetti MS-DOS FAT12 (1.44 MB) '}, + 'AB': {'OS': 'Darwin, Mac OS X / GO! OS', 'Description': 'Apple Darwin, Mac OS X boot / GO!'}, + 'AD': {'OS': 'RISC OS', 'Description': 'ADFS / FileCore format'}, + 'AE': {'OS': 'ShagOS', 'Description': 'ShagOS file system'}, + 'AF': {'OS': 'ShagOS', 'Description': 'Apple Mac OS X HFS and HFS+ / ShagOS swap'}, + 'B0': {'OS': 'Boot-Star', 'Description': 'Boot-Star dummy partition'}, + 'B1': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, + 'B2': {'OS': 'QNX 6.x', 'Description': 'QNX Neutrino power-safe file system'}, + 'B3': {'OS': 'QNX 6.x', 'Description': 'HP Volume Expansion (SpeedStor) / QNX Neutrino power-safe file system'}, + 'B4': {'OS': 'Hewlett Packard', 'Description': 'HP Volume Expansion (SpeedStor)'}, + 'B6': {'OS': 'Windows NT 4 Server', 'Description': 'HP Volume Expansion (SpeedStor) / Corrupted fault-tolerant FAT16B mirrored master volume '}, + 'B7': {'OS': 'BSDI (before 3.0) / Windows NT 4 Server', 'Description': 'BSDI native file system / swap / Corrupted fault-tolerant HPFS/NTFS mirrored master volume '}, + 'B8': {'OS': 'BSDI (before 3.0)', 'Description': 'BSDI swap / native file system'}, + 'BB': {'OS': 'BootWizard, OS Selector / Acronis True Image / Windows NT 4 Server', 'Description': 'PTS BootWizard 4 / OS Selector 5 for hidden partitions other than 01h, 04h, 06h, 07h, 0Bh, 0Ch, 0Eh and unformatted partitions / OEM Secure Zone (corresponds to BCh) / Corrupted fault-tolerant FAT32 mirrored master volume '}, + 'BC': {'OS': 'Windows NT 4 Server / Acronis True Image / Backup Capsule', 'Description': 'Corrupted fault-tolerant FAT32 mirrored master volume / Acronis Secure Zone / Backup Capsule'}, + 'BD': {'OS': 'BonnyDOS/286', 'Description': 'Unknown'}, + 'BE': {'OS': 'Solaris 8', 'Description': 'Solaris 8 boot'}, + 'BF': {'OS': 'Solaris', 'Description': 'Solaris x86 (for Sun disklabels, since 2005)'}, + 'C0': {'OS': 'DR-DOS, Multiuser DOS,REAL/32', 'Description': 'Secured FAT partition (smaller than 32 MB)'}, + 'C1': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT12 '}, + 'C2': {'OS': 'Power Boot', 'Description': 'Hidden Linux native file system'}, + 'C3': {'OS': 'Power Boot', 'Description': 'Hidden Linux swap'}, + 'C4': {'OS': 'DR DOS 6.0+', 'Description': 'Secured FAT16 '}, + 'C5': {'OS': 'DR DOS 6.0+', 'Description': 'Secured extended partition with CHS addressing '}, + 'C6': {'OS': 'DR DOS 6.0+ / Windows NT 4 Server', 'Description': 'Secured FAT16B / Corrupted fault-tolerant FAT16B mirrored slave volume '}, + 'C7': {'OS': 'Syrinx / Windows NT 4 Server', 'Description': 'Syrinx boot / Corrupted fault-tolerant HPFS/NTFS mirrored slave volume '}, + 'C8': {'Description': 'Reserved for DR-DOS since 1997'}, + 'C9': {'Description': 'Reserved for DR-DOS since 1997'}, + 'CA': {'Description': 'Reserved for DR-DOS since 1997'}, + 'CB': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, + 'CC': {'OS': 'DR-DOS 7.0x / Windows NT 4 Server', 'Description': 'Secured FAT32 / Corrupted fault-tolerant FAT32 mirrored slave volume '}, + 'CD': {'OS': 'CTOS', 'Description': 'Memory dump'}, + 'CE': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured FAT16B '}, + 'CF': {'OS': 'DR-DOS 7.0x', 'Description': 'Secured extended partition with LBA '}, + 'D0': {'OS': 'Multiuser DOS, REAL/32', 'Description': 'Secured FAT partition (larger than 32 MB)'}, + 'D1': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT12 '}, + 'D4': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16 '}, + 'D5': {'OS': 'Multiuser DOS', 'Description': 'Secured extended partition with CHS addressing '}, + 'D6': {'OS': 'Multiuser DOS', 'Description': 'Secured FAT16B '}, + 'D8': {'OS': 'Digital Research', 'Description': 'CP/M-86 [citation needed]'}, + 'DA': {'OS': 'Powercopy Backup', 'Description': 'Non-file system data / Shielded disk'}, + 'DB': {'OS': 'CP/M-86,Concurrent CP/M-86,Concurrent DOS / CTOS / D800 / DRMK', 'Description': 'CP/M-86, Concurrent CP/M-86, Concurrent DOS / boot image for x86 supervisor CPU (SCPU) module / FAT32 system restore partition (DSR)'}, + 'DD': {'OS': 'CTOS', 'Description': 'Hidden memory dump'}, + 'DE': {'OS': 'Dell', 'Description': 'FAT16 utility/diagnostic partition'}, + 'DF': {'OS': 'DG/UX / BootIt / Aviion', 'Description': 'DG/UX virtual disk manager / EMBRM'}, + 'E0': {'OS': 'STMicroelectronics', 'Description': 'ST AVFS'}, + 'E1': {'OS': 'SpeedStor', 'Description': 'Extended FAT12 (> 1023 cylinder)'}, + 'E2': {'Description': 'DOS read-only (XFDISK)'}, + 'E3': {'OS': 'SpeedStor', 'Description': 'DOS read-only'}, + 'E4': {'OS': 'SpeedStor', 'Description': 'Extended FAT16 (< 1024 cylinder)'}, + 'E5': {'OS': 'Tandy MS-DOS', 'Description': 'Logical sectored FAT12 or FAT16'}, + 'E6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'E8': {'OS': 'LUKS', 'Description': 'Linux Unified Key Setup'}, + 'EB': {'OS': 'BeOS, Haiku', 'Description': 'BFS'}, + 'EC': {'OS': 'SkyOS', 'Description': 'SkyFS'}, + 'ED': {'OS': 'Sprytix / EDD 4', 'Description': 'EDC loader / GPT hybrid MBR'}, + 'EE': {'OS': 'EFI', 'Description': 'GPT protective MBR'}, + 'EF': {'OS': 'EFI', 'Description': 'EFI system partition can be a FAT12, FAT16, FAT32 (or other) file system'}, + 'F0': {'OS': 'Linux / OS/32', 'Description': 'PA-RISC Linux boot loader. It must reside in first physical 2 GB. / floppy'}, + 'F1': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F2': {'OS': 'Sperry IT MS-DOS 3.x, Unisys MS-DOS 3.3, Digital ResearchDOS Plus 2.1', 'Description': 'Logical sectored FAT12 or FAT16 secondary partition'}, + 'F3': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F4': {'OS': 'SpeedStor / Prologue', 'Description': '"large" DOS partition / single volume partition for NGF or TwinFS'}, + 'F5': {'OS': 'Prologue', 'Description': 'MD0-MD9 multi volume partition for NGF or TwinFS'}, + 'F6': {'OS': 'SpeedStor', 'Description': 'Unknown'}, + 'F7': {'OS': 'O.S.G. / X1', 'Description': 'EFAT / Solid State file system'}, + 'F9': {'OS': 'Linux', 'Description': 'pCache ext2/ext3 persistent cache'}, + 'FA': {'OS': 'Bochs', 'Description': 'x86 emulator'}, + 'FB': {'OS': 'VMware', 'Description': 'VMware VMFS file system partition'}, + 'FC': {'OS': 'VMware', 'Description': 'VMware swap / VMKCORE kernel dump partition'}, + 'FD': {'OS': 'Linux / FreeDOS', 'Description': 'Linux RAID superblock with auto-detect / Reserved for FreeDOS'}, + 'FE': {'OS': 'SpeedStor / LANstep / Windows NT / Linux', 'Description': 'partition > 1024 cylinder / PS/2 IML partition / PS/2 recovery partition (FAT12 reference disk floppy image), / Disk Administration hidden partition / old Linux LVM'}, + 'FF': {'OS': 'XENIX', 'Description': 'XENIX bad block table'}, + '00000000-0000-0000-0000-000000000000': {'Description': 'Unused entry'}, + '024DEE41-33E7-11D3-9D69-0008C781F39F': {'Description': 'MBR partition scheme'}, + 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B': {'Description': 'EFI System partition'}, + '21686148-6449-6E6F-744E-656564454649': {'Description': 'BIOS Boot partition'}, + 'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593': {'Description': 'Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)'}, + 'F4019732-066E-4E12-8273-346C5641494F': {'Description': 'Sony boot partition'}, + 'BFBFAFE7-A34F-448A-9A5B-6213EB736C22': {'Description': 'Lenovo boot partition'}, + 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE': {'OS': 'Windows', 'Description': 'Microsoft Reserved Partition (MSR)'}, + 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7': {'OS': 'Windows', 'Description': 'Basic data partition'}, + '5808C8AA-7E8F-42E0-85D2-E1E90434CFB3': {'OS': 'Windows', 'Description': 'Logical Disk Manager (LDM) metadata partition'}, + 'AF9B60A0-1431-4F62-BC68-3311714A69AD': {'OS': 'Windows', 'Description': 'Logical Disk Manager data partition'}, + 'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC': {'OS': 'Windows', 'Description': 'Windows Recovery Environment'}, + '37AFFC90-EF7D-4E96-91C3-2D7AE055B174': {'OS': 'Windows', 'Description': 'IBM General Parallel File System (GPFS) partition'}, + 'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D': {'OS': 'Windows', 'Description': 'Storage Spaces partition'}, + '75894C1E-3AEB-11D3-B7C1-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Data partition'}, + 'E2A1E728-32E3-11D6-A682-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Service Partition'}, + '0FC63DAF-8483-4772-8E79-3D69D8477DE4': {'OS': 'Linux', 'Description': 'Linux filesystem data'}, + 'A19D880F-05FC-4D3B-A006-743F0F84911E': {'OS': 'Linux', 'Description': 'RAID partition'}, + '44479540-F297-41B2-9AF7-D131D5F0458A': {'OS': 'Linux', 'Description': 'Root partition (x86)'}, + '4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709': {'OS': 'Linux', 'Description': 'Root partition (x86-64)'}, + '69DAD710-2CE4-4E3C-B16C-21A1D49ABED3': {'OS': 'Linux', 'Description': 'Root partition (32-bit ARM)'}, + 'B921B045-1DF0-41C3-AF44-4C6F280D3FAE': {'OS': 'Linux', 'Description': 'Root partition (64-bit ARM/AArch64)'}, + '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F': {'OS': 'Linux', 'Description': 'Swap partition'}, + 'E6D6D379-F507-44C2-A23C-238F2A3DF928': {'OS': 'Linux', 'Description': 'Logical Volume Manager (LVM) partition'}, + '933AC7E1-2EB4-4F13-B844-0E14E2AEF915': {'OS': 'Linux', 'Description': '/home partition'}, + '3B8F8425-20E0-4F3B-907F-1A25A76F98E8': {'OS': 'Linux', 'Description': '/srv (server data) partition'}, + '7FFEC5C9-2D00-49B7-8941-3EA10A5586B7': {'OS': 'Linux', 'Description': 'Plain dm-crypt partition'}, + 'CA7D7CCB-63ED-4C53-861C-1742536059CC': {'OS': 'Linux', 'Description': 'LUKS partition'}, + '8DA63339-0007-60C0-C436-083AC8230908': {'OS': 'Linux', 'Description': 'Reserved'}, + '83BD6B9D-7F41-11DC-BE0B-001560B84F0F': {'OS': 'FreeBSD', 'Description': 'Boot partition'}, + '516E7CB4-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Data partition'}, + '516E7CB5-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Swap partition'}, + '516E7CB6-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Unix File System (UFS) partition'}, + '516E7CB8-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Vinum volume manager partition'}, + '516E7CBA-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'ZFS partition'}, + '48465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Hierarchical File System Plus (HFS+) partition'}, + '55465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple UFS'}, + '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'OS X Darwin', 'Description': 'ZFS'}, + '52414944-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition'}, + '52414944-5F4F-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition, offline'}, + '426F6F74-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Boot partition (Recovery HD)'}, + '4C616265-6C00-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Label'}, + '5265636F-7665-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple TV Recovery partition'}, + '53746F72-6167-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Core Storage (i.e. Lion FileVault) partition'}, + '6A82CB45-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Boot partition'}, + '6A85CF4D-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Root partition'}, + '6A87C46F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Swap partition'}, + '6A8B642B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Backup partition'}, + '6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/usr partition'}, + '6A8EF2E9-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/var partition'}, + '6A90BA39-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/home partition'}, + '6A9283A5-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Alternate sector'}, + '6A945A3B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Reserved partition'}, + '6A9630D1-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A980767-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A96237F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '6A8D2AC7-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'}, + '49F48D32-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Swap partition'}, + '49F48D5A-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'FFS partition'}, + '49F48D82-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'LFS partition'}, + '49F48DAA-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'RAID partition'}, + '2DB519C4-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Concatenated partition'}, + '2DB519EC-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Encrypted partition'}, + 'FE3A2A5D-4F32-41A7-B725-ACCC3285A309': {'OS': 'ChromeOS', 'Description': 'ChromeOS kernel'}, + '3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC': {'OS': 'ChromeOS', 'Description': 'ChromeOS rootfs'}, + '2E0A753D-9E48-43B0-8337-B15192CB1B5E': {'OS': 'ChromeOS', 'Description': 'ChromeOS future use'}, + '42465331-3BA3-10F1-802A-4861696B7521': {'OS': 'Haiku', 'Description': 'Haiku BFS'}, + '85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Boot partition'}, + '85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Data partition'}, + '85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Swap partition'}, + '0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Unix File System (UFS) partition'}, + '85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Vinum volume manager partition'}, + '85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'ZFS partition'}, + '45B0969E-9B03-4F30-B4C6-B4B80CEFF106': {'OS': 'Ceph', 'Description': 'Ceph Journal'}, + '45B0969E-9B03-4F30-B4C6-5EC00CEFF106': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt Encrypted Journal'}, + '4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph OSD'}, + '4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt OSD'}, + '89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph disk in creation'}, + '89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt disk in creation'}, + '824CC7A0-36A8-11E3-890A-952519AD3F61': {'OS': 'OpenBSD', 'Description': 'Data partition'}, + 'CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1': {'OS': 'QNX', 'Description': 'Power-safe (QNX6) file system'}, + 'C91818F9-8025-47AF-89D2-F030D7000C2C': {'OS': 'Plan 9', 'Description': 'Plan 9 partition'}, + '9D275380-40AD-11DB-BF97-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'vmkcore (coredump partition)'}, + 'AA31E02A-400F-11DB-9590-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMFS filesystem partition'}, + '9198EFFC-31C0-11DB-8F78-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMware Reserved'}, + '2568845D-2332-4675-BC39-8FA5A4748D15': {'OS': 'Android-IA', 'Description': 'Bootloader'}, + '114EAFFE-1552-4022-B26E-9B053604CF84': {'OS': 'Android-IA', 'Description': 'Bootloader2'}, + '49A4D17F-93A3-45C1-A0DE-F50B2EBE2599': {'OS': 'Android-IA', 'Description': 'Boot'}, + '4177C722-9E92-4AAB-8644-43502BFD5506': {'OS': 'Android-IA', 'Description': 'Recovery'}, + 'EF32A33B-A409-486C-9141-9FFB711F6266': {'OS': 'Android-IA', 'Description': 'Misc'}, + '20AC26BE-20B7-11E3-84C5-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Metadata'}, + '38F428E6-D326-425D-9140-6E0EA133647C': {'OS': 'Android-IA', 'Description': 'System'}, + 'A893EF21-E428-470A-9E55-0668FD91A2D9': {'OS': 'Android-IA', 'Description': 'Cache'}, + 'DC76DDA9-5AC1-491C-AF42-A82591580C0D': {'OS': 'Android-IA', 'Description': 'Data'}, + 'EBC597D0-2053-4B15-8B64-E0AAC75F4DB1': {'OS': 'Android-IA', 'Description': 'Persistent'}, + '8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80': {'OS': 'Android-IA', 'Description': 'Factory'}, + '767941D0-2085-11E3-AD3B-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Fastboot / Tertiary'}, + 'AC6D7924-EB71-4DF8-B48D-E267B27148FF': {'OS': 'Android-IA', 'Description': 'OEM'}, + '7412F7D5-A156-4B13-81DC-867174929325': {'OS': 'ONIE', 'Description': 'Boot'}, + 'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149': {'OS': 'ONIE', 'Description': 'Config'}, + '9E1A2D38-C612-4316-AA26-8B49521E5A8B': {'OS': 'PowerPC', 'Description': 'PReP boot'}, + 'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'}, +} + +def lookup_guid(guid): + return PARTITION_UIDS.get(guid.upper(), None) + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py similarity index 97% rename from Scripts/functions/windows_setup.py rename to .bin/Scripts/functions/windows_setup.py index cbbe1525..7097a371 100644 --- a/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -1,225 +1,225 @@ -# Wizard Kit PE: Functions - Windows Setup - -from functions.data import * - -# STATIC VARIABLES -DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) -WINDOWS_VERSIONS = [ - {'Name': 'Windows 7 Home Basic', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEBASIC'}, - {'Name': 'Windows 7 Home Premium', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 HOMEPREMIUM'}, - {'Name': 'Windows 7 Professional', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 PROFESSIONAL'}, - {'Name': 'Windows 7 Ultimate', - 'Image File': 'Win7', - 'Image Name': 'Windows 7 ULTIMATE'}, - - {'Name': 'Windows 8.1', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1', - 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', - 'Image File': 'Win8', - 'Image Name': 'Windows 8.1 Pro'}, - - {'Name': 'Windows 10 Home', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Home', - 'CRLF': True}, - {'Name': 'Windows 10 Pro', - 'Image File': 'Win10', - 'Image Name': 'Windows 10 Pro'}, - ] - -def find_windows_image(windows_version): - """Search for a Windows source image file, returns dict. - - Searches on local disks and then the WINDOWS_SERVER share.""" - image = {} - imagefile = windows_version['Image File'] - imagename = windows_version['Image Name'] - - # Search local source - for d in psutil.disk_partitions(): - for ext in ['esd', 'wim', 'swm']: - path = '{}images\{}.{}'.format(d.mountpoint, imagefile, ext) - if os.path.isfile(path) and wim_contains_image(path, imagename): - image['Path'] = path - image['Source'] = letter - if ext == 'swm': - image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) - break - - # Check for network source - if not image: - mount_windows_share() - if not WINDOWS_SERVER['Mounted']: - return None - for ext in ['esd', 'wim', 'swm']: - path = r'\\{}\{}\images\{}.ext'.format( - WINDOWS_SERVER['IP'], WINDOWS_SERVER['Share'], imagefile, ext) - if os.path.isfile(path) and wim_contains_image(path, imagename): - image['Path'] = path - image['Source'] = None - if ext == 'swm': - image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) - break - - # Display image to be used (if any) and return - if image: - print_info('Using image: {}'.format(image['Path'])) - return image - else: - print_error('Failed to find Windows source image for {}'.format( - windows_version['Name'])) - raise GeneralAbort - -def format_disk(disk, use_gpt): - """Format disk for use as a Windows OS disk.""" - if use_gpt: - format_gpt(disk) - else: - format_mbr(disk) - -def format_gpt(disk): - """Format disk for use as a Windows OS disk using the GPT layout.""" - with open(DISKPART_SCRIPT, 'w') as script: - # Partition table - script.write('select disk {}\n'.format(disk['Number'])) - script.write('clean\n') - script.write('convert gpt\n') - - # System partition - # NOTE: ESP needs to be >= 260 for Advanced Format 4K disks - script.write('create partition efi size=500\n') - script.write('format quick fs=fat32 label="System"\n') - script.write('assign letter="S"\n') - - # Microsoft Reserved (MSR) partition - script.write('create partition msr size=128\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Windows"\n') - script.write('assign letter="W"\n') - - # Recovery Tools partition - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery Tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') - - # Run script - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - time.sleep(2) - -def format_mbr(disk): - """Format disk for use as a Windows OS disk using the MBR layout.""" - with open(DISKPART_SCRIPT, 'w') as script: - # Partition table - script.write('select disk {}\n'.format(disk['Number'])) - script.write('clean\n') - - # System partition - script.write('create partition primary size=100\n') - script.write('format fs=ntfs quick label="System Reserved"\n') - script.write('active\n') - script.write('assign letter="S"\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format fs=ntfs quick label="Windows"\n') - script.write('assign letter="W"\n') - - # Recovery Tools partition - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery"\n') - script.write('assign letter="T"\n') - script.write('set id=27\n') - - # Run script - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - time.sleep(2) - -def mount_windows_share(): - """Mount the Windows images share unless labeled as already mounted.""" - if WINDOWS_SERVER['Mounted']: - # Blindly skip if we mounted earlier - continue - - mount_network_share(WINDOWS_SERVER) - -def select_windows_version(): - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select( - title = 'Which version of Windows are we installing?', - main_entries = WINDOWS_VERSIONS, - action_entries = actions) - - if selection.isnumeric(): - return WINDOWS_VERSIONS[int(selection)-1] - elif selection == 'M': - raise GeneralAbort - -def setup_windows(windows_image, windows_version): - cmd = [ - global_vars['Tools']['wimlib-imagex'], - 'apply', - windows_image['Path'], - windows_version['Image Name'], - 'W:\\'] - if 'Glob' in windows_image: - cmd.extend(windows_image['Glob']) - run_program(cmd) - -def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): - win = r'{}:\Windows'.format(windows_letter) - winre = r'{}\System32\Recovery\WinRE.wim'.format(win) - dest = r'{}:\Recovery\WindowsRE'.format(tools_letter) - - # Copy WinRE.wim - os.makedirs(dest, exist_ok=True) - shutil.copy(winre, r'{}\WinRE.wim'.format(dest)) - - # Set location - cmd = [ - r'{}\System32\ReAgentc.exe'.format(win), - '/setreimage', - '/path', dest, - '/target', win] - run_program(cmd) - -def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): - cmd = [ - r'{}:\Windows\System32\bcdboot.exe'.format(windows_letter), - r'{}:\Windows'.format(windows_letter), - '/s', '{}:'.format(system_letter), - '/f', mode] - run_program(cmd) - -def wim_contains_image(filename, imagename): - cmd = [ - global_vars['Tools']['wimlib-imagex'], - 'info', - filename, - imagename] - try: - run_program(cmd) - except subprocess.CalledProcessError: - return False - - return True - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Functions - Windows Setup + +from functions.data import * + +# STATIC VARIABLES +DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) +WINDOWS_VERSIONS = [ + {'Name': 'Windows 7 Home Basic', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEBASIC'}, + {'Name': 'Windows 7 Home Premium', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEPREMIUM'}, + {'Name': 'Windows 7 Professional', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 PROFESSIONAL'}, + {'Name': 'Windows 7 Ultimate', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 ULTIMATE'}, + + {'Name': 'Windows 8.1', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1 Pro'}, + + {'Name': 'Windows 10 Home', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Home', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Pro'}, + ] + +def find_windows_image(windows_version): + """Search for a Windows source image file, returns dict. + + Searches on local disks and then the WINDOWS_SERVER share.""" + image = {} + imagefile = windows_version['Image File'] + imagename = windows_version['Image Name'] + + # Search local source + for d in psutil.disk_partitions(): + for ext in ['esd', 'wim', 'swm']: + path = '{}images\{}.{}'.format(d.mountpoint, imagefile, ext) + if os.path.isfile(path) and wim_contains_image(path, imagename): + image['Path'] = path + image['Source'] = letter + if ext == 'swm': + image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) + break + + # Check for network source + if not image: + mount_windows_share() + if not WINDOWS_SERVER['Mounted']: + return None + for ext in ['esd', 'wim', 'swm']: + path = r'\\{}\{}\images\{}.ext'.format( + WINDOWS_SERVER['IP'], WINDOWS_SERVER['Share'], imagefile, ext) + if os.path.isfile(path) and wim_contains_image(path, imagename): + image['Path'] = path + image['Source'] = None + if ext == 'swm': + image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) + break + + # Display image to be used (if any) and return + if image: + print_info('Using image: {}'.format(image['Path'])) + return image + else: + print_error('Failed to find Windows source image for {}'.format( + windows_version['Name'])) + raise GeneralAbort + +def format_disk(disk, use_gpt): + """Format disk for use as a Windows OS disk.""" + if use_gpt: + format_gpt(disk) + else: + format_mbr(disk) + +def format_gpt(disk): + """Format disk for use as a Windows OS disk using the GPT layout.""" + with open(DISKPART_SCRIPT, 'w') as script: + # Partition table + script.write('select disk {}\n'.format(disk['Number'])) + script.write('clean\n') + script.write('convert gpt\n') + + # System partition + # NOTE: ESP needs to be >= 260 for Advanced Format 4K disks + script.write('create partition efi size=500\n') + script.write('format quick fs=fat32 label="System"\n') + script.write('assign letter="S"\n') + + # Microsoft Reserved (MSR) partition + script.write('create partition msr size=128\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery Tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') + + # Run script + run_program(['diskpart', '/s', DISKPART_SCRIPT]) + time.sleep(2) + +def format_mbr(disk): + """Format disk for use as a Windows OS disk using the MBR layout.""" + with open(DISKPART_SCRIPT, 'w') as script: + # Partition table + script.write('select disk {}\n'.format(disk['Number'])) + script.write('clean\n') + + # System partition + script.write('create partition primary size=100\n') + script.write('format fs=ntfs quick label="System Reserved"\n') + script.write('active\n') + script.write('assign letter="S"\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format fs=ntfs quick label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery"\n') + script.write('assign letter="T"\n') + script.write('set id=27\n') + + # Run script + run_program(['diskpart', '/s', DISKPART_SCRIPT]) + time.sleep(2) + +def mount_windows_share(): + """Mount the Windows images share unless labeled as already mounted.""" + if WINDOWS_SERVER['Mounted']: + # Blindly skip if we mounted earlier + continue + + mount_network_share(WINDOWS_SERVER) + +def select_windows_version(): + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Menu loop + selection = menu_select( + title = 'Which version of Windows are we installing?', + main_entries = WINDOWS_VERSIONS, + action_entries = actions) + + if selection.isnumeric(): + return WINDOWS_VERSIONS[int(selection)-1] + elif selection == 'M': + raise GeneralAbort + +def setup_windows(windows_image, windows_version): + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'apply', + windows_image['Path'], + windows_version['Image Name'], + 'W:\\'] + if 'Glob' in windows_image: + cmd.extend(windows_image['Glob']) + run_program(cmd) + +def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): + win = r'{}:\Windows'.format(windows_letter) + winre = r'{}\System32\Recovery\WinRE.wim'.format(win) + dest = r'{}:\Recovery\WindowsRE'.format(tools_letter) + + # Copy WinRE.wim + os.makedirs(dest, exist_ok=True) + shutil.copy(winre, r'{}\WinRE.wim'.format(dest)) + + # Set location + cmd = [ + r'{}\System32\ReAgentc.exe'.format(win), + '/setreimage', + '/path', dest, + '/target', win] + run_program(cmd) + +def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): + cmd = [ + r'{}:\Windows\System32\bcdboot.exe'.format(windows_letter), + r'{}:\Windows'.format(windows_letter), + '/s', '{}:'.format(system_letter), + '/f', mode] + run_program(cmd) + +def wim_contains_image(filename, imagename): + cmd = [ + global_vars['Tools']['wimlib-imagex'], + 'info', + filename, + imagename] + try: + run_program(cmd) + except subprocess.CalledProcessError: + return False + + return True + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py similarity index 96% rename from Scripts/functions/winpe_menus.py rename to .bin/Scripts/functions/winpe_menus.py index c6ba4e8c..d7673774 100644 --- a/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -1,380 +1,380 @@ -# Wizard Kit PE: Menus - -from functions.backup import * -from functions.disk import * -from functions.windows_setup import * - -# STATIC VARIABLES -FAST_COPY_PE_ARGS = [ - '/cmd=noexist_only', - '/utf8', - '/skip_empty_dir', - '/linkdest', - '/no_ui', - '/auto_close', - '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), - ] -PE_TOOLS = { - 'BlueScreenView': { - 'Path': r'BlueScreenView\BlueScreenView.exe', - }, - 'FastCopy': { - 'Path': r'FastCopy\FastCopy.exe', - 'Args': FAST_COPY_PE_ARGS, - }, - 'HWiNFO': { - 'Path': r'HWiNFO\HWiNFO.exe', - }, - 'NT Password Editor': { - 'Path': r'NT Password Editor\ntpwedit.exe', - }, - 'Notepad++': { - 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', - }, - 'PhotoRec': { - 'Path': r'TestDisk\photorec_win.exe', - 'Args': ['-new_console:n'], - }, - 'Prime95': { - 'Path': r'Prime95\prime95.exe', - }, - 'ProduKey': { - 'Path': r'ProduKey\ProduKey.exe', - }, - 'Q-Dir': { - 'Path': r'Q-Dir\Q-Dir.exe', - }, - 'TestDisk': { - 'Path': r'TestDisk\testdisk_win.exe', - 'Args': ['-new_console:n'], - }, - } - -def menu_backup(): - """Take backup images of partition(s) in the WIM format.""" - errors = False - other_results = { - 'Error': { - 'CalledProcessError': 'Unknown Error', - 'PathNotFoundError': 'Missing', - }, - 'Warning': { - 'GenericAbort': 'Skipped', - 'GenericRepair': 'Repaired', - }} - set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) - - # Set ticket Number - clear_screen() - ticket_number = get_ticket_number() - - # Mount backup shares - mount_backup_shares() - - # Select destination - destination = select_backup_destination() - - # Scan disks - try_and_print( - message = 'Assigning letters...', - function = assign_volume_letters, - other_results = other_results) - result = try_and_print( - message = 'Getting disk info...', - function = scan_disks, - other_results = other_results) - if result['CS']: - disks = result['Out'] - else: - print_error('ERROR: No disks found.') - raise GenericAbort - - # Select disk to backup - disk = select_disk('For which disk are we creating backups?', disks) - if not disk: - raise GenericAbort - - # "Prep" disk - prep_disk_for_backup(destination, disk, ticket_number) - - # Display details for backup task - clear_screen() - print_info('Create Backup - Details:\n') - show_info(message='Ticket:', info=ticket_number) - show_info( - message = 'Source:', - info = '[{Table}] ({Type}) {Name} {Size}'.format(**disk), - ) - show_info( - message = 'Destination:', - info = destination.get('Display Name', destination['Name']), - ) - for par in disk['Partitions']: - show_info(message='', info=par['Display String'], width=20) - print_standard(disk['Backup Warnings']) - - # Ask to proceed - if (not ask('Proceed with backup?')): - raise GenericAbort - - # Backup partition(s) - print_info('\n\nStarting task.\n') - for par in disk['Partitions']: - result = try_and_print( - message = 'Partition {} Backup...'.format(par['Number']), - function = backup_partition, - other_results = other_results, - disk = disk, - partition = par) - if not result['CS']: - errors = True - par['Error'] = result['Error'] - - # Verify backup(s) - if disk['Valid Partitions']: - print_info('\n\n Verifying backup images(s)\n') - for par in disk['Partitions']: - if par['Number'] in disk['Bad Partitions']: - continue # Skip verification - result = try_and_print( - message = 'Partition {} Image...'.format(par['Number']), - function = verify_wim_backup, - other_results = other_results, - partition = par) - if not result['CS']: - errors = True - par['Error'] = result['Error'] - - # Print summary - if errors: - print_warning('\nErrors were encountered and are detailed below.') - for par in [p for p in disk['Partitions'] if 'Error' in p]: - print_standard(' Partition {} Error:'.format(par['Number'])) - if hasattr(par['Error'], 'stderr'): - try: - par['Error'] = par['Error'].stderr.decode() - except: - # Deal with badly formatted error message - pass - if isinstance(par['Error'], basestring): - print_error('\t{}'.format(par['Error'])) - else: - try: - par['Error'] = par['Error'].splitlines() - par['Error'] = [line.strip() for line in par['Error']] - par['Error'] = [line for line in par['Error'] if line] - except: - pass - for line in par['Error']: - print_error('\t{}'.format(line)) - time.sleep(30) - else: - print_success('\nNo errors were encountered during imaging.') - time.sleep(5) - pause('\nPress Enter to return to main menu... ') - -def menu_root(): - menus = [ - {'Name': 'Create Backups', 'Menu': menu_backup}, - {'Name': 'Setup Windows', 'Menu': menu_setup}, - {'Name': 'Misc Tools', 'Menu': menu_tools}, - ] - actions = [ - {'Name': 'Command Prompt', 'Letter': 'C'}, - {'Name': 'Reboot', 'Letter': 'R'}, - {'Name': 'Shutdown', 'Letter': 'S'}, - ] - - # Main loop - while True: - set_title(KIT_NAME_FULL) - selection = menu_select( - title = 'Main Menu', - main_entries = menus, - action_entries = actions, - secret_exit = True) - - if (selection.isnumeric()): - try: - menus[int(selection)-1]['Menu']() - except AbortError: - pass - elif (selection == 'C'): - run_program(['cmd', '-new_console:n'], check=False) - elif (selection == 'R'): - run_program(['wpeutil', 'reboot']) - elif (selection == 'S'): - run_program(['wpeutil', 'shutdown']) - else: - exit_script() - -def menu_setup(): - """Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" - errors = False - set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) - - # Set ticket ID - clear_screen() - ticket_number = get_ticket_number() - - # Select the version of Windows to apply - windows_version = select_windows_version() - - # Find Windows image - windows_image = find_windows_image(windows_version) - - # Scan disks - try_and_print( - message = 'Assigning letters...', - function = assign_volume_letters, - other_results = other_results) - result = try_and_print( - message = 'Getting disk info...', - function = scan_disks, - other_results = other_results) - if result['CS']: - disks = result['Out'] - else: - print_error('ERROR: No disks found.') - raise GenericAbort - - # Select disk to use as the OS disk - dest_disk = select_disk('To which disk are we installing Windows?', disks) - if not disk: - raise GenericAbort - - # "Prep" disk - prep_disk_for_formatting(dest_disk) - - # Display details for setup task - clear_screen() - print_info('Setup Windows - Details:\n') - show_info(message='Ticket:', info=ticket_number) - show_info(message='Installing:', info=windows_version['Name']) - show_info( - message = 'Boot Method:', - info = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') - show_info(message='Using Image:', info=windows_version['Path']) - print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format( - **dest_disk)) - for par in dest_disk['Partitions']: - print_warning(par['Display String']) - print_warning(dest_disk['Format Warnings']) - - if (not ask('Is this correct?')): - raise GeneralAbort - - # Safety check - print_standard('\nSAFETY CHECK') - print_warning('All data will be DELETED from the ' - 'disk & partition(s) listed above.') - print_warning('This is irreversible and will lead ' - 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) - if (not ask('Asking again to confirm, is this correct?')): - raise GeneralAbort - - # Remove volume letters so S, T, & W can be used below - remove_volume_letters(keep=windows_image['Source']) - new_letter = reassign_volume_letter(letter=windows_image['Source']) - if new_letter: - windows_image['Source'] = new_letter - - # Format and partition disk - result = try_and_print( - message = 'Formatting disk...', - function = format_disk, - other_results = other_results, - disk = dest_disk, - use_gpt = dest_disk['Use GPT']) - if not result['CS']: - # We need to crash as the disk is in an unknown state - print_error('ERROR: Failed to format disk.') - raise GenericAbort - - # Apply Image - result = try_and_print( - message = 'Applying image...', - function = setup_windows, - other_results = other_results, - windows_image = windows_image, - windows_version = windows_version) - if not result['CS']: - # We need to crash as the disk is in an unknown state - print_error('ERROR: Failed to apply image.') - raise GenericAbort - - # Create Boot files - try_and_print( - message = 'Updating boot files...', - function = update_boot_partition, - other_results = other_results) - - # Setup WinRE - try_and_print( - message = 'Updating recovery tools...', - function = setup_windows_re, - other_results = other_results, - windows_version = windows_version) - - # Print summary - print_standard('\nDone.') - pause('\nPress Enter to return to main menu... ') - -def menu_tools(): - tools = [k for k in sorted(PE_TOOLS.keys())] - actions = [{'Name': 'Main Menu', 'Letter': 'M'},] - set_title(KIT_NAME_FULL) - - # Menu loop - while True: - selection = menu_select( - title = 'Tools Menu', - main_entries = tools, - action_entries = actions) - if (selection.isnumeric()): - tool = tools[int(selection)-1] - cmd = [PE_TOOLS[tool]['Path']] + PE_TOOLS[tool].get('Args', []) - if tool == 'Blue Screen View': - # Select path to scan - minidump_path = select_minidump_path() - if minidump_path: - cmd.extend(['/MiniDumpFolder', minidump_path]) - try: - popen_program(cmd) - except Exception: - print_error('Failed to run {prog}'.format(prog=tool['Name'])) - time.sleep(2) - pause() - elif (selection == 'M'): - break - -def select_minidump_path(): - dumps = [] - - # Assign volume letters first - assign_volume_letters() - - # Search for minidumps - tmp = run_program('mountvol') - tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] - # Remove RAMDisk letter - if 'X' in tmp: - tmp.remove('X') - for disk in tmp: - if os.path.exists('{}:\\Windows\\MiniDump'.format(disk)): - dumps.append({'Name': '{}:\\Windows\\MiniDump'.format(disk)}) - - # Check results before showing menu - if len(dumps) == 0: - print_error(' No BSoD / MiniDump paths found') - time.sleep(2) - return None - - # Menu - selection = menu_select( - title = 'Which BSoD / MiniDump path are we scanning?', - main_entries = dumps) - return dumps[int(selection) - 1]['Name'] - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Menus + +from functions.backup import * +from functions.disk import * +from functions.windows_setup import * + +# STATIC VARIABLES +FAST_COPY_PE_ARGS = [ + '/cmd=noexist_only', + '/utf8', + '/skip_empty_dir', + '/linkdest', + '/no_ui', + '/auto_close', + '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), + ] +PE_TOOLS = { + 'BlueScreenView': { + 'Path': r'BlueScreenView\BlueScreenView.exe', + }, + 'FastCopy': { + 'Path': r'FastCopy\FastCopy.exe', + 'Args': FAST_COPY_PE_ARGS, + }, + 'HWiNFO': { + 'Path': r'HWiNFO\HWiNFO.exe', + }, + 'NT Password Editor': { + 'Path': r'NT Password Editor\ntpwedit.exe', + }, + 'Notepad++': { + 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', + }, + 'PhotoRec': { + 'Path': r'TestDisk\photorec_win.exe', + 'Args': ['-new_console:n'], + }, + 'Prime95': { + 'Path': r'Prime95\prime95.exe', + }, + 'ProduKey': { + 'Path': r'ProduKey\ProduKey.exe', + }, + 'Q-Dir': { + 'Path': r'Q-Dir\Q-Dir.exe', + }, + 'TestDisk': { + 'Path': r'TestDisk\testdisk_win.exe', + 'Args': ['-new_console:n'], + }, + } + +def menu_backup(): + """Take backup images of partition(s) in the WIM format.""" + errors = False + other_results = { + 'Error': { + 'CalledProcessError': 'Unknown Error', + 'PathNotFoundError': 'Missing', + }, + 'Warning': { + 'GenericAbort': 'Skipped', + 'GenericRepair': 'Repaired', + }} + set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) + + # Set ticket Number + clear_screen() + ticket_number = get_ticket_number() + + # Mount backup shares + mount_backup_shares() + + # Select destination + destination = select_backup_destination() + + # Scan disks + try_and_print( + message = 'Assigning letters...', + function = assign_volume_letters, + other_results = other_results) + result = try_and_print( + message = 'Getting disk info...', + function = scan_disks, + other_results = other_results) + if result['CS']: + disks = result['Out'] + else: + print_error('ERROR: No disks found.') + raise GenericAbort + + # Select disk to backup + disk = select_disk('For which disk are we creating backups?', disks) + if not disk: + raise GenericAbort + + # "Prep" disk + prep_disk_for_backup(destination, disk, ticket_number) + + # Display details for backup task + clear_screen() + print_info('Create Backup - Details:\n') + show_info(message='Ticket:', info=ticket_number) + show_info( + message = 'Source:', + info = '[{Table}] ({Type}) {Name} {Size}'.format(**disk), + ) + show_info( + message = 'Destination:', + info = destination.get('Display Name', destination['Name']), + ) + for par in disk['Partitions']: + show_info(message='', info=par['Display String'], width=20) + print_standard(disk['Backup Warnings']) + + # Ask to proceed + if (not ask('Proceed with backup?')): + raise GenericAbort + + # Backup partition(s) + print_info('\n\nStarting task.\n') + for par in disk['Partitions']: + result = try_and_print( + message = 'Partition {} Backup...'.format(par['Number']), + function = backup_partition, + other_results = other_results, + disk = disk, + partition = par) + if not result['CS']: + errors = True + par['Error'] = result['Error'] + + # Verify backup(s) + if disk['Valid Partitions']: + print_info('\n\n Verifying backup images(s)\n') + for par in disk['Partitions']: + if par['Number'] in disk['Bad Partitions']: + continue # Skip verification + result = try_and_print( + message = 'Partition {} Image...'.format(par['Number']), + function = verify_wim_backup, + other_results = other_results, + partition = par) + if not result['CS']: + errors = True + par['Error'] = result['Error'] + + # Print summary + if errors: + print_warning('\nErrors were encountered and are detailed below.') + for par in [p for p in disk['Partitions'] if 'Error' in p]: + print_standard(' Partition {} Error:'.format(par['Number'])) + if hasattr(par['Error'], 'stderr'): + try: + par['Error'] = par['Error'].stderr.decode() + except: + # Deal with badly formatted error message + pass + if isinstance(par['Error'], basestring): + print_error('\t{}'.format(par['Error'])) + else: + try: + par['Error'] = par['Error'].splitlines() + par['Error'] = [line.strip() for line in par['Error']] + par['Error'] = [line for line in par['Error'] if line] + except: + pass + for line in par['Error']: + print_error('\t{}'.format(line)) + time.sleep(30) + else: + print_success('\nNo errors were encountered during imaging.') + time.sleep(5) + pause('\nPress Enter to return to main menu... ') + +def menu_root(): + menus = [ + {'Name': 'Create Backups', 'Menu': menu_backup}, + {'Name': 'Setup Windows', 'Menu': menu_setup}, + {'Name': 'Misc Tools', 'Menu': menu_tools}, + ] + actions = [ + {'Name': 'Command Prompt', 'Letter': 'C'}, + {'Name': 'Reboot', 'Letter': 'R'}, + {'Name': 'Shutdown', 'Letter': 'S'}, + ] + + # Main loop + while True: + set_title(KIT_NAME_FULL) + selection = menu_select( + title = 'Main Menu', + main_entries = menus, + action_entries = actions, + secret_exit = True) + + if (selection.isnumeric()): + try: + menus[int(selection)-1]['Menu']() + except AbortError: + pass + elif (selection == 'C'): + run_program(['cmd', '-new_console:n'], check=False) + elif (selection == 'R'): + run_program(['wpeutil', 'reboot']) + elif (selection == 'S'): + run_program(['wpeutil', 'shutdown']) + else: + exit_script() + +def menu_setup(): + """Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" + errors = False + set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) + + # Set ticket ID + clear_screen() + ticket_number = get_ticket_number() + + # Select the version of Windows to apply + windows_version = select_windows_version() + + # Find Windows image + windows_image = find_windows_image(windows_version) + + # Scan disks + try_and_print( + message = 'Assigning letters...', + function = assign_volume_letters, + other_results = other_results) + result = try_and_print( + message = 'Getting disk info...', + function = scan_disks, + other_results = other_results) + if result['CS']: + disks = result['Out'] + else: + print_error('ERROR: No disks found.') + raise GenericAbort + + # Select disk to use as the OS disk + dest_disk = select_disk('To which disk are we installing Windows?', disks) + if not disk: + raise GenericAbort + + # "Prep" disk + prep_disk_for_formatting(dest_disk) + + # Display details for setup task + clear_screen() + print_info('Setup Windows - Details:\n') + show_info(message='Ticket:', info=ticket_number) + show_info(message='Installing:', info=windows_version['Name']) + show_info( + message = 'Boot Method:', + info = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') + show_info(message='Using Image:', info=windows_version['Path']) + print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format( + **dest_disk)) + for par in dest_disk['Partitions']: + print_warning(par['Display String']) + print_warning(dest_disk['Format Warnings']) + + if (not ask('Is this correct?')): + raise GeneralAbort + + # Safety check + print_standard('\nSAFETY CHECK') + print_warning('All data will be DELETED from the ' + 'disk & partition(s) listed above.') + print_warning('This is irreversible and will lead ' + 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) + if (not ask('Asking again to confirm, is this correct?')): + raise GeneralAbort + + # Remove volume letters so S, T, & W can be used below + remove_volume_letters(keep=windows_image['Source']) + new_letter = reassign_volume_letter(letter=windows_image['Source']) + if new_letter: + windows_image['Source'] = new_letter + + # Format and partition disk + result = try_and_print( + message = 'Formatting disk...', + function = format_disk, + other_results = other_results, + disk = dest_disk, + use_gpt = dest_disk['Use GPT']) + if not result['CS']: + # We need to crash as the disk is in an unknown state + print_error('ERROR: Failed to format disk.') + raise GenericAbort + + # Apply Image + result = try_and_print( + message = 'Applying image...', + function = setup_windows, + other_results = other_results, + windows_image = windows_image, + windows_version = windows_version) + if not result['CS']: + # We need to crash as the disk is in an unknown state + print_error('ERROR: Failed to apply image.') + raise GenericAbort + + # Create Boot files + try_and_print( + message = 'Updating boot files...', + function = update_boot_partition, + other_results = other_results) + + # Setup WinRE + try_and_print( + message = 'Updating recovery tools...', + function = setup_windows_re, + other_results = other_results, + windows_version = windows_version) + + # Print summary + print_standard('\nDone.') + pause('\nPress Enter to return to main menu... ') + +def menu_tools(): + tools = [k for k in sorted(PE_TOOLS.keys())] + actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + set_title(KIT_NAME_FULL) + + # Menu loop + while True: + selection = menu_select( + title = 'Tools Menu', + main_entries = tools, + action_entries = actions) + if (selection.isnumeric()): + tool = tools[int(selection)-1] + cmd = [PE_TOOLS[tool]['Path']] + PE_TOOLS[tool].get('Args', []) + if tool == 'Blue Screen View': + # Select path to scan + minidump_path = select_minidump_path() + if minidump_path: + cmd.extend(['/MiniDumpFolder', minidump_path]) + try: + popen_program(cmd) + except Exception: + print_error('Failed to run {prog}'.format(prog=tool['Name'])) + time.sleep(2) + pause() + elif (selection == 'M'): + break + +def select_minidump_path(): + dumps = [] + + # Assign volume letters first + assign_volume_letters() + + # Search for minidumps + tmp = run_program('mountvol') + tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] + # Remove RAMDisk letter + if 'X' in tmp: + tmp.remove('X') + for disk in tmp: + if os.path.exists('{}:\\Windows\\MiniDump'.format(disk)): + dumps.append({'Name': '{}:\\Windows\\MiniDump'.format(disk)}) + + # Check results before showing menu + if len(dumps) == 0: + print_error(' No BSoD / MiniDump paths found') + time.sleep(2) + return None + + # Menu + selection = menu_select( + title = 'Which BSoD / MiniDump path are we scanning?', + main_entries = dumps) + return dumps[int(selection) - 1]['Name'] + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/settings/main.py b/.bin/Scripts/settings/main.py similarity index 97% rename from Scripts/settings/main.py rename to .bin/Scripts/settings/main.py index 4b1d9818..43066c55 100644 --- a/Scripts/settings/main.py +++ b/.bin/Scripts/settings/main.py @@ -1,68 +1,68 @@ -# Wizard Kit PE: Settings - Main / Branding - -# Features -ENABLED_UPLOAD_DATA = False - -# STATIC VARIABLES (also used by .cmd files) -## Not using spaces aroung '=' for easier .cmd substrings -ARCHIVE_PASSWORD='Abracadabra' -KIT_NAME_FULL='Wizard Kit PE' -KIT_NAME_SHORT='WKPE' -OFFICE_SERVER_IP='10.0.0.10' -QUICKBOOKS_SERVER_IP='10.0.0.10' -SUPPORT_MESSAGE='Please let 2Shirt know by opening an issue on GitHub' -TIME_ZONE='Pacific Standard Time' # Always use "Standard Time" (DST is applied correctly) - -# SERVER VARIABLES -## NOTE: Windows can only use one user per server. This means that if -## one server serves multiple shares then you have to use the same -## user/password for all of those shares. -BACKUP_SERVERS = [ - { 'IP': '10.0.0.10', - 'Name': 'ServerOne', - 'Mounted': False, - 'Share': 'Backups', - 'User': 'restore', - 'Pass': 'Abracadabra', - }, - { 'IP': '10.0.0.11', - 'Name': 'ServerTwo', - 'Mounted': False, - 'Share': 'Backups', - 'User': 'restore', - 'Pass': 'Abracadabra', - }, -] -CLIENT_INFO_SERVER = { - 'IP': '10.0.0.10', - 'RegEntry': r'0x10001,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - 'Share': '/srv/ClientInfo', - 'User': 'upload', -} -OFFICE_SERVER = { - 'IP': OFFICE_SERVER_IP, - 'Name': 'ServerOne', - 'Mounted': False, - 'Share': 'Office', - 'User': 'restore', - 'Pass': 'Abracadabra', -} -QUICKBOOKS_SERVER = { - 'IP': QUICKBOOKS_SERVER_IP, - 'Name': 'ServerOne', - 'Mounted': False, - 'Share': 'QuickBooks', - 'User': 'restore', - 'Pass': 'Abracadabra', -} -WINDOWS_SERVER = { - 'IP': '10.0.0.10', - 'Name': 'ServerOne', - 'Mounted': False, - 'Share': 'Windows', - 'User': 'restore', - 'Pass': 'Abracadabra', -} - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Settings - Main / Branding + +# Features +ENABLED_UPLOAD_DATA = False + +# STATIC VARIABLES (also used by .cmd files) +## Not using spaces aroung '=' for easier .cmd substrings +ARCHIVE_PASSWORD='Abracadabra' +KIT_NAME_FULL='Wizard Kit PE' +KIT_NAME_SHORT='WKPE' +OFFICE_SERVER_IP='10.0.0.10' +QUICKBOOKS_SERVER_IP='10.0.0.10' +SUPPORT_MESSAGE='Please let 2Shirt know by opening an issue on GitHub' +TIME_ZONE='Pacific Standard Time' # Always use "Standard Time" (DST is applied correctly) + +# SERVER VARIABLES +## NOTE: Windows can only use one user per server. This means that if +## one server serves multiple shares then you have to use the same +## user/password for all of those shares. +BACKUP_SERVERS = [ + { 'IP': '10.0.0.10', + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Backups', + 'User': 'restore', + 'Pass': 'Abracadabra', + }, + { 'IP': '10.0.0.11', + 'Name': 'ServerTwo', + 'Mounted': False, + 'Share': 'Backups', + 'User': 'restore', + 'Pass': 'Abracadabra', + }, +] +CLIENT_INFO_SERVER = { + 'IP': '10.0.0.10', + 'RegEntry': r'0x10001,0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'Share': '/srv/ClientInfo', + 'User': 'upload', +} +OFFICE_SERVER = { + 'IP': OFFICE_SERVER_IP, + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Office', + 'User': 'restore', + 'Pass': 'Abracadabra', +} +QUICKBOOKS_SERVER = { + 'IP': QUICKBOOKS_SERVER_IP, + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'QuickBooks', + 'User': 'restore', + 'Pass': 'Abracadabra', +} +WINDOWS_SERVER = { + 'IP': '10.0.0.10', + 'Name': 'ServerOne', + 'Mounted': False, + 'Share': 'Windows', + 'User': 'restore', + 'Pass': 'Abracadabra', +} + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/settings/tools.py b/.bin/Scripts/settings/tools.py similarity index 96% rename from Scripts/settings/tools.py rename to .bin/Scripts/settings/tools.py index ab8be9e1..9f9f44be 100644 --- a/Scripts/settings/tools.py +++ b/.bin/Scripts/settings/tools.py @@ -1,55 +1,55 @@ -# Wizard Kit PE: Settings - Tools - -TOOLS = { - # NOTE: BinDir will be prepended to these paths at runtime - 'AIDA64': { - '32': r'AIDA64\aida64.exe'}, - 'AutoRuns': { - '32': r'Autoruns\autoruns.exe', - '64': r'Autoruns\autoruns64.exe'}, - 'BleachBit': { - '32': r'BleachBit\bleachbit_console.exe'}, - 'Caffeine': { - '32': r'Caffeine\caffeine.exe'}, - 'Du': { - '32': r'Du\du.exe', - '64': r'Du\du64.exe'}, - 'ERUNT': { - '32': r'ERUNT\ERUNT.EXE'}, - 'Everything': { - '32': r'Everything\Everything.exe', - '64': r'Everything\Everything64.exe'}, - 'FastCopy': { - '32': r'FastCopy\FastCopy.exe', - '64': r'FastCopy\FastCopy64.exe'}, - 'HitmanPro': { - '32': r'HitmanPro\HitmanPro.exe', - '64': r'HitmanPro\HitmanPro64.exe'}, - 'HWiNFO': { - '32': r'HWiNFO\HWiNFO.exe', - '64': r'HWiNFO\HWiNFO64.exe'}, - 'KVRT': { - '32': r'KVRT\KVRT.exe'}, - 'NotepadPlusPlus': { - '32': r'NotepadPlusPlus\notepadplusplus.exe'}, - 'ProduKey': { - '32': r'ProduKey\ProduKey.exe', - '64': r'ProduKey\ProduKey64.exe'}, - 'PuTTY-PSFTP': { - '32': r'PuTTY\PSFTP.EXE'}, - 'RKill': { - '32': r'RKill\RKill.exe'}, - 'SevenZip': { - '32': r'7-Zip\7za.exe', - '64': r'7-Zip\7za64.exe'}, - 'TDSSKiller': { - '32': r'TDSSKiller\TDSSKiller.exe'}, - 'wimlib-imagex': { - '32': r'wimlib\x32\wimlib-imagex.exe', - '64': r'wimlib\x64\wimlib-imagex.exe'}, - 'XMPlay': { - '32': r'XMPlay\xmplay.exe'}, - } - -if __name__ == '__main__': - print("This file is not meant to be called directly.") +# Wizard Kit PE: Settings - Tools + +TOOLS = { + # NOTE: BinDir will be prepended to these paths at runtime + 'AIDA64': { + '32': r'AIDA64\aida64.exe'}, + 'AutoRuns': { + '32': r'Autoruns\autoruns.exe', + '64': r'Autoruns\autoruns64.exe'}, + 'BleachBit': { + '32': r'BleachBit\bleachbit_console.exe'}, + 'Caffeine': { + '32': r'Caffeine\caffeine.exe'}, + 'Du': { + '32': r'Du\du.exe', + '64': r'Du\du64.exe'}, + 'ERUNT': { + '32': r'ERUNT\ERUNT.EXE'}, + 'Everything': { + '32': r'Everything\Everything.exe', + '64': r'Everything\Everything64.exe'}, + 'FastCopy': { + '32': r'FastCopy\FastCopy.exe', + '64': r'FastCopy\FastCopy64.exe'}, + 'HitmanPro': { + '32': r'HitmanPro\HitmanPro.exe', + '64': r'HitmanPro\HitmanPro64.exe'}, + 'HWiNFO': { + '32': r'HWiNFO\HWiNFO.exe', + '64': r'HWiNFO\HWiNFO64.exe'}, + 'KVRT': { + '32': r'KVRT\KVRT.exe'}, + 'NotepadPlusPlus': { + '32': r'NotepadPlusPlus\notepadplusplus.exe'}, + 'ProduKey': { + '32': r'ProduKey\ProduKey.exe', + '64': r'ProduKey\ProduKey64.exe'}, + 'PuTTY-PSFTP': { + '32': r'PuTTY\PSFTP.EXE'}, + 'RKill': { + '32': r'RKill\RKill.exe'}, + 'SevenZip': { + '32': r'7-Zip\7za.exe', + '64': r'7-Zip\7za64.exe'}, + 'TDSSKiller': { + '32': r'TDSSKiller\TDSSKiller.exe'}, + 'wimlib-imagex': { + '32': r'wimlib\x32\wimlib-imagex.exe', + '64': r'wimlib\x64\wimlib-imagex.exe'}, + 'XMPlay': { + '32': r'XMPlay\xmplay.exe'}, + } + +if __name__ == '__main__': + print("This file is not meant to be called directly.") diff --git a/Scripts/winpe_root_menu.py b/.bin/Scripts/winpe_root_menu.py similarity index 95% rename from Scripts/winpe_root_menu.py rename to .bin/Scripts/winpe_root_menu.py index 4bd39aef..94166876 100644 --- a/Scripts/winpe_root_menu.py +++ b/.bin/Scripts/winpe_root_menu.py @@ -1,23 +1,23 @@ -# Wizard Kit PE: Root Menu - -import os -import sys - -# Init -os.chdir(os.path.dirname(os.path.realpath(__file__))) -sys.path.append(os.getcwd()) -from functions.winpe_menus import * -init_global_vars() -set_title('{}: Root Menu'.format(KIT_NAME_FULL)) -global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) - -if __name__ == '__main__': - try: - menu_root() - except GenericAbort: - # pause('Press Enter to return to main menu... ') - pass - except SystemExit: - pass - except: - major_exception() +# Wizard Kit PE: Root Menu + +import os +import sys + +# Init +os.chdir(os.path.dirname(os.path.realpath(__file__))) +sys.path.append(os.getcwd()) +from functions.winpe_menus import * +init_global_vars() +set_title('{}: Root Menu'.format(KIT_NAME_FULL)) +global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) + +if __name__ == '__main__': + try: + menu_root() + except GenericAbort: + # pause('Press Enter to return to main menu... ') + pass + except SystemExit: + pass + except: + major_exception() diff --git a/.gitignore b/.gitignore index 6e041ca5..74636f9f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,3 @@ **/__pycache__/* -*.bak -*.iso -.bin/tmp -Drivers -Logs -Mount -PEFiles -WK/amd64/ -WK/x86/ +BUILD +OUT_PE diff --git a/System32/Winpeshl.ini b/.pe_items/System32/Winpeshl.ini similarity index 97% rename from System32/Winpeshl.ini rename to .pe_items/System32/Winpeshl.ini index d272162f..a91b5b58 100644 --- a/System32/Winpeshl.ini +++ b/.pe_items/System32/Winpeshl.ini @@ -1,6 +1,6 @@ -[LaunchApp] -[LaunchApps] -wpeinit -wpeutil updatebootinfo -cd /d "%SystemDrive%\.bin" -"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\menu.py" +[LaunchApp] +[LaunchApps] +wpeinit +wpeutil updatebootinfo +cd /d "%SystemDrive%\.bin" +"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\menu.py" diff --git a/.pe_items/System32/menu.cmd b/.pe_items/System32/menu.cmd new file mode 100644 index 00000000..cec35be5 --- /dev/null +++ b/.pe_items/System32/menu.cmd @@ -0,0 +1,2 @@ +@echo off +python "%SystemDrive%\.bin\Scripts\menu.py" diff --git a/WK/_include/CPU-Z/cpuz.ini b/.pe_items/_include/CPU-Z/cpuz.ini similarity index 92% rename from WK/_include/CPU-Z/cpuz.ini rename to .pe_items/_include/CPU-Z/cpuz.ini index e10ce749..13a2674a 100644 --- a/WK/_include/CPU-Z/cpuz.ini +++ b/.pe_items/_include/CPU-Z/cpuz.ini @@ -1,20 +1,20 @@ -[CPU-Z] -VERSION=1.7.7.0 -TextFontName= -TextFontSize=14 -TextFontColor=000080 -LabelFontName= -LabelFontSize=14 -ACPI=1 -PCI=1 -MaxPCIBus=256 -DMI=1 -Sensor=1 -SMBus=1 -Display=1 -UseDisplayAPI=1 -BusClock=1 -Chipset=1 -SPD=1 -XOC=0 -CheckUpdates=0 +[CPU-Z] +VERSION=1.7.7.0 +TextFontName= +TextFontSize=14 +TextFontColor=000080 +LabelFontName= +LabelFontSize=14 +ACPI=1 +PCI=1 +MaxPCIBus=256 +DMI=1 +Sensor=1 +SMBus=1 +Display=1 +UseDisplayAPI=1 +BusClock=1 +Chipset=1 +SPD=1 +XOC=0 +CheckUpdates=0 diff --git a/WK/_include/ConEmu/ConEmu.xml b/.pe_items/_include/ConEmu/ConEmu.xml similarity index 98% rename from WK/_include/ConEmu/ConEmu.xml rename to .pe_items/_include/ConEmu/ConEmu.xml index 8a2049b9..43160e68 100644 --- a/WK/_include/ConEmu/ConEmu.xml +++ b/.pe_items/_include/ConEmu/ConEmu.xml @@ -1,765 +1,765 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/_include/HWiNFO/HWiNFO.INI b/.pe_items/_include/HWiNFO/HWiNFO.INI similarity index 95% rename from WK/_include/HWiNFO/HWiNFO.INI rename to .pe_items/_include/HWiNFO/HWiNFO.INI index 74cf2a3e..24a5d535 100644 --- a/WK/_include/HWiNFO/HWiNFO.INI +++ b/.pe_items/_include/HWiNFO/HWiNFO.INI @@ -1,671 +1,671 @@ -[Benchmark_CPU] -Intel Pentium-100=707 -Intel Pentium-120/Notebook=835 -Intel Pentium-166/QDI=1380 -Cyrix 6x86MX-PR300=1411 -AMD-K6-166/QDI=1482 -Intel Pentium MMX-200=1484 -Cyrix MII-PR333=1518 -Intel Mobile Pentium MMX-233=1642 -Intel Pentium Pro-166 Dual CPU=1679 -AMD-K6-200/DTK=1777 -AMD-K6-200/QDI=1778 -Intel Pentium Pro-200=1944 -AMD-K6-233/DTK=2067 -Intel P2-233/Siemens=2350 -VIA Cyrix III 533/133=2362 -Intel Celeron-266/BXmaster=2586 -Intel P2-266/Siemens=2603 -AMD-K6-2-300/PCChips M577=2655 -Intel Celeron 300=2883 -Intel Celeron-300/PCChips=2922 -AMD-K6-2-350/FIC=3092 -AMD-K6-III-400=3524 -AMD-K6-III-400/FIC VA-503A=3557 -Intel Celeron-366/BXmaster=3718 -Intel P2-400/Siemens=3886 -Intel Celeron-400/BXmaster=3890 -AMD-K6-2-450/FIC=3964 -AMD-K6-III-448/FIC VA-503A=3975 -AMD-K6-III-450=3978 -Intel Mobile P2-400/Scenic=4047 -Intel Celeron-413/BXmaster=4175 -Intel Celeron-433=4219 -Intel P3-450/CC820=4363 -Intel P3-450/Siemens=4372 -Intel Celeron-450=4555 -Intel Celeron-300A@467=4686 -Intel Celeron-466/BXmaster=4789 -Intel P3-500/GA-6BXDS=5021 -Intel Pentium III Xeon-550=5299 -Intel Celeron-525/BXmaster=5314 -Intel P3-550/Siemens=5543 -Intel Celeron-550/BXmaster=5579 -Intel Celeron-575/BXmaster=5845 -Intel Celeron-616/BXmaster=5999 -Intel P3-617/GA-BX2000=6241 -AMD Athlon-600/AMD-750=6303 -AMD Duron-600/KT133=6436 -Intel P3-650/BX=6497 -AMD Athlon-650/KX133=6749 -AMD Duron-650/KT133=6971 -Intel P3-700/BX=7013 -AMD Athlon-700/KX133=7185 -AMD Duron-700/KT133=7507 -Intel Celeron-815/BXmaster=7985 -AMD Athlon-750/KT133=8085 -AMD Athlon-800/AMD-750=8286 -AMD Duron-800/KT133=8580 -Intel P3-650@870/BX=8675 -AMD Duron-850/KT133=9120 -Intel P3-650@917/BX=9175 -AMD Duron-900/KT133=9654 -AMD Duron-928 (9x103)=9952 -Intel Celeron-566@1010=10115 -VIA Antaur-1000=6108 -VIA C3-1333=7601 -AMD Duron-950/KT133=10190 -AMD Athlon-1000/KT133=10734 -AMD Athlon-1200/KT133=12949 -AMD Athlon XP 1500+/KT133=14297 -AMD Athlon XP 2000+/KT133A=17691 -AMD Athlon XP 2200+/KT133A=19490 -AMD Athlon XP-M 2500+/KM400=19590 -AMD Athlon XP-M 3000+/SiS748=23391 -Intel P3-1000/i815=10381 -Intel P4-1600=6636 -Intel P4-1800=7445 -Intel P4-2000=8272 -Intel P4-2500=11051 -Intel Pentium-M ULV-1000=10515 -Intel Pentium-M-1300=13590 -Intel Pentium-M-1600=16856 -Intel Pentium-M 735=16958 -Intel Pentium-M 755=20008 -Intel Pentium-M 770=21163 -Intel P4-2800(noHT)/i875P=12399 -Intel P4-3066(noHT)/i845PE=13479 -Intel P4-3000E(noHT)/i915P=22136 -Intel P4-3000 530 (HT)=34013 -Intel P4-3200E(noHT)/i875P=23446 -Intel P4-3600E(noHT)/i925X=26424 -Intel Xeon-3800(HT)=55028 -AMD Athlon64 3200+=23814 -AMD Athlon64 3800+=28731 -AMD Athlon64 FX-53=28727 -AMD Opteron 248=25920 -AMD Turion64 ML-34+=18520 -AMD Turion64 X2 TL-60=47697 -AMD Athlon 64 X2 4400+=52867 -Intel Core Duo T2600 (1core)=20293 -Intel Core Duo T2600 (2core)=40849 -Intel Core 2 Duo E6700=51765 -Intel Core 2 Duo T7400=53238 -Transmeta Crusoe TM5800-1000=6382 -2xIntel Xeon 5150/5000P=131832 -4xIntel Xeon MP 7040=180052 -Intel Core 2 Extreme QX6700=129908 -AMD Phenom 9500=103687 -Intel Atom 230=15438 -Intel Core i5-520M=94834 -Intel Core i7-860=180329 -Intel Core i7-820QM=123279 -Intel Core i7-980X=347501 -Intel Core i5-2520M=111448 -Intel Core i7-3820=265424 - -[Benchmark_FPU] -Intel Pentium-100=1109 -VIA Cyrix III 533/133=1327 -Intel Pentium 120/Notebook=1350 -Intel Pentium Pro-166 Dual CPU=1663 -Intel Pentium Pro-200=1934 -Cyrix 6x86MX-PR300=2304 -Intel P2-233/Siemens=2323 -AMD-K6-166/QDI=2533 -Cyrix MII-PR333=2585 -Intel Celeron-266/BXmaster=2630 -Intel Mobile Pentium MMX-233=2647 -Intel P2-266/Siemens=2662 -Intel Celeron-300=2862 -AMD-K6-200/DTK=2999 -AMD-K6-200/QDI=3041 -AMD-K6-233/DTK=3492 -Intel Celeron-366/BXmaster=3650 -Intel P2-400/Siemens=3968 -Intel Celeron-400/BXmaster=3972 -Intel Mobile P2-400/Scenic=3973 -Intel Celeron-413/BXmaster=4097 -Intel Celeron-433=4304 -Intel P3-450/CC820=4444 -Intel P3-450/Siemens=4452 -Intel Celeron-450=4472 -Intel Celeron-300A@467=4599 -AMD-K6-2-300/PCChips M577=4605 -Intel Celeron-466/BXmaster=4628 -Intel P3-500/GA-6BXDS=4958 -Intel Celeron-525/BXmaster=5215 -AMD-K6-2-350/FIC=5368 -Intel Pentium III Xeon-550=5417 -Intel P3-550/Siemens=5440 -Intel Celeron-550/BXmaster=5477 -Intel Celeron-575/BXmaster=5738 -Intel Celeron-616/BXmaster=5897 -Intel P3-617/GA-BX2000=6114 -AMD-K6-III-400/FIC VA-503A=6166 -AMD-K6-III-400=6169 -Intel P3-650/BX=6446 -AMD-K6-2-450/FIC=6876 -AMD-K6-III-448/FIC VA-503A=6893 -AMD-K6-III-450=6895 -Intel P3-700/BX=6942 -Intel Celeron-815/BXmaster=7799 -Intel P3-650@870/BX=8614 -Intel P3-650@917/BX=9080 -VIA C3-1333=3160 -AMD Duron-600/KT133=9132 -AMD Athlon-600/AMD-750=9231 -AMD Athlon-650/KX133=9888 -Intel Celeron-566@1010=9977 -AMD Athlon-700/KX133=10527 -AMD Athlon-750/KT133=11457 -AMD Athlon-800/AMD-750=12149 -AMD Duron-850/KT133=12954 -AMD Duron-900/KT133=13712 -AMD Duron-928 (9x103)=14150 -AMD Duron-950/KT133=14479 -AMD Athlon-1000/KT133=15252 -AMD Athlon-1200/KT133=18378 -AMD Athlon XP 1500+/KT133=20757 -AMD Athlon XP 1800+=23375 -AMD Athlon XP 2000+/KT133A=25693 -AMD Athlon XP 2200+/KT133A=28296 -AMD Athlon XP-M 2500+/KM400=28877 -AMD Athlon XP-M 3000+/SiS748=34104 -Intel P3-1000/i815=9813 -Intel P4-1600=3282 -Intel P4-1800=3833 -Intel P4-2000=4256 -Intel P4-2500=6020 -Intel Pentium-M ULV-1000=8547 -Intel Pentium-M-1300=11089 -Intel Pentium-M-1600=13614 -Intel Pentium-M 735=14211 -Intel Pentium-M 755=16772 -Intel Pentium-M 770=17807 -Intel P4-2800(noHT)/i875P=6799 -Intel P4-3066(noHT)/i845PE=7396 -Intel P4-3000 530 (HT)=9220 -Intel P4-3200E(noHT)/i875P=6578 -Intel P4-3600E(noHT)/i925X=8163 -Intel Xeon-3800(HT)=17241 -AMD Athlon64 3200+=31194 -AMD Athlon64 3800+=37379 -AMD Athlon64 FX-53=37426 -AMD Opteron 248=34115 -AMD Turion64 ML-34+=28056 -AMD Turion64 X2 TL-60=62143 -AMD Athlon 64 X2 4400+=68974 -Intel Core Duo T2600 (1core)=16967 -Intel Core Duo T2600 (2core)=34039 -Intel Core 2 Duo E6600=36031 -Intel Core 2 Duo E6700=40075 -Intel Core 2 Duo T7400=32659 -Transmeta Crusoe TM5800-1000=4251 -2xIntel Xeon 5150/5000P=80725 -4xIntel Xeon MP 7040=54379 -Intel Core 2 Extreme QX6700=80338 -AMD Phenom 9500=133430 -Intel Atom 230=10769 -Intel Core i5-520M=60634 -Intel Core i7-860=131820 -Intel Core i7-820QM=90751 -Intel Core i7-980X=215620 -Intel Core i5-2520M=55354 -Intel Core i7-3820=130252 - -[Benchmark_MMX] -AMD-K6-166/QDI=909 -AMD-K6-200/QDI=1070 -Intel P2-266/440LX=1339 -VIA Cyrix III 533/133=1815 -Intel Pentium MMX-200=2041 -Intel Mobile Pentium MMX-233=2363 -Intel P2-233/440BX=2390 -Intel Celeron-300=2931 -Intel Celeron-366=3742 -Intel Celeron-450=4602 -Intel Celeron-300A@467=4737 -Intel P3-500/GA-6BXDS=5009 -AMD Duron-600/KT133=5454 -Intel P3-550/Siemens=5513 -AMD Athlon-650/KX133=5906 -AMD Athlon-700/Abit KA7=6356 -Intel P3-650/BX=6490 -AMD Duron-750/KT133=6823 -AMD Athlon-750/KT133=6846 -Intel P3-700/BX=7025 -AMD Duron-800/KT133=7277 -AMD Duron-850/KT133=7738 -AMD Duron-900/KT133=8192 -AMD Duron-928 (9x103)=8448 -AMD Duron-950/KT133=8645 -Intel P3-650@870/BX=8706 -AMD Athlon-1000/KT133=9110 -Intel P3-650@917/BX=9173 -Intel Celeron-566@1010=10080 -VIA C3-1333=6063 -AMD Athlon-1200/KT133=10998 -AMD Athlon XP 1500+/KT133=12125 -AMD Athlon XP 1800+=13642 -AMD Athlon XP 2000+/KT133A=15013 -AMD Athlon XP 2200+/KT133A=16516 -AMD Athlon XP-M 2500+/KM400=16858 -AMD Athlon XP-M 3000+/SiS748=20040 -Intel P3-1000=9903 -Intel P4-1600=14468 -Intel P4-1800=16319 -Intel P4-2000=18140 -Intel P4-2500=22681 -Intel Pentium-M ULV-1000=9937 -Intel Pentium-M-1300=12865 -Intel Pentium-M-1600=15835 -Intel Pentium-M 735=16839 -Intel Pentium-M 755=19869 -Intel Pentium-M 770=21149 -Intel P4-2800(noHT)/i875P=24478 -Intel P4-3066(noHT)/i845PE=26437 -Intel P4-3000 530 (HT)=27352 -Intel P4-3200E(noHT)/i875P=22592 -Intel P4-3600E(noHT)/i925X=25314 -Intel Xeon-3800(HT)=53268 -AMD Athlon64 3200+=18228 -AMD Athlon64 3800+=21859 -AMD Athlon64 FX-53=21856 -AMD Opteron 248=19926 -AMD Turion64 ML-34+=16403 -AMD Turion64 X2 TL-60=36363 -AMD Athlon 64 X2 4400+=40282 -Intel Core Duo T2600 (1core)=21423 -Intel Core Duo T2600 (2core)=42912 -Intel Core 2 Duo E6600=74154 -Intel Core 2 Duo E6700=82312 -Intel Core 2 Duo T7400=67321 -Transmeta Crusoe TM5800-1000=5272 -2xIntel Xeon 5150/5000P=51186 -4xIntel Xeon MP 7040=83086 -Intel Core 2 Extreme QX6700=165067 -AMD Phenom 9500=80202 -Intel Atom 230=14545 -Intel Core i5-520M=80822 -Intel Core i7-860=171336 -Intel Core i7-820QM=115063 -Intel Core i7-980X=261051 -Intel Core i5-2520M=81444 -Intel Core i7-3820=160178 - -[Benchmark_Memory] -Intel Pentium-100/FPM=69 -Intel Pentium Pro-166 Dual CPU=78 -AMD-K6-166/QDI/EDO=85 -Intel Pentium MMX-200/EDO=92 -AMD-K6-200/QDI/EDO=93 -Intel Pentium MMX-233/PC66=101 -Intel P2-233/440BX/PC66=111 -VIA Cyrix III 533/133=114 -Intel P2-266/440BX/PC66=117 -AMD-K6-III-400=135 -Intel Celeron-366/PC66=163 -AMD Duron-600/KT133=173 -AMD Athlon-700/KX133/PC133=202 -AMD Athlon-650/KX133=205 -Intel P3-500/GA-6BXDS/PC100=209 -Intel P3-550/Siemens/PC100=215 -Intel Celeron-300A@467/PC66=209 -Intel Celeron-300/PC66=146 -Intel P3-650/BX/PC100=238 -Intel P3-700/BX/PC100=211 -AMD Athlon-750/KT133/PC133=214 -AMD Duron-750/KT133=263 -Intel Celeron-566@1010=273 -VIA C3-1333/CN400=223 -AMD Duron-950/KT133=275 -AMD Duron-928 (9x103)/KT133=292 -AMD Duron-1100/SiS745/DDR333=477 -AMD Athlon XP-M 2500+/DDR333=548 -Intel P3-650@917/FSB140=310 -Intel P3-1000/PC133=218 -Intel P4-1600/i850=1115 -Intel P4-2000/i850/PC800=1245 -Intel P4-1800/i845G/DDR266=867 -Intel P4-2500/i845/DDR266=757 -Intel Pentium-M-1600/DDR266=830 -Intel Pentium-M 735/855PM/DDR400=971 -Intel P4-3066/i845PE/DDR266=1028 -Intel P4-2800/i875P/2Ch/DDR400=2056 -Intel P4-3200E/i875P/2Ch/DDR400=2342 -Intel P4-3600E/i915P/DDR2-533=2556 -Intel P4-3600E/i925X/DDR2-533=2844 -Intel Xeon-3800/E7525/DDR2-400=1635 -AMD Athlon64 3200+/1Ch/DDR400=1266 -AMD Athlon64 3800+/2Ch/DDR400=2375 -AMD Athlon64 FX-53/2Ch/DDR400=2166 -AMD Opteron 248/DDR266=947 -AMD Turion64 ML-34+=1071 -Intel Core 2 Duo E6700/DDR2-800=2894 -Transmeta Crusoe TM5800-1000=337 -2xIntel Xeon 5150/5000P/DDR2-667F=2919 -4xIntel Xeon MP 7040=1721 -AMD Phenom 9500=1795 -Intel Atom 230/945/DDR2-800=1682 -Intel Core i5-520M=5235 -Intel Core i7-860/DDR3-667/2CH=6506 -Intel Core i7-820QM=5424 -Intel Core i7-980X=9343 -Intel Core i7-3820/DDR3-1600/4CH=13366 - -[Benchmark_Disk_ReadBurst] -Fujitsu MPB3043ATU E/PIO=4.03 -Seagate ST38410A/PIO=4.33 -Maxtor 91021U2/PIO=4.61 -Maxtor 92041U4/PIO=4.82 -Quantum Fireball_TM2110S300X=6.83 -SEAGATE ST51080N=7.92 -Seagate ST31277A=8,37 -IBM DCAS-32160 S65A=8.65 -QUANTUM FIREBALL ST3.2A/PIO=14.74 -Seagate ST39102LW Cheetah=30.05 -IBM DJNA-370910/UDMA66=15.27 -Seagate ST34321A/UDMA33=21.03 -Seagate ST38421A=23.82 -Seagate ST34310A=23.88 -QUANTUM FIREBALL SE2.1A=26.43 -Maxtor 91021U2/UDMA33=29.13 -Maxtor 54098U8/UDMA33=29.5 -IBM DTTA-350430=29.7 -IBM-DPTA-371360=29.86 -Seagate ST320420A=47.3 -IBM-DJNA-371350=27.87 -IBM-DTLA-307030/ATA100=82.22 -SEAGATE Cheetah X15/RAID=137.08 -IBM Deskstar 60GXP/ATA100=81.98 -MAXTOR 4K020H1/ATA100=84.58 -Seagate ST317221A/UDMA66=42.03 -Maxtor 6E040L0=79.36 -Seagate ST380021A/ATA100=73.11 -HITACHI DK23EA-40=80.04 -WDC WD800JB/ATA100=85.71 -TOSHIBA MK4019GAX=83.60 -Maxtor MaxLine III SATA+NCQ=119.96 -ST312002 6AS=106.61 -Maxtor Atlas 10K5 73SCA=145.86 -WDC WD3200YS-01PGB0=167.33 -Hitachi HTE726040M9AT00=84.61 -Seagate ST3160827AS=120.88 -WDC WD5000AADS-00S9B0=122.87 -Hitachi HTS545032B9A=161.10 -Seagate ST1000DM003-9YN1=282.43 - -[Benchmark_Disk_ReadRandom] -Hitachi HTE726040M9AT00=22.82 -Maxtor Atlas 10K5 73SCA=31.61 -Seagate ST3160827AS=32.26 -FUJITSU MHV2080BH=17.79 -TOSHIBA MK8034GSX=18.12 -ST916082 1AS=22.27 -WDC WD5000AADS-00S9B0=24.58 -Hitachi HTS545032B9A=24.72 -Seagate ST1000DM003-9YN1=37.09 - -[Benchmark_Disk_RandomAccess] -SEAGATE ST51080N=20.96 -Quantum Fireball_TM2110S300X=20.74 -Seagate ST34321A/UDMA33=17.21 -Seagate ST38410A/PIO=17.17 -Seagate ST31277A=16.75 -Fujitsu MPB3043ATU E=16.18 -IBM DTTA-350430=16.5 -IBM DCAS-32160 S65A=15.95 -Maxtor 92041U4/PIO=15.81 -Seagate ST34310A=15.56 -Maxtor 91021U2/PIO=15.66 -Seagate ST38421A=15.71 -QUANTUM FIREBALL ST3.2A=15.50 -QUANTUM FIREBALL SE2.1A=14.94 -Maxtor 54098U8/UDMA33=13.77 -Seagate ST320420A=12.57 -IBM DJNA-370910/UDMA66=12.10 -Seagate ST39102LW Cheetah=8.78 -IBM-DPTA-371360=13.37 -IBM-DJNA-371350=13.38 -IBM-DTLA-307030/ATA100=12.44 -IBM-DTLA-307030/ATA100+AAM=22.34 -SEAGATE Cheetah X15/RAID=5.65 -IBM Deskstar 60GXP=12.70 -MAXTOR 4K020H1/ATA100=19.12 -Seagate ST317221A/UDMA66=16.60 -Maxtor 6E040L0=14.52 -Seagate ST380021A/ATA100=14.58 -HITACHI DK23EA-40=19.40 -WDC WD800JB/ATA100=13.61 -TOSHIBA MK4019GAX=18.61 -Maxtor MaxLine III SATA+NCQ=15.82 -ST312002 6AS=12.51 -Maxtor Atlas 10K5 73SCA=10.16 -WDC WD3200YS-01PGB0=13.16 -Hitachi HTE726040M9AT00=12.90 -Seagate ST3160827AS=11.65 -Seagate ST380215A=14.82 -WDC WD5000AADS-00S9B0=17.37 -Hitachi HTS545032B9A=22.16 -Seagate ST1000DM003-9YN1=15.53 - -[LogfileSettings] -COMP=1 -COMP_SP=1 -COMP_Name=1 -COMP_Os=1 -COMP_User=0 -CPU=1 -CPU_Name=1 -CPU_ID=1 -CPU_Vendor=1 -CPU_Stepping=1 -CPU_Type=1 -CPU_BrandID=1 -CPU_PN=1 -CPU_Clock=1 -CPU_MaxFreq=1 -CPU_CacheL1=1 -CPU_CacheL2=1 -CPU_TLB_I=1 -CPU_TLB_D=1 -CPU_Features=1 -CPU_PIROM=1 -MEM=1 -MEM_TotalSize=1 -MEM_Timing=1 -MEM_Row=1 -MEM_Row_Size=1 -MEM_Row_Type=1 -MEM_Row_Speed=1 -MEM_Row_Model=1 -MEM_Row_ECC=1 -MEM_Row_Date=1 -MEM_Row_SN=1 -MEM_Row_Cfg=1 -MEM_Row_Latency=1 -MEM_Row_Features=1 -MEM_Row_iFeatures=1 -BUS=1 -BUS_PCI=1 -BUS_PCI_DevName=1 -BUS_PCI_DevNumber=1 -BUS_PCI_Resources=1 -BUS_PCI_Features=1 -BUS_PCI_DevSpecific=1 -BUS_PCIX_Features=1 -BUS_PCIe_Features=1 -BUS_PCI_DRV_INFO=1 -BUS_EISA=1 -DMI=1 -DMI_0=1 -DMI_1=1 -DMI_2=1 -DMI_3=1 -DMI_4=1 -DMI_5=1 -DMI_6=1 -DMI_7=1 -DMI_8=1 -DMI_9=1 -DMI_10=1 -DMI_11=1 -DMI_12=1 -DMI_13=1 -DMI_14=1 -DMI_15=1 -DMI_16=1 -DMI_17=1 -DMI_18=1 -DMI_19=1 -DMI_20=1 -DMI_21=1 -DMI_22=1 -DMI_23=1 -DMI_24=1 -DMI_25=1 -DMI_26=1 -DMI_27=1 -DMI_28=1 -DMI_29=1 -DMI_30=1 -DMI_31=1 -DMI_32=1 -DMI_33=1 -DMI_34=1 -DMI_35=1 -DMI_36=1 -DMI_37=1 -DMI_38=1 -DMI_39=1 -DMI_129=1 -DMI_130=1 -DMI_131=1 -VIDEO=1 -VIDEO_Chipset=1 -VIDEO_Memory=1 -VIDEO_Card=1 -VIDEO_Bus=1 -VIDEO_RAMDAC=1 -VIDEO_BIOSver=1 -VIDEO_Clock=1 -VIDEO_HWID=1 -VIDEO_DRV_INFO=1 -VIDEO_DirectX=1 -MON=1 -MON_Name=1 -MON_SN=1 -MON_Date=1 -MON_Dimensions=1 -MON_DisplayType=1 -MON_InputSignal=1 -MON_Gamma=1 -MON_DPMSinput=1 -MON_DPMSmodes=1 -MOBO=1 -MOBO_Model=1 -MOBO_Chipset=1 -MOBO_CompName=1 -MOBO_MachineType=1 -MOBO_Slots=1 -MOBO_BIOS_Manuf=1 -MOBO_BIOS_Date=1 -MOBO_PNP_Devs=1 -MOBO_PNP_Nodes=1 -MOBO_ACPI_Devs=1 -MOBO_ACPI_Enum=1 -DRIVE=1 -DRIVE_IDE=1 -DRIVE_IDE_Ctrller=1 -DRIVE_IDE_Channel=1 -DRIVE_IDE_Model=1 -DRIVE_IDE_Rev=1 -DRIVE_IDE_SN=1 -DRIVE_IDE_Capacity=1 -DRIVE_IDE_Geometry=1 -DRIVE_IDE_Cache=1 -DRIVE_IDE_Xfer=1 -DRIVE_IDE_BasicCapab=1 -DRIVE_IDE_ATA2Capab=1 -DRIVE_IDE_SMART=1 -DRIVE_SCSI=1 -DRIVE_SCSI_ID=1 -DRIVE_SCSI_Desc=1 -DRIVE_SCSI_Class=1 -DRIVE_Floppy=1 -NETWORK=1 -NETWORK_HWID=1 -NETWORK_DRV_INFO=1 -AUDIO=1 -AUDIO_DRV_INFO=1 -AUDIO_HWID=1 -PORTS=1 -BUS_USB=1 -BUS_USB_DRV_INFO=1 -BATTERY=1 -SENSORS=1 - -[Settings] -HighestIdeAddress=0 -AcpiEnum=0 -SWSMI=1 -DebugMode=0 -SMBus=1 -TempScale=C -AC97CodecID=1 -SkipProblematicPciDev=0 -GPUI2C=1 -LPC=1 -DefReportType=5 -TPM=0 -PCIdirect=1 -OpenSystemSummary=0 -RememberPreferences=1 -LargeFonts=0 -OpenSensors=0 -MinimalizeMainWnd=0 -MinimalizeSensors=0 -PersistentDriver=0 -UseHPET=1 -AutoUpdate=0 -GPUI2CNVAPI=1 -GPUI2CADL=0 -SensorsOnly=0 -AcpiEval=1 -CpuClkFromBusClk=1 -BusClkPolling=1 -SMBusAdrExclude=11111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 -GPUI2CBusExclude=00000000 -SensorsSM=1 -IoctlKernel=0 -SummaryOnly=0 -WakeGPUs=1 -KeepTheme=0 -FlushBuffers=1 -iMEsupport=1 -GPUI2Ccaching=1 -CSMI_SAS_Support=1 -DebugDirect=1 -MinimalizeSensorsClose=0 -WakeGPUsExt=0 -PollSleepingGPUs=0 -ShowWelcomeAndProgress=1 -EnablePchTherm=0 -ReorderGPUs=1 -NvmlSupport=1 -DecimalSeparator=. -ThousandsSeparator=, -CsvSeparator=, -MinimizeGraphs=1 -TextButtons=0 +[Benchmark_CPU] +Intel Pentium-100=707 +Intel Pentium-120/Notebook=835 +Intel Pentium-166/QDI=1380 +Cyrix 6x86MX-PR300=1411 +AMD-K6-166/QDI=1482 +Intel Pentium MMX-200=1484 +Cyrix MII-PR333=1518 +Intel Mobile Pentium MMX-233=1642 +Intel Pentium Pro-166 Dual CPU=1679 +AMD-K6-200/DTK=1777 +AMD-K6-200/QDI=1778 +Intel Pentium Pro-200=1944 +AMD-K6-233/DTK=2067 +Intel P2-233/Siemens=2350 +VIA Cyrix III 533/133=2362 +Intel Celeron-266/BXmaster=2586 +Intel P2-266/Siemens=2603 +AMD-K6-2-300/PCChips M577=2655 +Intel Celeron 300=2883 +Intel Celeron-300/PCChips=2922 +AMD-K6-2-350/FIC=3092 +AMD-K6-III-400=3524 +AMD-K6-III-400/FIC VA-503A=3557 +Intel Celeron-366/BXmaster=3718 +Intel P2-400/Siemens=3886 +Intel Celeron-400/BXmaster=3890 +AMD-K6-2-450/FIC=3964 +AMD-K6-III-448/FIC VA-503A=3975 +AMD-K6-III-450=3978 +Intel Mobile P2-400/Scenic=4047 +Intel Celeron-413/BXmaster=4175 +Intel Celeron-433=4219 +Intel P3-450/CC820=4363 +Intel P3-450/Siemens=4372 +Intel Celeron-450=4555 +Intel Celeron-300A@467=4686 +Intel Celeron-466/BXmaster=4789 +Intel P3-500/GA-6BXDS=5021 +Intel Pentium III Xeon-550=5299 +Intel Celeron-525/BXmaster=5314 +Intel P3-550/Siemens=5543 +Intel Celeron-550/BXmaster=5579 +Intel Celeron-575/BXmaster=5845 +Intel Celeron-616/BXmaster=5999 +Intel P3-617/GA-BX2000=6241 +AMD Athlon-600/AMD-750=6303 +AMD Duron-600/KT133=6436 +Intel P3-650/BX=6497 +AMD Athlon-650/KX133=6749 +AMD Duron-650/KT133=6971 +Intel P3-700/BX=7013 +AMD Athlon-700/KX133=7185 +AMD Duron-700/KT133=7507 +Intel Celeron-815/BXmaster=7985 +AMD Athlon-750/KT133=8085 +AMD Athlon-800/AMD-750=8286 +AMD Duron-800/KT133=8580 +Intel P3-650@870/BX=8675 +AMD Duron-850/KT133=9120 +Intel P3-650@917/BX=9175 +AMD Duron-900/KT133=9654 +AMD Duron-928 (9x103)=9952 +Intel Celeron-566@1010=10115 +VIA Antaur-1000=6108 +VIA C3-1333=7601 +AMD Duron-950/KT133=10190 +AMD Athlon-1000/KT133=10734 +AMD Athlon-1200/KT133=12949 +AMD Athlon XP 1500+/KT133=14297 +AMD Athlon XP 2000+/KT133A=17691 +AMD Athlon XP 2200+/KT133A=19490 +AMD Athlon XP-M 2500+/KM400=19590 +AMD Athlon XP-M 3000+/SiS748=23391 +Intel P3-1000/i815=10381 +Intel P4-1600=6636 +Intel P4-1800=7445 +Intel P4-2000=8272 +Intel P4-2500=11051 +Intel Pentium-M ULV-1000=10515 +Intel Pentium-M-1300=13590 +Intel Pentium-M-1600=16856 +Intel Pentium-M 735=16958 +Intel Pentium-M 755=20008 +Intel Pentium-M 770=21163 +Intel P4-2800(noHT)/i875P=12399 +Intel P4-3066(noHT)/i845PE=13479 +Intel P4-3000E(noHT)/i915P=22136 +Intel P4-3000 530 (HT)=34013 +Intel P4-3200E(noHT)/i875P=23446 +Intel P4-3600E(noHT)/i925X=26424 +Intel Xeon-3800(HT)=55028 +AMD Athlon64 3200+=23814 +AMD Athlon64 3800+=28731 +AMD Athlon64 FX-53=28727 +AMD Opteron 248=25920 +AMD Turion64 ML-34+=18520 +AMD Turion64 X2 TL-60=47697 +AMD Athlon 64 X2 4400+=52867 +Intel Core Duo T2600 (1core)=20293 +Intel Core Duo T2600 (2core)=40849 +Intel Core 2 Duo E6700=51765 +Intel Core 2 Duo T7400=53238 +Transmeta Crusoe TM5800-1000=6382 +2xIntel Xeon 5150/5000P=131832 +4xIntel Xeon MP 7040=180052 +Intel Core 2 Extreme QX6700=129908 +AMD Phenom 9500=103687 +Intel Atom 230=15438 +Intel Core i5-520M=94834 +Intel Core i7-860=180329 +Intel Core i7-820QM=123279 +Intel Core i7-980X=347501 +Intel Core i5-2520M=111448 +Intel Core i7-3820=265424 + +[Benchmark_FPU] +Intel Pentium-100=1109 +VIA Cyrix III 533/133=1327 +Intel Pentium 120/Notebook=1350 +Intel Pentium Pro-166 Dual CPU=1663 +Intel Pentium Pro-200=1934 +Cyrix 6x86MX-PR300=2304 +Intel P2-233/Siemens=2323 +AMD-K6-166/QDI=2533 +Cyrix MII-PR333=2585 +Intel Celeron-266/BXmaster=2630 +Intel Mobile Pentium MMX-233=2647 +Intel P2-266/Siemens=2662 +Intel Celeron-300=2862 +AMD-K6-200/DTK=2999 +AMD-K6-200/QDI=3041 +AMD-K6-233/DTK=3492 +Intel Celeron-366/BXmaster=3650 +Intel P2-400/Siemens=3968 +Intel Celeron-400/BXmaster=3972 +Intel Mobile P2-400/Scenic=3973 +Intel Celeron-413/BXmaster=4097 +Intel Celeron-433=4304 +Intel P3-450/CC820=4444 +Intel P3-450/Siemens=4452 +Intel Celeron-450=4472 +Intel Celeron-300A@467=4599 +AMD-K6-2-300/PCChips M577=4605 +Intel Celeron-466/BXmaster=4628 +Intel P3-500/GA-6BXDS=4958 +Intel Celeron-525/BXmaster=5215 +AMD-K6-2-350/FIC=5368 +Intel Pentium III Xeon-550=5417 +Intel P3-550/Siemens=5440 +Intel Celeron-550/BXmaster=5477 +Intel Celeron-575/BXmaster=5738 +Intel Celeron-616/BXmaster=5897 +Intel P3-617/GA-BX2000=6114 +AMD-K6-III-400/FIC VA-503A=6166 +AMD-K6-III-400=6169 +Intel P3-650/BX=6446 +AMD-K6-2-450/FIC=6876 +AMD-K6-III-448/FIC VA-503A=6893 +AMD-K6-III-450=6895 +Intel P3-700/BX=6942 +Intel Celeron-815/BXmaster=7799 +Intel P3-650@870/BX=8614 +Intel P3-650@917/BX=9080 +VIA C3-1333=3160 +AMD Duron-600/KT133=9132 +AMD Athlon-600/AMD-750=9231 +AMD Athlon-650/KX133=9888 +Intel Celeron-566@1010=9977 +AMD Athlon-700/KX133=10527 +AMD Athlon-750/KT133=11457 +AMD Athlon-800/AMD-750=12149 +AMD Duron-850/KT133=12954 +AMD Duron-900/KT133=13712 +AMD Duron-928 (9x103)=14150 +AMD Duron-950/KT133=14479 +AMD Athlon-1000/KT133=15252 +AMD Athlon-1200/KT133=18378 +AMD Athlon XP 1500+/KT133=20757 +AMD Athlon XP 1800+=23375 +AMD Athlon XP 2000+/KT133A=25693 +AMD Athlon XP 2200+/KT133A=28296 +AMD Athlon XP-M 2500+/KM400=28877 +AMD Athlon XP-M 3000+/SiS748=34104 +Intel P3-1000/i815=9813 +Intel P4-1600=3282 +Intel P4-1800=3833 +Intel P4-2000=4256 +Intel P4-2500=6020 +Intel Pentium-M ULV-1000=8547 +Intel Pentium-M-1300=11089 +Intel Pentium-M-1600=13614 +Intel Pentium-M 735=14211 +Intel Pentium-M 755=16772 +Intel Pentium-M 770=17807 +Intel P4-2800(noHT)/i875P=6799 +Intel P4-3066(noHT)/i845PE=7396 +Intel P4-3000 530 (HT)=9220 +Intel P4-3200E(noHT)/i875P=6578 +Intel P4-3600E(noHT)/i925X=8163 +Intel Xeon-3800(HT)=17241 +AMD Athlon64 3200+=31194 +AMD Athlon64 3800+=37379 +AMD Athlon64 FX-53=37426 +AMD Opteron 248=34115 +AMD Turion64 ML-34+=28056 +AMD Turion64 X2 TL-60=62143 +AMD Athlon 64 X2 4400+=68974 +Intel Core Duo T2600 (1core)=16967 +Intel Core Duo T2600 (2core)=34039 +Intel Core 2 Duo E6600=36031 +Intel Core 2 Duo E6700=40075 +Intel Core 2 Duo T7400=32659 +Transmeta Crusoe TM5800-1000=4251 +2xIntel Xeon 5150/5000P=80725 +4xIntel Xeon MP 7040=54379 +Intel Core 2 Extreme QX6700=80338 +AMD Phenom 9500=133430 +Intel Atom 230=10769 +Intel Core i5-520M=60634 +Intel Core i7-860=131820 +Intel Core i7-820QM=90751 +Intel Core i7-980X=215620 +Intel Core i5-2520M=55354 +Intel Core i7-3820=130252 + +[Benchmark_MMX] +AMD-K6-166/QDI=909 +AMD-K6-200/QDI=1070 +Intel P2-266/440LX=1339 +VIA Cyrix III 533/133=1815 +Intel Pentium MMX-200=2041 +Intel Mobile Pentium MMX-233=2363 +Intel P2-233/440BX=2390 +Intel Celeron-300=2931 +Intel Celeron-366=3742 +Intel Celeron-450=4602 +Intel Celeron-300A@467=4737 +Intel P3-500/GA-6BXDS=5009 +AMD Duron-600/KT133=5454 +Intel P3-550/Siemens=5513 +AMD Athlon-650/KX133=5906 +AMD Athlon-700/Abit KA7=6356 +Intel P3-650/BX=6490 +AMD Duron-750/KT133=6823 +AMD Athlon-750/KT133=6846 +Intel P3-700/BX=7025 +AMD Duron-800/KT133=7277 +AMD Duron-850/KT133=7738 +AMD Duron-900/KT133=8192 +AMD Duron-928 (9x103)=8448 +AMD Duron-950/KT133=8645 +Intel P3-650@870/BX=8706 +AMD Athlon-1000/KT133=9110 +Intel P3-650@917/BX=9173 +Intel Celeron-566@1010=10080 +VIA C3-1333=6063 +AMD Athlon-1200/KT133=10998 +AMD Athlon XP 1500+/KT133=12125 +AMD Athlon XP 1800+=13642 +AMD Athlon XP 2000+/KT133A=15013 +AMD Athlon XP 2200+/KT133A=16516 +AMD Athlon XP-M 2500+/KM400=16858 +AMD Athlon XP-M 3000+/SiS748=20040 +Intel P3-1000=9903 +Intel P4-1600=14468 +Intel P4-1800=16319 +Intel P4-2000=18140 +Intel P4-2500=22681 +Intel Pentium-M ULV-1000=9937 +Intel Pentium-M-1300=12865 +Intel Pentium-M-1600=15835 +Intel Pentium-M 735=16839 +Intel Pentium-M 755=19869 +Intel Pentium-M 770=21149 +Intel P4-2800(noHT)/i875P=24478 +Intel P4-3066(noHT)/i845PE=26437 +Intel P4-3000 530 (HT)=27352 +Intel P4-3200E(noHT)/i875P=22592 +Intel P4-3600E(noHT)/i925X=25314 +Intel Xeon-3800(HT)=53268 +AMD Athlon64 3200+=18228 +AMD Athlon64 3800+=21859 +AMD Athlon64 FX-53=21856 +AMD Opteron 248=19926 +AMD Turion64 ML-34+=16403 +AMD Turion64 X2 TL-60=36363 +AMD Athlon 64 X2 4400+=40282 +Intel Core Duo T2600 (1core)=21423 +Intel Core Duo T2600 (2core)=42912 +Intel Core 2 Duo E6600=74154 +Intel Core 2 Duo E6700=82312 +Intel Core 2 Duo T7400=67321 +Transmeta Crusoe TM5800-1000=5272 +2xIntel Xeon 5150/5000P=51186 +4xIntel Xeon MP 7040=83086 +Intel Core 2 Extreme QX6700=165067 +AMD Phenom 9500=80202 +Intel Atom 230=14545 +Intel Core i5-520M=80822 +Intel Core i7-860=171336 +Intel Core i7-820QM=115063 +Intel Core i7-980X=261051 +Intel Core i5-2520M=81444 +Intel Core i7-3820=160178 + +[Benchmark_Memory] +Intel Pentium-100/FPM=69 +Intel Pentium Pro-166 Dual CPU=78 +AMD-K6-166/QDI/EDO=85 +Intel Pentium MMX-200/EDO=92 +AMD-K6-200/QDI/EDO=93 +Intel Pentium MMX-233/PC66=101 +Intel P2-233/440BX/PC66=111 +VIA Cyrix III 533/133=114 +Intel P2-266/440BX/PC66=117 +AMD-K6-III-400=135 +Intel Celeron-366/PC66=163 +AMD Duron-600/KT133=173 +AMD Athlon-700/KX133/PC133=202 +AMD Athlon-650/KX133=205 +Intel P3-500/GA-6BXDS/PC100=209 +Intel P3-550/Siemens/PC100=215 +Intel Celeron-300A@467/PC66=209 +Intel Celeron-300/PC66=146 +Intel P3-650/BX/PC100=238 +Intel P3-700/BX/PC100=211 +AMD Athlon-750/KT133/PC133=214 +AMD Duron-750/KT133=263 +Intel Celeron-566@1010=273 +VIA C3-1333/CN400=223 +AMD Duron-950/KT133=275 +AMD Duron-928 (9x103)/KT133=292 +AMD Duron-1100/SiS745/DDR333=477 +AMD Athlon XP-M 2500+/DDR333=548 +Intel P3-650@917/FSB140=310 +Intel P3-1000/PC133=218 +Intel P4-1600/i850=1115 +Intel P4-2000/i850/PC800=1245 +Intel P4-1800/i845G/DDR266=867 +Intel P4-2500/i845/DDR266=757 +Intel Pentium-M-1600/DDR266=830 +Intel Pentium-M 735/855PM/DDR400=971 +Intel P4-3066/i845PE/DDR266=1028 +Intel P4-2800/i875P/2Ch/DDR400=2056 +Intel P4-3200E/i875P/2Ch/DDR400=2342 +Intel P4-3600E/i915P/DDR2-533=2556 +Intel P4-3600E/i925X/DDR2-533=2844 +Intel Xeon-3800/E7525/DDR2-400=1635 +AMD Athlon64 3200+/1Ch/DDR400=1266 +AMD Athlon64 3800+/2Ch/DDR400=2375 +AMD Athlon64 FX-53/2Ch/DDR400=2166 +AMD Opteron 248/DDR266=947 +AMD Turion64 ML-34+=1071 +Intel Core 2 Duo E6700/DDR2-800=2894 +Transmeta Crusoe TM5800-1000=337 +2xIntel Xeon 5150/5000P/DDR2-667F=2919 +4xIntel Xeon MP 7040=1721 +AMD Phenom 9500=1795 +Intel Atom 230/945/DDR2-800=1682 +Intel Core i5-520M=5235 +Intel Core i7-860/DDR3-667/2CH=6506 +Intel Core i7-820QM=5424 +Intel Core i7-980X=9343 +Intel Core i7-3820/DDR3-1600/4CH=13366 + +[Benchmark_Disk_ReadBurst] +Fujitsu MPB3043ATU E/PIO=4.03 +Seagate ST38410A/PIO=4.33 +Maxtor 91021U2/PIO=4.61 +Maxtor 92041U4/PIO=4.82 +Quantum Fireball_TM2110S300X=6.83 +SEAGATE ST51080N=7.92 +Seagate ST31277A=8,37 +IBM DCAS-32160 S65A=8.65 +QUANTUM FIREBALL ST3.2A/PIO=14.74 +Seagate ST39102LW Cheetah=30.05 +IBM DJNA-370910/UDMA66=15.27 +Seagate ST34321A/UDMA33=21.03 +Seagate ST38421A=23.82 +Seagate ST34310A=23.88 +QUANTUM FIREBALL SE2.1A=26.43 +Maxtor 91021U2/UDMA33=29.13 +Maxtor 54098U8/UDMA33=29.5 +IBM DTTA-350430=29.7 +IBM-DPTA-371360=29.86 +Seagate ST320420A=47.3 +IBM-DJNA-371350=27.87 +IBM-DTLA-307030/ATA100=82.22 +SEAGATE Cheetah X15/RAID=137.08 +IBM Deskstar 60GXP/ATA100=81.98 +MAXTOR 4K020H1/ATA100=84.58 +Seagate ST317221A/UDMA66=42.03 +Maxtor 6E040L0=79.36 +Seagate ST380021A/ATA100=73.11 +HITACHI DK23EA-40=80.04 +WDC WD800JB/ATA100=85.71 +TOSHIBA MK4019GAX=83.60 +Maxtor MaxLine III SATA+NCQ=119.96 +ST312002 6AS=106.61 +Maxtor Atlas 10K5 73SCA=145.86 +WDC WD3200YS-01PGB0=167.33 +Hitachi HTE726040M9AT00=84.61 +Seagate ST3160827AS=120.88 +WDC WD5000AADS-00S9B0=122.87 +Hitachi HTS545032B9A=161.10 +Seagate ST1000DM003-9YN1=282.43 + +[Benchmark_Disk_ReadRandom] +Hitachi HTE726040M9AT00=22.82 +Maxtor Atlas 10K5 73SCA=31.61 +Seagate ST3160827AS=32.26 +FUJITSU MHV2080BH=17.79 +TOSHIBA MK8034GSX=18.12 +ST916082 1AS=22.27 +WDC WD5000AADS-00S9B0=24.58 +Hitachi HTS545032B9A=24.72 +Seagate ST1000DM003-9YN1=37.09 + +[Benchmark_Disk_RandomAccess] +SEAGATE ST51080N=20.96 +Quantum Fireball_TM2110S300X=20.74 +Seagate ST34321A/UDMA33=17.21 +Seagate ST38410A/PIO=17.17 +Seagate ST31277A=16.75 +Fujitsu MPB3043ATU E=16.18 +IBM DTTA-350430=16.5 +IBM DCAS-32160 S65A=15.95 +Maxtor 92041U4/PIO=15.81 +Seagate ST34310A=15.56 +Maxtor 91021U2/PIO=15.66 +Seagate ST38421A=15.71 +QUANTUM FIREBALL ST3.2A=15.50 +QUANTUM FIREBALL SE2.1A=14.94 +Maxtor 54098U8/UDMA33=13.77 +Seagate ST320420A=12.57 +IBM DJNA-370910/UDMA66=12.10 +Seagate ST39102LW Cheetah=8.78 +IBM-DPTA-371360=13.37 +IBM-DJNA-371350=13.38 +IBM-DTLA-307030/ATA100=12.44 +IBM-DTLA-307030/ATA100+AAM=22.34 +SEAGATE Cheetah X15/RAID=5.65 +IBM Deskstar 60GXP=12.70 +MAXTOR 4K020H1/ATA100=19.12 +Seagate ST317221A/UDMA66=16.60 +Maxtor 6E040L0=14.52 +Seagate ST380021A/ATA100=14.58 +HITACHI DK23EA-40=19.40 +WDC WD800JB/ATA100=13.61 +TOSHIBA MK4019GAX=18.61 +Maxtor MaxLine III SATA+NCQ=15.82 +ST312002 6AS=12.51 +Maxtor Atlas 10K5 73SCA=10.16 +WDC WD3200YS-01PGB0=13.16 +Hitachi HTE726040M9AT00=12.90 +Seagate ST3160827AS=11.65 +Seagate ST380215A=14.82 +WDC WD5000AADS-00S9B0=17.37 +Hitachi HTS545032B9A=22.16 +Seagate ST1000DM003-9YN1=15.53 + +[LogfileSettings] +COMP=1 +COMP_SP=1 +COMP_Name=1 +COMP_Os=1 +COMP_User=0 +CPU=1 +CPU_Name=1 +CPU_ID=1 +CPU_Vendor=1 +CPU_Stepping=1 +CPU_Type=1 +CPU_BrandID=1 +CPU_PN=1 +CPU_Clock=1 +CPU_MaxFreq=1 +CPU_CacheL1=1 +CPU_CacheL2=1 +CPU_TLB_I=1 +CPU_TLB_D=1 +CPU_Features=1 +CPU_PIROM=1 +MEM=1 +MEM_TotalSize=1 +MEM_Timing=1 +MEM_Row=1 +MEM_Row_Size=1 +MEM_Row_Type=1 +MEM_Row_Speed=1 +MEM_Row_Model=1 +MEM_Row_ECC=1 +MEM_Row_Date=1 +MEM_Row_SN=1 +MEM_Row_Cfg=1 +MEM_Row_Latency=1 +MEM_Row_Features=1 +MEM_Row_iFeatures=1 +BUS=1 +BUS_PCI=1 +BUS_PCI_DevName=1 +BUS_PCI_DevNumber=1 +BUS_PCI_Resources=1 +BUS_PCI_Features=1 +BUS_PCI_DevSpecific=1 +BUS_PCIX_Features=1 +BUS_PCIe_Features=1 +BUS_PCI_DRV_INFO=1 +BUS_EISA=1 +DMI=1 +DMI_0=1 +DMI_1=1 +DMI_2=1 +DMI_3=1 +DMI_4=1 +DMI_5=1 +DMI_6=1 +DMI_7=1 +DMI_8=1 +DMI_9=1 +DMI_10=1 +DMI_11=1 +DMI_12=1 +DMI_13=1 +DMI_14=1 +DMI_15=1 +DMI_16=1 +DMI_17=1 +DMI_18=1 +DMI_19=1 +DMI_20=1 +DMI_21=1 +DMI_22=1 +DMI_23=1 +DMI_24=1 +DMI_25=1 +DMI_26=1 +DMI_27=1 +DMI_28=1 +DMI_29=1 +DMI_30=1 +DMI_31=1 +DMI_32=1 +DMI_33=1 +DMI_34=1 +DMI_35=1 +DMI_36=1 +DMI_37=1 +DMI_38=1 +DMI_39=1 +DMI_129=1 +DMI_130=1 +DMI_131=1 +VIDEO=1 +VIDEO_Chipset=1 +VIDEO_Memory=1 +VIDEO_Card=1 +VIDEO_Bus=1 +VIDEO_RAMDAC=1 +VIDEO_BIOSver=1 +VIDEO_Clock=1 +VIDEO_HWID=1 +VIDEO_DRV_INFO=1 +VIDEO_DirectX=1 +MON=1 +MON_Name=1 +MON_SN=1 +MON_Date=1 +MON_Dimensions=1 +MON_DisplayType=1 +MON_InputSignal=1 +MON_Gamma=1 +MON_DPMSinput=1 +MON_DPMSmodes=1 +MOBO=1 +MOBO_Model=1 +MOBO_Chipset=1 +MOBO_CompName=1 +MOBO_MachineType=1 +MOBO_Slots=1 +MOBO_BIOS_Manuf=1 +MOBO_BIOS_Date=1 +MOBO_PNP_Devs=1 +MOBO_PNP_Nodes=1 +MOBO_ACPI_Devs=1 +MOBO_ACPI_Enum=1 +DRIVE=1 +DRIVE_IDE=1 +DRIVE_IDE_Ctrller=1 +DRIVE_IDE_Channel=1 +DRIVE_IDE_Model=1 +DRIVE_IDE_Rev=1 +DRIVE_IDE_SN=1 +DRIVE_IDE_Capacity=1 +DRIVE_IDE_Geometry=1 +DRIVE_IDE_Cache=1 +DRIVE_IDE_Xfer=1 +DRIVE_IDE_BasicCapab=1 +DRIVE_IDE_ATA2Capab=1 +DRIVE_IDE_SMART=1 +DRIVE_SCSI=1 +DRIVE_SCSI_ID=1 +DRIVE_SCSI_Desc=1 +DRIVE_SCSI_Class=1 +DRIVE_Floppy=1 +NETWORK=1 +NETWORK_HWID=1 +NETWORK_DRV_INFO=1 +AUDIO=1 +AUDIO_DRV_INFO=1 +AUDIO_HWID=1 +PORTS=1 +BUS_USB=1 +BUS_USB_DRV_INFO=1 +BATTERY=1 +SENSORS=1 + +[Settings] +HighestIdeAddress=0 +AcpiEnum=0 +SWSMI=1 +DebugMode=0 +SMBus=1 +TempScale=C +AC97CodecID=1 +SkipProblematicPciDev=0 +GPUI2C=1 +LPC=1 +DefReportType=5 +TPM=0 +PCIdirect=1 +OpenSystemSummary=0 +RememberPreferences=1 +LargeFonts=0 +OpenSensors=0 +MinimalizeMainWnd=0 +MinimalizeSensors=0 +PersistentDriver=0 +UseHPET=1 +AutoUpdate=0 +GPUI2CNVAPI=1 +GPUI2CADL=0 +SensorsOnly=0 +AcpiEval=1 +CpuClkFromBusClk=1 +BusClkPolling=1 +SMBusAdrExclude=11111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000 +GPUI2CBusExclude=00000000 +SensorsSM=1 +IoctlKernel=0 +SummaryOnly=0 +WakeGPUs=1 +KeepTheme=0 +FlushBuffers=1 +iMEsupport=1 +GPUI2Ccaching=1 +CSMI_SAS_Support=1 +DebugDirect=1 +MinimalizeSensorsClose=0 +WakeGPUsExt=0 +PollSleepingGPUs=0 +ShowWelcomeAndProgress=1 +EnablePchTherm=0 +ReorderGPUs=1 +NvmlSupport=1 +DecimalSeparator=. +ThousandsSeparator=, +CsvSeparator=, +MinimizeGraphs=1 +TextButtons=0 diff --git a/WK/_include/NotepadPlusPlus/config.xml b/.pe_items/_include/NotepadPlusPlus/config.xml similarity index 98% rename from WK/_include/NotepadPlusPlus/config.xml rename to .pe_items/_include/NotepadPlusPlus/config.xml index 999daa1b..8becc843 100644 --- a/WK/_include/NotepadPlusPlus/config.xml +++ b/.pe_items/_include/NotepadPlusPlus/config.xml @@ -1,56 +1,56 @@ - - - - - - standard - hide - - vertical - hide - - no - yes - no - no - yes - yes - no - yes - - - - - yes - yes - 2 - - - - - - hide - - - - - - - - - - yes - - - - - - - - - - - - - - + + + + + + standard + hide + + vertical + hide + + no + yes + no + no + yes + yes + no + yes + + + + + yes + yes + 2 + + + + + + hide + + + + + + + + + + yes + + + + + + + + + + + + + + diff --git a/WK/_include/NotepadPlusPlus/npp.cmd b/.pe_items/_include/NotepadPlusPlus/npp.cmd similarity index 98% rename from WK/_include/NotepadPlusPlus/npp.cmd rename to .pe_items/_include/NotepadPlusPlus/npp.cmd index d387df55..6996dd3c 100644 --- a/WK/_include/NotepadPlusPlus/npp.cmd +++ b/.pe_items/_include/NotepadPlusPlus/npp.cmd @@ -1,3 +1,3 @@ -@echo off - +@echo off + start "" %SystemDrive%\.bin\NotepadPlusPlus\notepadplusplus.exe %2 %3 %4 %5 %6 %7 %8 %9 \ No newline at end of file diff --git a/WK/_include/NotepadPlusPlus/stylers.model.xml b/.pe_items/_include/NotepadPlusPlus/stylers.model.xml similarity index 99% rename from WK/_include/NotepadPlusPlus/stylers.model.xml rename to .pe_items/_include/NotepadPlusPlus/stylers.model.xml index 17235271..a93f074b 100644 --- a/WK/_include/NotepadPlusPlus/stylers.model.xml +++ b/.pe_items/_include/NotepadPlusPlus/stylers.model.xml @@ -1,1371 +1,1371 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/_include/Q-Dir/Q-Dir.ini b/.pe_items/_include/Q-Dir/Q-Dir.ini similarity index 99% rename from WK/_include/Q-Dir/Q-Dir.ini rename to .pe_items/_include/Q-Dir/Q-Dir.ini index ac926a8c..f0daf623 100644 --- a/WK/_include/Q-Dir/Q-Dir.ini +++ b/.pe_items/_include/Q-Dir/Q-Dir.ini @@ -1,68 +1,68 @@ -[Start] -m_lang_id=1 -QDir_Id=0 -useColorStart=1 -Als=12 -designe_mode=2 -showCmd=3 -StartCrash=0 -default_tab= -Max=1 -show_ext_in_type=1 -title_info=1 -adresbar_style=1 -useTreeColor=1 -useColor=1 -[Favoriten] -Ordner=.\Favoriten\ -[Q] -Link=.\Favoriten\Quick-Link\ -[Q-Dir] -Lizenz=1 - - - - - -[Vorschau] -Filter=*.avi;*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.mp*;*.pdf;*.png;*.wm*; -[Filter2] -0=#Hidden=1=-1=1=1=-1=0 -1=*.zip;*.rar;*.gz;*.7z;=1=00AA00=-1=1=-1=0 -2=*.mp*;*.avi;*.wma;=1=DD0058=-1=1=-1=0 -3=#DIR=1=008800=-1=1=-1=0 -4=*.jpg;*.jpeg;*.png,*.gif;*.bmp;*.ico=1=BB00BB=-1=1=-1=0 -5=*.html;*.htm;*.url=1=456789=-1=1=-1=0 -6=*.pl;*.cgi;*.php;*.pdf;*.doc;*.rtf;*.xls=1=BB8844=-1=1=-1=0 -7=*.cpp;*.hpp;*.h=1=DD0058=-1=1=-1=0 -8=*.exe;*.dll;*.bat=1=FF0000=-1=1=-1=0 -9=*=1=0000BB=-1=1=-1=0 -10=#BG=1=-1=-1=1=-1=0 -11=#BG-A=1=-1=-1=1=-1=0 -[Ordner] -Filter= -[Column_OS_6.1_Ploder1] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -Spatlen_291=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%00%00%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%EE%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0E%00%00%00%69%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%91%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0C%00%00%00%46%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%00%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-563719693|772 -[Column_OS_6.1_Ploder2] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Column_OS_6.1_Ploder3] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Column_OS_6.1_Ploder4] -Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 -[Programs_State] -Disable=0 -[Quick-Links] -WK=%systemdrive%/WK -[Options] -Start=7 -[X-Size] -mode=1 -dig=0 -fld_size=1 -ths_sep=1 -type=0 -precent=1 -ff_cnt=1 -block_no_focus=1 -nosort_fld_size=1 +[Start] +m_lang_id=1 +QDir_Id=0 +useColorStart=1 +Als=12 +designe_mode=2 +showCmd=3 +StartCrash=0 +default_tab= +Max=1 +show_ext_in_type=1 +title_info=1 +adresbar_style=1 +useTreeColor=1 +useColor=1 +[Favoriten] +Ordner=.\Favoriten\ +[Q] +Link=.\Favoriten\Quick-Link\ +[Q-Dir] +Lizenz=1 + + + + + +[Vorschau] +Filter=*.avi;*.bmp;*.gif;*.ico;*.jpeg;*.jpg;*.mp*;*.pdf;*.png;*.wm*; +[Filter2] +0=#Hidden=1=-1=1=1=-1=0 +1=*.zip;*.rar;*.gz;*.7z;=1=00AA00=-1=1=-1=0 +2=*.mp*;*.avi;*.wma;=1=DD0058=-1=1=-1=0 +3=#DIR=1=008800=-1=1=-1=0 +4=*.jpg;*.jpeg;*.png,*.gif;*.bmp;*.ico=1=BB00BB=-1=1=-1=0 +5=*.html;*.htm;*.url=1=456789=-1=1=-1=0 +6=*.pl;*.cgi;*.php;*.pdf;*.doc;*.rtf;*.xls=1=BB8844=-1=1=-1=0 +7=*.cpp;*.hpp;*.h=1=DD0058=-1=1=-1=0 +8=*.exe;*.dll;*.bat=1=FF0000=-1=1=-1=0 +9=*=1=0000BB=-1=1=-1=0 +10=#BG=1=-1=-1=1=-1=0 +11=#BG-A=1=-1=-1=1=-1=0 +[Ordner] +Filter= +[Column_OS_6.1_Ploder1] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +Spatlen_291=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%2D%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%30%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%00%00%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%EE%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0E%00%00%00%69%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%91%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0C%00%00%00%46%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%00%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-563719693|772 +[Column_OS_6.1_Ploder2] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder3] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Column_OS_6.1_Ploder4] +Spatlen_::{20D04FE0-3AEA-1069-A2D8-08002B30309D}=%1C%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%F1%F1%F1%F1%14%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%D0%02%00%00%CC%02%00%00%31%53%50%53%05%D5%CD%D5%9C%2E%1B%10%93%97%08%00%2B%2C%F9%AE%83%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%46%00%4D%00%54%00%49%00%44%00%00%00%08%00%00%00%4E%00%00%00%7B%00%42%00%37%00%32%00%35%00%46%00%31%00%33%00%30%00%2D%00%34%00%37%00%45%00%46%00%2D%00%31%00%30%00%31%00%41%00%2D%00%41%00%35%00%46%00%31%00%2D%00%30%00%32%00%36%00%30%00%38%00%43%00%39%00%45%00%45%00%42%00%41%00%43%00%7D%00%00%00%00%00%33%00%00%00%22%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%44%00%69%00%72%00%65%00%63%00%74%00%69%00%6F%00%6E%00%00%00%13%00%00%00%01%00%00%00%5B%00%00%00%0A%00%00%00%00%53%00%6F%00%72%00%74%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%1C%00%00%00%01%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%01%00%00%00%25%00%00%00%14%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%56%00%69%00%65%00%77%00%00%00%0B%00%00%00%FF%FF%00%00%1B%00%00%00%0A%00%00%00%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%04%00%00%00%23%00%00%00%12%00%00%00%00%49%00%63%00%6F%00%6E%00%53%00%69%00%7A%00%65%00%00%00%13%00%00%00%10%00%00%00%BD%00%00%00%10%00%00%00%00%43%00%6F%00%6C%00%49%00%6E%00%66%00%6F%00%00%00%42%00%00%00%1E%00%00%00%70%00%72%00%6F%00%70%00%34%00%32%00%39%00%34%00%39%00%36%00%37%00%32%00%39%00%35%00%00%00%00%00%78%00%00%00%FD%DF%DF%FD%10%00%00%00%00%00%00%00%00%00%00%00%04%00%00%00%18%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%0A%00%00%00%8C%00%00%00%30%F1%25%B7%EF%47%1A%10%A5%F1%02%60%8C%9E%EB%AC%04%00%00%00%AF%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%03%00%00%00%70%00%00%00%35%4B%17%9B%FF%40%D2%11%A2%7E%00%C0%4F%C3%08%71%02%00%00%00%70%00%00%00%2F%00%00%00%1E%00%00%00%00%47%00%72%00%6F%00%75%00%70%00%42%00%79%00%4B%00%65%00%79%00%3A%00%50%00%49%00%44%00%00%00%13%00%00%00%04%00%00%00%1F%00%00%00%0E%00%00%00%00%46%00%46%00%6C%00%61%00%67%00%73%00%00%00%13%00%00%00%05%00%20%40%31%00%00%00%20%00%00%00%00%4C%00%6F%00%67%00%69%00%63%00%61%00%6C%00%56%00%69%00%65%00%77%00%4D%00%6F%00%64%00%65%00%00%00%13%00%00%00%01%00%00%00%00%00%00%00%00%00%00%00|CODEMODE1|-1905896973|772 +[Programs_State] +Disable=0 +[Quick-Links] +WK=%systemdrive%/WK +[Options] +Start=7 +[X-Size] +mode=1 +dig=0 +fld_size=1 +ths_sep=1 +type=0 +precent=1 +ff_cnt=1 +block_no_focus=1 +nosort_fld_size=1 diff --git a/System32/menu.cmd b/System32/menu.cmd deleted file mode 100644 index b8e5509a..00000000 --- a/System32/menu.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -python "%SystemDrive%\.bin\Scripts\menu.py" \ No newline at end of file From 46582c18337f62b0b8baaa8de0e84e5e4c5ed7d2 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 11:57:38 -0800 Subject: [PATCH 62/85] Bugfix: Forgot I renamed/replaced menu.py --- .pe_items/System32/Winpeshl.ini | 2 +- .pe_items/System32/menu.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pe_items/System32/Winpeshl.ini b/.pe_items/System32/Winpeshl.ini index a91b5b58..9147e972 100644 --- a/.pe_items/System32/Winpeshl.ini +++ b/.pe_items/System32/Winpeshl.ini @@ -3,4 +3,4 @@ wpeinit wpeutil updatebootinfo cd /d "%SystemDrive%\.bin" -"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\menu.py" +"%SystemDrive%\.bin\ConEmu\ConEmu.exe", /cmd cmd /k cd "%SystemDrive%\.bin" & python "%SystemDrive%\.bin\Scripts\winpe_root_menu.py" diff --git a/.pe_items/System32/menu.cmd b/.pe_items/System32/menu.cmd index cec35be5..76edf44a 100644 --- a/.pe_items/System32/menu.cmd +++ b/.pe_items/System32/menu.cmd @@ -1,2 +1,2 @@ @echo off -python "%SystemDrive%\.bin\Scripts\menu.py" +python "%SystemDrive%\.bin\Scripts\winpe_root_menu.py" From 387b1740e49a2a8d4472ee7ec006d24a4b68f0a5 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 11:57:56 -0800 Subject: [PATCH 63/85] Enabled DISM logging --- .bin/Scripts/build_pe.ps1 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 26d8ace4..7e9c9f68 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -11,6 +11,7 @@ $WD = $(Split-Path $MyInvocation.MyCommand.Path) $Bin = (Get-Item $WD -Force).Parent.FullName $Root = (Get-Item $Bin -Force).Parent.FullName $Build = "$Root\BUILD" +$LogDir = "$Build\Logs" $Temp = "$Build\Temp" $Date = Get-Date -UFormat "%Y-%m-%d" $Host.UI.RawUI.BackgroundColor = "Black" @@ -109,6 +110,7 @@ if ($MyInvocation.InvocationName -ne ".") { } Push-Location "$WD" MakeClean + New-Item -Type Directory $LogDir 2>&1 | Out-Null if (Ask-User "Update Tools?") { $DownloadErrors = 0 @@ -488,10 +490,10 @@ if ($MyInvocation.InvocationName -ne ".") { # Mount image Write-Host "Mounting image..." New-Item -Path $Mount -ItemType "directory" -Force | Out-Null - Mount-WindowsImage -Path $Mount -ImagePath "$PEFiles\media\sources\boot.wim" -Index 1 | Out-Null + Mount-WindowsImage -Path $Mount -ImagePath "$PEFiles\media\sources\boot.wim" -Index 1 -LogPath "$LogDir\DISM.log" # Add drivers - Add-WindowsDriver -Path $Mount -Driver $Drivers -Recurse | Out-Null + Add-WindowsDriver -Path $Mount -Driver $Drivers -Recurse -LogPath "$LogDir\DISM.log" # Add packages Write-Host "Adding packages:" @@ -504,17 +506,18 @@ if ($MyInvocation.InvocationName -ne ".") { foreach ($Package in $WinPEPackages) { $PackagePath = ("{0}\{1}\WinPE_OCs\{2}.cab" -f $Env:WinPERoot, $Arch, $Package) Write-Host " $Package..." - Add-WindowsPackage –PackagePath $PackagePath –Path $Mount | Out-Null + Add-WindowsPackage –PackagePath $PackagePath –Path $Mount -LogPath "$LogDir\DISM.log" $LangPackagePath = ("{0}\{1}\WinPE_OCs\en-us\{2}_en-us.cab" -f $Env:WinPERoot, $Arch, $Package) if (Test-Path $LangPackagePath) { - Add-WindowsPackage –PackagePath $LangPackagePath –Path $Mount | Out-Null + Add-WindowsPackage –PackagePath $LangPackagePath –Path $Mount -LogPath "$LogDir\DISM.log" } } # Set RamDisk size $ArgumentList = @( ('/Image:"{0}"' -f $Mount), - "/Set-ScratchSpace:512" + "/Set-ScratchSpace:512", + ('/LogPath:"{0}\DISM.log"' -f $LogDir) ) Start-Process -FilePath $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait @@ -580,7 +583,7 @@ if ($MyInvocation.InvocationName -ne ".") { # Unmount image Write-Host "Dismounting image..." - Dismount-WindowsImage -Path $Mount -Save + Dismount-WindowsImage -Path $Mount -Save -LogPath "$LogDir\DISM.log" # Create ISO New-Item -Type Directory "$Root\OUT_PE" 2>&1 | Out-Null From cd3f3ed8d38fdd90ada4a57875373a9a8fb2fb87 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:02:05 -0800 Subject: [PATCH 64/85] Always more cleanup --- Scripts/functions/disk.py | 6 +++--- Scripts/functions/windows_setup.py | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index eb2bda4f..5d6cc2a7 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -197,7 +197,7 @@ def get_table_type(disk): elif REGEX_DISK_RAW.search(output): part_type = 'RAW' else: - part_type = 'Unknown + part_type = 'Unknown' return part_type @@ -288,7 +288,7 @@ def remove_volume_letters(keep=None): with open(DISKPART_SCRIPT, 'w') as script: for vol in get_volumes(): if vol['Letter'].upper() != keep.upper(): - script.write('select volume {}\n'.format(vol['Number'])) + script.write('select volume {}\n'.format(vol['Number'])) script.write('remove noerr\n') # Run script @@ -319,7 +319,7 @@ def scan_disks(): # Done return disks -def select_disk(title='Which disk?', disks): +def select_disk(title='Which disk?', disks=[]): """Select a disk from the attached disks""" # Build menu disk_options = [] diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index cbbe1525..ae8d401b 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -150,11 +150,8 @@ def format_mbr(disk): def mount_windows_share(): """Mount the Windows images share unless labeled as already mounted.""" - if WINDOWS_SERVER['Mounted']: - # Blindly skip if we mounted earlier - continue - - mount_network_share(WINDOWS_SERVER) + if not WINDOWS_SERVER['Mounted']: + mount_network_share(WINDOWS_SERVER) def select_windows_version(): actions = [ From 5aab8a98e371ab5dca128f8567f76de2ae400dcb Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:24:11 -0800 Subject: [PATCH 65/85] Bugfix: Was trying to use 'Env' before it was set. --- Scripts/functions/windows_setup.py | 1 - Scripts/winpe_root_menu.py | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index ae8d401b..c96ed5a2 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -3,7 +3,6 @@ from functions.data import * # STATIC VARIABLES -DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) WINDOWS_VERSIONS = [ {'Name': 'Windows 7 Home Basic', 'Image File': 'Win7', diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index 4bd39aef..407b3e84 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -11,6 +11,9 @@ init_global_vars() set_title('{}: Root Menu'.format(KIT_NAME_FULL)) global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) +# STATIC VARIABLES +DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) + if __name__ == '__main__': try: menu_root() From ab6fd19c021120988335f6ef859a517bd33eb747 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:26:11 -0800 Subject: [PATCH 66/85] Bugfix: menu_select() --- Scripts/functions/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/functions/common.py b/Scripts/functions/common.py index 59826f0f..9a2211a4 100644 --- a/Scripts/functions/common.py +++ b/Scripts/functions/common.py @@ -226,7 +226,7 @@ def menu_select(title='~ Untitled Menu ~', # Set title if 'Title' in global_vars: - title = '{}\n\n{}'.format(global_vars['Title']) + title = '{}\n\n{}'.format(global_vars['Title'], title) # Build menu menu_splash = '{}\n\n'.format(title) From 06affc3bd109dedb875a5cc809030745336b6fcb Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:26:37 -0800 Subject: [PATCH 67/85] Bugfix: menu_tools() --- Scripts/functions/winpe_menus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index c6ba4e8c..f34376ae 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -321,7 +321,7 @@ def menu_setup(): pause('\nPress Enter to return to main menu... ') def menu_tools(): - tools = [k for k in sorted(PE_TOOLS.keys())] + tools = [{'Name': k} for k in sorted(PE_TOOLS.keys())] actions = [{'Name': 'Main Menu', 'Letter': 'M'},] set_title(KIT_NAME_FULL) From 97e93e812be4c7990d1860ff3577fc12e28795a1 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:27:26 -0800 Subject: [PATCH 68/85] Bugfix: partition_uids import --- Scripts/functions/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 5d6cc2a7..76601ffb 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -1,7 +1,7 @@ # Wizard Kit PE: Functions - Disk from functions.common import * -import partition_uids +from functions import partition_uids # Regex REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) From 5d32f3c94a1f3f79d85d850ffbde66a567755463 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:27:53 -0800 Subject: [PATCH 69/85] Bugfix: Abort logic --- Scripts/functions/disk.py | 2 +- Scripts/functions/windows_setup.py | 4 ++-- Scripts/functions/winpe_menus.py | 9 +++++---- Scripts/winpe_root_menu.py | 3 --- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Scripts/functions/disk.py b/Scripts/functions/disk.py index 76601ffb..8cff593e 100644 --- a/Scripts/functions/disk.py +++ b/Scripts/functions/disk.py @@ -360,7 +360,7 @@ def select_disk(title='Which disk?', disks=[]): if (selection.isnumeric()): return disk_options[int(selection)-1]['Disk'] elif (selection == 'M'): - raise GeneralAbort + raise GenericAbort if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index c96ed5a2..90ff549f 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -75,7 +75,7 @@ def find_windows_image(windows_version): else: print_error('Failed to find Windows source image for {}'.format( windows_version['Name'])) - raise GeneralAbort + raise GenericAbort def format_disk(disk, use_gpt): """Format disk for use as a Windows OS disk.""" @@ -166,7 +166,7 @@ def select_windows_version(): if selection.isnumeric(): return WINDOWS_VERSIONS[int(selection)-1] elif selection == 'M': - raise GeneralAbort + raise GenericAbort def setup_windows(windows_image, windows_version): cmd = [ diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index f34376ae..64a63e97 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -197,8 +197,9 @@ def menu_root(): if (selection.isnumeric()): try: menus[int(selection)-1]['Menu']() - except AbortError: - pass + except GenericAbort: + print_warning('\nAborted\n') + pause('Press Enter to return to main menu... ') elif (selection == 'C'): run_program(['cmd', '-new_console:n'], check=False) elif (selection == 'R'): @@ -262,7 +263,7 @@ def menu_setup(): print_warning(dest_disk['Format Warnings']) if (not ask('Is this correct?')): - raise GeneralAbort + raise GenericAbort # Safety check print_standard('\nSAFETY CHECK') @@ -271,7 +272,7 @@ def menu_setup(): print_warning('This is irreversible and will lead ' 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) if (not ask('Asking again to confirm, is this correct?')): - raise GeneralAbort + raise GenericAbort # Remove volume letters so S, T, & W can be used below remove_volume_letters(keep=windows_image['Source']) diff --git a/Scripts/winpe_root_menu.py b/Scripts/winpe_root_menu.py index 407b3e84..1ddea8a5 100644 --- a/Scripts/winpe_root_menu.py +++ b/Scripts/winpe_root_menu.py @@ -17,9 +17,6 @@ DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) if __name__ == '__main__': try: menu_root() - except GenericAbort: - # pause('Press Enter to return to main menu... ') - pass except SystemExit: pass except: From a6f9518648887a5c14c2dac477da0647fe9da06d Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:41:39 -0800 Subject: [PATCH 70/85] Bugfix: find_windows_image() --- Scripts/functions/windows_setup.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Scripts/functions/windows_setup.py b/Scripts/functions/windows_setup.py index 90ff549f..1d960367 100644 --- a/Scripts/functions/windows_setup.py +++ b/Scripts/functions/windows_setup.py @@ -56,17 +56,20 @@ def find_windows_image(windows_version): # Check for network source if not image: mount_windows_share() - if not WINDOWS_SERVER['Mounted']: - return None - for ext in ['esd', 'wim', 'swm']: - path = r'\\{}\{}\images\{}.ext'.format( - WINDOWS_SERVER['IP'], WINDOWS_SERVER['Share'], imagefile, ext) - if os.path.isfile(path) and wim_contains_image(path, imagename): - image['Path'] = path - image['Source'] = None - if ext == 'swm': - image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) - break + if WINDOWS_SERVER['Mounted']: + for ext in ['esd', 'wim', 'swm']: + path = r'\\{}\{}\images\{}.ext'.format( + WINDOWS_SERVER['IP'], + WINDOWS_SERVER['Share'], + imagefile, + ext) + if os.path.isfile(path) and wim_contains_image(path, imagename): + image['Path'] = path + image['Source'] = None + if ext == 'swm': + image['Glob'] = '--ref="{}*.swm"'.format( + image['Path'][:-4]) + break # Display image to be used (if any) and return if image: From 56c396045144afa8b5465fae6752f8418408d0ba Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:42:23 -0800 Subject: [PATCH 71/85] Bugfix: menu_setup() --- Scripts/functions/winpe_menus.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 64a63e97..637f5d0f 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -212,6 +212,15 @@ def menu_root(): def menu_setup(): """Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" errors = False + other_results = { + 'Error': { + 'CalledProcessError': 'Unknown Error', + 'PathNotFoundError': 'Missing', + }, + 'Warning': { + 'GenericAbort': 'Skipped', + 'GenericRepair': 'Repaired', + }} set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) # Set ticket ID From f608e9b88c6b368aeda0d124801b0a81d31cd49b Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 12:42:46 -0800 Subject: [PATCH 72/85] Show title before getting ticket_number --- Scripts/functions/winpe_menus.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Scripts/functions/winpe_menus.py b/Scripts/functions/winpe_menus.py index 637f5d0f..b89ce79d 100644 --- a/Scripts/functions/winpe_menus.py +++ b/Scripts/functions/winpe_menus.py @@ -66,6 +66,7 @@ def menu_backup(): # Set ticket Number clear_screen() + print_standard('{}\n'.format(global_vars['Title'])) ticket_number = get_ticket_number() # Mount backup shares @@ -225,6 +226,7 @@ def menu_setup(): # Set ticket ID clear_screen() + print_standard('{}\n'.format(global_vars['Title'])) ticket_number = get_ticket_number() # Select the version of Windows to apply From 5e5d5834d9b3bf49600d294a754a2365d3b22292 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 13:15:56 -0800 Subject: [PATCH 73/85] Bugfix: PE_TOOLS paths --- .bin/Scripts/functions/winpe_menus.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index dcd0ba18..d22827ed 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -175,6 +175,11 @@ def menu_backup(): pause('\nPress Enter to return to main menu... ') def menu_root(): + # Fix PE_TOOLS paths + for k in PE_TOOLS.keys(): + PE_TOOLS[k]['Path'] = r'{}\{}'.format( + global_vars['BinDir'], PE_TOOLS[k]['Path']) + menus = [ {'Name': 'Create Backups', 'Menu': menu_backup}, {'Name': 'Setup Windows', 'Menu': menu_setup}, @@ -344,8 +349,8 @@ def menu_tools(): main_entries = tools, action_entries = actions) if (selection.isnumeric()): - tool = tools[int(selection)-1] - cmd = [PE_TOOLS[tool]['Path']] + PE_TOOLS[tool].get('Args', []) + name = tools[int(selection)-1]['Name'] + cmd = [PE_TOOLS[name]['Path']] + PE_TOOLS[name].get('Args', []) if tool == 'Blue Screen View': # Select path to scan minidump_path = select_minidump_path() @@ -354,7 +359,7 @@ def menu_tools(): try: popen_program(cmd) except Exception: - print_error('Failed to run {prog}'.format(prog=tool['Name'])) + print_error('Failed to run {}'.format(name)) time.sleep(2) pause() elif (selection == 'M'): From 8d729d9066a6f15495b4ceee922d1aa771f8bc1d Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 13:16:21 -0800 Subject: [PATCH 74/85] Bugfix: find_windows_image() --- .bin/Scripts/functions/windows_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index 0096b116..edfeb5ca 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -58,7 +58,7 @@ def find_windows_image(windows_version): mount_windows_share() if WINDOWS_SERVER['Mounted']: for ext in ['esd', 'wim', 'swm']: - path = r'\\{}\{}\images\{}.ext'.format( + path = r'\\{}\{}\images\{}.{}'.format( WINDOWS_SERVER['IP'], WINDOWS_SERVER['Share'], imagefile, From a9822ae9bde80660739455c761335ee2c4c1d3d1 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 13:31:42 -0800 Subject: [PATCH 75/85] Bugfix Tool paths --- .bin/Scripts/functions/winpe_menus.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index d22827ed..130d5eb1 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -50,6 +50,16 @@ PE_TOOLS = { }, } +def check_pe_tools(): + for k in PE_TOOLS.keys(): + PE_TOOLS[k]['Path'] = r'{}\{}'.format( + global_vars['BinDir'], PE_TOOLS[k]['Path']) + global_vars['Tools']['wimlib-imagex'] = re.sub( + r'\\x(32|64)', + r'', + global_vars['Tools']['wimlib-imagex'], + re.IGNORECASE) + def menu_backup(): """Take backup images of partition(s) in the WIM format.""" errors = False @@ -175,11 +185,7 @@ def menu_backup(): pause('\nPress Enter to return to main menu... ') def menu_root(): - # Fix PE_TOOLS paths - for k in PE_TOOLS.keys(): - PE_TOOLS[k]['Path'] = r'{}\{}'.format( - global_vars['BinDir'], PE_TOOLS[k]['Path']) - + check_pe_tools() menus = [ {'Name': 'Create Backups', 'Menu': menu_backup}, {'Name': 'Setup Windows', 'Menu': menu_setup}, From d075f17bfac478255b34b1151a5b19806ab39b5e Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 15:27:10 -0800 Subject: [PATCH 76/85] Added run_diskpart(script) * Takes list, writes script, runs script, and returns result --- .bin/Scripts/functions/disk.py | 124 +++++++++++++----------- .bin/Scripts/functions/windows_setup.py | 81 ++++++++-------- .bin/Scripts/winpe_root_menu.py | 3 - 3 files changed, 106 insertions(+), 102 deletions(-) diff --git a/.bin/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py index c1e88491..db8681fd 100644 --- a/.bin/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -12,19 +12,16 @@ REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) def assign_volume_letters(): - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - script.write('select volume {}\n'.format(vol['Number'])) - script.write('assign\n') - - # Remove current letters remove_volume_letters() - # Run script - try: - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - except subprocess.CalledProcessError: - pass + # Write script + script = [] + for vol in get_volumes(): + script.append('select volume {}'.format(vol['Number'])) + script.append('assign') + + # Run + run_diskpart(script) def get_boot_mode(): boot_mode = 'Legacy' @@ -41,17 +38,17 @@ def get_boot_mode(): def get_disk_details(disk): details = {} - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('detail disk\n') + script = [ + 'select disk {}'.format(disk['Number']), + 'detail disk'] + # Run try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(script) except subprocess.CalledProcessError: pass else: + output = result.stdout.decode().strip() # Remove empty lines tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] # Set disk name @@ -65,17 +62,15 @@ def get_disk_details(disk): def get_disks(): disks = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list disk\n') try: # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(['list disk']) except subprocess.CalledProcessError: pass else: # Append disk numbers + output = result.stdout.decode().strip() for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output): num = tmp[0] size = human_readable_size(tmp[1]) @@ -85,20 +80,20 @@ def get_disks(): def get_partition_details(disk, partition): details = {} - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('select partition {}\n'.format(partition['Number'])) - script.write('detail partition\n') + script = [ + 'select disk {}'.format(disk['Number']), + 'select partition {}'.format(partition['Number']), + 'detail partition'] # Diskpart details try: # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(script) except subprocess.CalledProcessError: pass else: # Get volume letter or RAW status + output = result.stdout.decode().strip() tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output) if tmp: if tmp.group(1).upper() == 'RAW': @@ -132,11 +127,11 @@ def get_partition_details(disk, partition): '{}:'.format(details['Letter']) ] try: - output = run_program(cmd) - output = output.stdout.decode().strip() + result = run_program(cmd) except subprocess.CalledProcessError: pass else: + output = result.stdout.decode().strip() # Remove empty lines from output tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] # Add "Feature" lines @@ -158,18 +153,18 @@ def get_partition_details(disk, partition): def get_partitions(disk): partitions = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('list partition\n') + script = [ + 'select disk {}'.format(disk['Number']), + 'list partition'] try: # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(script) except subprocess.CalledProcessError: pass else: # Append partition numbers + output = result.stdout.decode().strip() regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+' for tmp in re.findall(regex, output, re.IGNORECASE): num = tmp[0] @@ -180,40 +175,34 @@ def get_partitions(disk): def get_table_type(disk): part_type = 'Unknown' - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select disk {}\n'.format(disk['Number'])) - script.write('uniqueid disk\n') + script = [ + 'select disk {}'.format(disk['Number']), + 'uniqueid disk'] try: - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(script) except subprocess.CalledProcessError: pass else: + output = result.stdout.decode().strip() if REGEX_DISK_GPT.search(output): part_type = 'GPT' elif REGEX_DISK_MBR.search(output): part_type = 'MBR' elif REGEX_DISK_RAW.search(output): part_type = 'RAW' - else: - part_type = 'Unknown' return part_type def get_volumes(): vols = [] - with open(DISKPART_SCRIPT, 'w') as script: - script.write('list volume\n') - try: - # Run script - output = run_program(['diskpart', '/s', DISKPART_SCRIPT]) - output = output.stdout.decode().strip() + result = run_diskpart(['list volume']) except subprocess.CalledProcessError: pass else: # Append volume numbers + output = result.stdout.decode().strip() for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output): vols.append({'Number': tmp[0], 'Letter': tmp[1]}) @@ -270,13 +259,12 @@ def reassign_volume_letter(letter, new_letter='I'): if not letter: # Ignore return None + script = [ + 'select volume {}'.format(letter), + 'remove noerr', + 'assign letter={}'.format(new_letter)] try: - # Run script - with open(DISKPART_SCRIPT, 'w') as script: - script.write('select volume {}\n'.format(letter)) - script.write('remove noerr\n') - script.write('assign letter={}\n'.format(new_letter)) - run_program(['diskpart', '/s', DISKPART_SCRIPT]) + run_diskpart(script) except subprocess.CalledProcessError: pass else: @@ -285,18 +273,36 @@ def reassign_volume_letter(letter, new_letter='I'): def remove_volume_letters(keep=None): if not keep: keep = '' - with open(DISKPART_SCRIPT, 'w') as script: - for vol in get_volumes(): - if vol['Letter'].upper() != keep.upper(): - script.write('select volume {}\n'.format(vol['Number'])) - script.write('remove noerr\n') + + script = [] + for vol in get_volumes(): + if vol['Letter'].upper() != keep.upper(): + script.append('select volume {}'.format(vol['Number'])) + script.append('remove noerr') # Run script try: - run_program(['diskpart', '/s', DISKPART_SCRIPT]) + run_diskpart(script) except subprocess.CalledProcessError: pass +def run_diskpart(script): + tempfile = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) + + # Write script + with open(tempfile, 'w') as f: + for line in script: + f.write('{}\n'.format(line)) + + # Run script + cmd = [ + r'{}\Windows\System32\diskpart.exe'.format( + global_vars['Env']['SYSTEMDRIVE']), + '/s', tempfile] + result = run_program(cmd) + time.sleep(2) + return result + def scan_disks(): """Get details about the attached disks""" disks = get_disks() diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index edfeb5ca..be016a2d 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -1,6 +1,7 @@ # Wizard Kit PE: Functions - Windows Setup from functions.data import * +from functions.disk import * # STATIC VARIABLES WINDOWS_VERSIONS = [ @@ -89,66 +90,66 @@ def format_disk(disk, use_gpt): def format_gpt(disk): """Format disk for use as a Windows OS disk using the GPT layout.""" - with open(DISKPART_SCRIPT, 'w') as script: + script = [ # Partition table - script.write('select disk {}\n'.format(disk['Number'])) - script.write('clean\n') - script.write('convert gpt\n') + 'select disk {}'.format(disk['Number']), + 'clean', + 'convert gpt', # System partition # NOTE: ESP needs to be >= 260 for Advanced Format 4K disks - script.write('create partition efi size=500\n') - script.write('format quick fs=fat32 label="System"\n') - script.write('assign letter="S"\n') + 'create partition efi size=500', + 'format quick fs=fat32 label="System"', + 'assign letter="S"', # Microsoft Reserved (MSR) partition - script.write('create partition msr size=128\n') + 'create partition msr size=128', # Windows partition - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Windows"\n') - script.write('assign letter="W"\n') + 'create partition primary', + 'format quick fs=ntfs label="Windows"', + 'assign letter="W"', # Recovery Tools partition - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery Tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') - - # Run script - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - time.sleep(2) + 'shrink minimum=500', + 'create partition primary', + 'format quick fs=ntfs label="Recovery Tools"', + 'assign letter="T"', + 'set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"', + 'gpt attributes=0x8000000000000001', + ] + + # Run + run_diskpart(script) def format_mbr(disk): """Format disk for use as a Windows OS disk using the MBR layout.""" - with open(DISKPART_SCRIPT, 'w') as script: + script = [ # Partition table - script.write('select disk {}\n'.format(disk['Number'])) - script.write('clean\n') + 'select disk {}'.format(disk['Number']), + 'clean', # System partition - script.write('create partition primary size=100\n') - script.write('format fs=ntfs quick label="System Reserved"\n') - script.write('active\n') - script.write('assign letter="S"\n') + 'create partition primary size=100', + 'format fs=ntfs quick label="System Reserved"', + 'active', + 'assign letter="S"', # Windows partition - script.write('create partition primary\n') - script.write('format fs=ntfs quick label="Windows"\n') - script.write('assign letter="W"\n') + 'create partition primary', + 'format fs=ntfs quick label="Windows"', + 'assign letter="W"', # Recovery Tools partition - script.write('shrink minimum=500\n') - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Recovery"\n') - script.write('assign letter="T"\n') - script.write('set id=27\n') - - # Run script - run_program(['diskpart', '/s', DISKPART_SCRIPT]) - time.sleep(2) + 'shrink minimum=500', + 'create partition primary', + 'format quick fs=ntfs label="Recovery"', + 'assign letter="T"', + 'set id=27', + ] + + # Run + run_diskpart(script) def mount_windows_share(): """Mount the Windows images share unless labeled as already mounted.""" diff --git a/.bin/Scripts/winpe_root_menu.py b/.bin/Scripts/winpe_root_menu.py index 279fa33d..6225760c 100644 --- a/.bin/Scripts/winpe_root_menu.py +++ b/.bin/Scripts/winpe_root_menu.py @@ -11,9 +11,6 @@ init_global_vars() set_title('{}: Root Menu'.format(KIT_NAME_FULL)) global_vars['LogFile'] = r'{LogDir}\WinPE.log'.format(**global_vars) -# STATIC VARIABLES -DISKPART_SCRIPT = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) - if __name__ == '__main__': try: menu_root() From dce31bf5dd8babfe1a914af4b2964f7c17eb002a Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 15:28:15 -0800 Subject: [PATCH 77/85] Windows Setup working --- .bin/Scripts/functions/common.py | 13 ++++++++++--- .bin/Scripts/functions/disk.py | 8 ++++---- .bin/Scripts/functions/winpe_menus.py | 19 ++++++++++++------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.bin/Scripts/functions/common.py b/.bin/Scripts/functions/common.py index d8ea62e5..40b9ca4b 100644 --- a/.bin/Scripts/functions/common.py +++ b/.bin/Scripts/functions/common.py @@ -372,10 +372,17 @@ def set_title(title='~Some Title~'): global_vars['Title'] = title os.system('title {}'.format(title)) -def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): +def show_info(message='~Some message~', info='~Some info~', indent=8, width=32, + warning=False, error=False): """Display info with formatting.""" - print_standard('{indent}{message:<{width}}{info}'.format( - indent=' '*indent, width=width, message=message, info=info)) + message = '{indent}{message:<{width}}{info}'.format( + indent=' '*indent, width=width, message=message, info=info) + if error: + print_error(message) + elif warning: + print_warning(message) + else: + print_standard(message) def sleep(seconds=2): """Wait for a while.""" diff --git a/.bin/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py index db8681fd..821529ae 100644 --- a/.bin/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -232,7 +232,7 @@ def prep_disk_for_formatting(disk=None): if len(disk['Partitions']) == 0: disk['Format Warnings'] += 'No partitions found\n' for partition in disk['Partitions']: - display = ' Partition {num:>{width}}:\t{size} {fs}'.format( + display = '{size} {fs}'.format( num = partition['Number'], width = width, size = partition['Size'], @@ -344,10 +344,10 @@ def select_disk(title='Which disk?', disks=[]): # Show unsupported partition(s) if is_bad_partition(partition): - p_display_name = '{YELLOW}{display}{CLEAR}'.format( - display=p_name, **COLORS) + p_name = '{YELLOW}{p_name}{CLEAR}'.format( + p_name=p_name, **COLORS) - display_name += '\n\t\t\t{}'.format(display_name) + display_name += '\n\t\t\t{}'.format(p_name) if not disk['Partitions']: display_name += '\n\t\t\t{}No partitions found.{}'.format( COLORS['YELLOW'], COLORS['CLEAR']) diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index 130d5eb1..5b412d50 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -263,7 +263,7 @@ def menu_setup(): # Select disk to use as the OS disk dest_disk = select_disk('To which disk are we installing Windows?', disks) - if not disk: + if not dest_disk: raise GenericAbort # "Prep" disk @@ -277,11 +277,16 @@ def menu_setup(): show_info( message = 'Boot Method:', info = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') - show_info(message='Using Image:', info=windows_version['Path']) - print_warning(' ERASING: \t[{Table}] ({Type}) {Name} {Size}\n'.format( - **dest_disk)) + show_info(message='Using Image:', info=windows_image['Path']) + show_info( + message = 'ERASING:', + info = '[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk), + warning = True) for par in dest_disk['Partitions']: - print_warning(par['Display String']) + show_info( + message = 'Partition {:>2}:'.format(par['Number']), + info = par['Display String'], + warning = True) print_warning(dest_disk['Format Warnings']) if (not ask('Is this correct?')): @@ -290,7 +295,7 @@ def menu_setup(): # Safety check print_standard('\nSAFETY CHECK') print_warning('All data will be DELETED from the ' - 'disk & partition(s) listed above.') + 'disk and partition(s) listed above.') print_warning('This is irreversible and will lead ' 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) if (not ask('Asking again to confirm, is this correct?')): @@ -357,7 +362,7 @@ def menu_tools(): if (selection.isnumeric()): name = tools[int(selection)-1]['Name'] cmd = [PE_TOOLS[name]['Path']] + PE_TOOLS[name].get('Args', []) - if tool == 'Blue Screen View': + if name == 'Blue Screen View': # Select path to scan minidump_path = select_minidump_path() if minidump_path: From 19176d30cf4a73d2e4ac2c16379ca1a9c4cd408c Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 15:46:58 -0800 Subject: [PATCH 78/85] Open logs and cleanup --- .bin/Scripts/functions/backup.py | 2 +- .bin/Scripts/functions/disk.py | 2 +- .bin/Scripts/functions/winpe_menus.py | 26 +++++++++++++++++++++----- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/.bin/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py index c916a0e3..10ff9964 100644 --- a/.bin/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -36,7 +36,7 @@ def prep_disk_for_backup(destination, disk, ticket_number): # Get partition totals disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] - if is_bad_partition(partition)] + if is_bad_partition(par)] num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) disk['Valid Partitions'] = num_valid_partitions if disk['Valid Partitions'] <= 0: diff --git a/.bin/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py index 821529ae..897422bb 100644 --- a/.bin/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -300,7 +300,7 @@ def run_diskpart(script): global_vars['Env']['SYSTEMDRIVE']), '/s', tempfile] result = run_program(cmd) - time.sleep(2) + sleep(2) return result def scan_disks(): diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index 5b412d50..a43c95d8 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -178,10 +178,17 @@ def menu_backup(): pass for line in par['Error']: print_error('\t{}'.format(line)) - time.sleep(30) else: print_success('\nNo errors were encountered during imaging.') - time.sleep(5) + if 'LogFile' in global_vars: + cmd = [ + global_vars['Tools']['NotepadPlusPlus'], + global_vars['LogFile']] + try: + popen_program(cmd) + except Exception: + print_error('ERROR: Failed to open log.') + sleep(30) pause('\nPress Enter to return to main menu... ') def menu_root(): @@ -219,7 +226,7 @@ def menu_root(): elif (selection == 'S'): run_program(['wpeutil', 'shutdown']) else: - exit_script() + sys.exit() def menu_setup(): """Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" @@ -346,6 +353,15 @@ def menu_setup(): # Print summary print_standard('\nDone.') + if 'LogFile' in global_vars: + cmd = [ + global_vars['Tools']['NotepadPlusPlus'], + global_vars['LogFile']] + try: + popen_program(cmd) + except Exception: + print_error('ERROR: Failed to open log.') + sleep(30) pause('\nPress Enter to return to main menu... ') def menu_tools(): @@ -371,7 +387,7 @@ def menu_tools(): popen_program(cmd) except Exception: print_error('Failed to run {}'.format(name)) - time.sleep(2) + sleep(2) pause() elif (selection == 'M'): break @@ -395,7 +411,7 @@ def select_minidump_path(): # Check results before showing menu if len(dumps) == 0: print_error(' No BSoD / MiniDump paths found') - time.sleep(2) + sleep(2) return None # Menu From 20a730c6e70031ac6ee2d957cceca70add9b3d56 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 15:48:00 -0800 Subject: [PATCH 79/85] Bugfix: bcdboot Need to use WinPE's copy instead of local * Win7 version doesn't have the /f option --- .bin/Scripts/functions/windows_setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index be016a2d..78396a0e 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -202,7 +202,8 @@ def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): cmd = [ - r'{}:\Windows\System32\bcdboot.exe'.format(windows_letter), + r'{}:\Windows\System32\bcdboot.exe'.format( + global_vars['Env']['SYSTEMDRIVE']), r'{}:\Windows'.format(windows_letter), '/s', '{}:'.format(system_letter), '/f', mode] From 541660484b1d504b616d8d82583712288a2bb9c6 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 17:12:27 -0800 Subject: [PATCH 80/85] Bugfixes for backup sections ** Still broken though --- .bin/Scripts/functions/backup.py | 6 +++--- .bin/Scripts/functions/winpe_menus.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.bin/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py index 10ff9964..614a4be0 100644 --- a/.bin/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -4,14 +4,14 @@ from functions.disk import * # Regex REGEX_BAD_PATH_NAMES = re.compile( - r'([<>:"/\\\|\?\*]' + r'([<>:"/\|\?\*]' r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' r'|^\s+' r'|[\s\.]+$', re.IGNORECASE) -def backup_partition(disk, partition): - if par['Image Exists'] or par['Number'] in disk['Bad Partitions']: +def backup_partition(disk, par): + if par.get('Image Exists', False) or par['Number'] in disk['Bad Partitions']: raise GenericAbort cmd = [ diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index a43c95d8..faf86636 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -83,7 +83,7 @@ def menu_backup(): mount_backup_shares() # Select destination - destination = select_backup_destination() + destination = select_backup_destination(auto_select=False) # Scan disks try_and_print( @@ -136,7 +136,7 @@ def menu_backup(): function = backup_partition, other_results = other_results, disk = disk, - partition = par) + par = par) if not result['CS']: errors = True par['Error'] = result['Error'] From ffa2abb2b417b22b0854b0221f10b4b6ec4d07ef Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 17:13:20 -0800 Subject: [PATCH 81/85] Adjusted partition info display --- .bin/Scripts/functions/backup.py | 15 +++----- .bin/Scripts/functions/common.py | 13 +++++-- .bin/Scripts/functions/disk.py | 4 +- .bin/Scripts/functions/winpe_menus.py | 54 ++++++++++++++------------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/.bin/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py index 614a4be0..5be31f0a 100644 --- a/.bin/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -45,7 +45,7 @@ def prep_disk_for_backup(destination, disk, ticket_number): # Prep partitions for par in disk['Partitions']: - display = 'Partition {num:>{width}}:\t{size} {fs}'.format( + display = '{size} {fs}'.format( num = par['Number'], width = width, size = par['Size'], @@ -53,14 +53,12 @@ def prep_disk_for_backup(destination, disk, ticket_number): if par['Number'] in disk['Bad Partitions']: # Set display string using partition description & OS type - display = ' * {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( + display = '* {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( display = display, q = '"' if par['Name'] != '' else '', name = par['Name'], desc = par['Description'], os = par['OS']) - display = '{YELLOW}{display}{CLEAR}'.format( - display=display, **COLORS) else: # Update info for WIM capturing par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' @@ -78,16 +76,15 @@ def prep_disk_for_backup(destination, disk, ticket_number): par['Image Exists'] = os.path.exists(par['Image Path']) if par['Image Exists']: disk['Clobber Risk'].append(par['Number']) - display = '{} + {}'.format(COLORS['BLUE'], display) + display = '+ {}'.format(display) else: - display = '{} {}'.format(COLORS['CLEAR'], display) + display = ' {}'.format(display) # Append rest of Display String for valid/clobber partitions - display += ' (Used: {used})\t{q}{name}{q}{CLEAR}'.format( + display += ' (Used: {used})\t{q}{name}{q}'.format( used = par['Used Space'], q = '"' if par['Name'] != '' else '', - name = par['Name'], - **COLORS) + name = par['Name']) # For all partitions par['Display String'] = display diff --git a/.bin/Scripts/functions/common.py b/.bin/Scripts/functions/common.py index 40b9ca4b..202b665e 100644 --- a/.bin/Scripts/functions/common.py +++ b/.bin/Scripts/functions/common.py @@ -372,18 +372,23 @@ def set_title(title='~Some Title~'): global_vars['Title'] = title os.system('title {}'.format(title)) -def show_info(message='~Some message~', info='~Some info~', indent=8, width=32, - warning=False, error=False): +def show_data(message='~Some message~', data='~Some data~', indent=8, width=32, + info=False, warning=False, error=False): """Display info with formatting.""" - message = '{indent}{message:<{width}}{info}'.format( - indent=' '*indent, width=width, message=message, info=info) + message = '{indent}{message:<{width}}{data}'.format( + indent=' '*indent, width=width, message=message, data=data) if error: print_error(message) elif warning: print_warning(message) + elif info: + print_info(message) else: print_standard(message) +def show_info(message='~Some message~', info='~Some info~', indent=8, width=32): + show_data(message=message, data=info, indent=indent, width=width) + def sleep(seconds=2): """Wait for a while.""" time.sleep(seconds) diff --git a/.bin/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py index 897422bb..538975fd 100644 --- a/.bin/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -111,8 +111,8 @@ def get_partition_details(disk, partition): guid = partition_uids.lookup_guid(details['Type']) if guid: details.update({ - 'Description': guid.get('Description', ''), - 'OS': guid.get('OS', '')}) + 'Description': guid.get('Description', '')[:29], + 'OS': guid.get('OS', '')[:26]}) if 'Letter' in details: # Disk usage diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index faf86636..c38f3cad 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -111,17 +111,24 @@ def menu_backup(): # Display details for backup task clear_screen() print_info('Create Backup - Details:\n') - show_info(message='Ticket:', info=ticket_number) - show_info( + show_data(message='Ticket:', data=ticket_number) + show_data( message = 'Source:', - info = '[{Table}] ({Type}) {Name} {Size}'.format(**disk), + data = '[{Table}] ({Type}) {Name} {Size}'.format(**disk), ) - show_info( + show_data( message = 'Destination:', - info = destination.get('Display Name', destination['Name']), + data = destination.get('Display Name', destination['Name']), ) for par in disk['Partitions']: - show_info(message='', info=par['Display String'], width=20) + message = 'Partition {}:'.format(par['Number']) + data = par['Display String'] + if par['Number'] in disk['Bad Partitions']: + show_data(message=message, data=data, width=30, warning=True) + elif par['Image Exists']: + show_data(message=message, data=data, width=30, info=True) + else: + show_data(message=message, data=data, width=30) print_standard(disk['Backup Warnings']) # Ask to proceed @@ -167,17 +174,14 @@ def menu_backup(): except: # Deal with badly formatted error message pass - if isinstance(par['Error'], basestring): - print_error('\t{}'.format(par['Error'])) - else: - try: - par['Error'] = par['Error'].splitlines() - par['Error'] = [line.strip() for line in par['Error']] - par['Error'] = [line for line in par['Error'] if line] - except: - pass + try: + par['Error'] = par['Error'].splitlines() + par['Error'] = [line.strip() for line in par['Error']] + par['Error'] = [line for line in par['Error'] if line] for line in par['Error']: print_error('\t{}'.format(line)) + except: + print_error('\t{}'.format(par['Error'])) else: print_success('\nNo errors were encountered during imaging.') if 'LogFile' in global_vars: @@ -279,20 +283,20 @@ def menu_setup(): # Display details for setup task clear_screen() print_info('Setup Windows - Details:\n') - show_info(message='Ticket:', info=ticket_number) - show_info(message='Installing:', info=windows_version['Name']) - show_info( + show_data(message='Ticket:', data=ticket_number) + show_data(message='Installing:', data=windows_version['Name']) + show_data( message = 'Boot Method:', - info = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') - show_info(message='Using Image:', info=windows_image['Path']) - show_info( + data = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') + show_data(message='Using Image:', data=windows_image['Path']) + show_data( message = 'ERASING:', - info = '[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk), + data = '[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk), warning = True) for par in dest_disk['Partitions']: - show_info( - message = 'Partition {:>2}:'.format(par['Number']), - info = par['Display String'], + show_data( + message = 'Partition {}:'.format(par['Number']), + data = par['Display String'], warning = True) print_warning(dest_disk['Format Warnings']) From c52681be052155211b055af92e75a4982d3d2e06 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 18:31:06 -0800 Subject: [PATCH 82/85] Bugfix: wimlib sections --- .bin/Scripts/functions/backup.py | 6 +++--- .bin/Scripts/functions/winpe_menus.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.bin/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py index 5be31f0a..0a04f555 100644 --- a/.bin/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -16,12 +16,12 @@ def backup_partition(disk, par): cmd = [ global_vars['Tools']['wimlib-imagex'], - 'capture' + 'capture', '{}:\\'.format(par['Letter']), par['Image Path'], par['Image Name'], # Image name par['Image Name'], # Image description - ' --compress=none', + '--compress=none', ] dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE) os.makedirs(dest_dir, exist_ok=True) @@ -142,7 +142,7 @@ def verify_wim_backup(partition): global_vars['Tools']['wimlib-imagex'], 'verify', partition['Image Path'], - ' --nocheck', + '--nocheck', ] run_program(cmd) diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index c38f3cad..d951c7de 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -144,7 +144,7 @@ def menu_backup(): other_results = other_results, disk = disk, par = par) - if not result['CS']: + if not result['CS'] and not isinstance(result['Error'], GenericAbort): errors = True par['Error'] = result['Error'] From 7a13a1551436d42433608440c1a459b29ee1ede4 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 18:39:02 -0800 Subject: [PATCH 83/85] Bugfix: bcdboot (again) --- .bin/Scripts/functions/windows_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index 78396a0e..982ebf74 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -202,7 +202,7 @@ def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): cmd = [ - r'{}:\Windows\System32\bcdboot.exe'.format( + r'{}\Windows\System32\bcdboot.exe'.format( global_vars['Env']['SYSTEMDRIVE']), r'{}:\Windows'.format(windows_letter), '/s', '{}:'.format(system_letter), From b6cc250892ed4c0a6f3d12709fdbaf7f0b5d66e0 Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 19:30:14 -0800 Subject: [PATCH 84/85] Added Images folder to PE --- .bin/Scripts/build_pe.ps1 | 4 ++-- WinPE.jpg => Images/WinPE.jpg | Bin 2 files changed, 2 insertions(+), 2 deletions(-) rename WinPE.jpg => Images/WinPE.jpg (100%) diff --git a/.bin/Scripts/build_pe.ps1 b/.bin/Scripts/build_pe.ps1 index 7e9c9f68..91a423bc 100644 --- a/.bin/Scripts/build_pe.ps1 +++ b/.bin/Scripts/build_pe.ps1 @@ -531,7 +531,7 @@ if ($MyInvocation.InvocationName -ne ".") { $DestIni = "$Mount\.bin\HWiNFO\HWiNFO32.INI" } Move-Item -Path "$Mount\.bin\HWiNFO\HWiNFO.INI" -Destination $DestIni -Force - Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\.bin\ConEmu\ConEmu.jpg" -Recurse -Force + Copy-Item -Path "$Root\Images\WinPE.jpg" -Destination "$Mount\.bin\ConEmu\ConEmu.jpg" -Recurse -Force Copy-Item -Path "$Bin\Scripts" -Destination "$Mount\.bin\Scripts" -Recurse -Force # Add System32 items @@ -541,7 +541,7 @@ if ($MyInvocation.InvocationName -ne ".") { Start-Process -FilePath "$HostSystem32\takeown.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait $ArgumentList = @("$Mount\Windows\System32\winpe.jpg", "/grant", "Administrators:F") Start-Process -FilePath "$HostSystem32\icacls.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait - Copy-Item -Path "$Root\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force + Copy-Item -Path "$Root\Images\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force # Load registry hives Write-Host "Updating Registry..." diff --git a/WinPE.jpg b/Images/WinPE.jpg similarity index 100% rename from WinPE.jpg rename to Images/WinPE.jpg From adbfa038b677fa0514fbbfed79d29979111d4abc Mon Sep 17 00:00:00 2001 From: Alan Mason <1923621+2Shirt@users.noreply.github.com> Date: Fri, 1 Dec 2017 19:32:27 -0800 Subject: [PATCH 85/85] Cowardly moving WinPE out of the way --- {.bin => FAKE_PE_ROOT/.bin}/Scripts/build_pe.ps1 | 0 .../.bin}/Scripts/functions/backup.py | 0 .../.bin}/Scripts/functions/common.py | 0 .../.bin}/Scripts/functions/data.py | 0 .../.bin}/Scripts/functions/disk.py | 0 .../.bin}/Scripts/functions/partition_uids.py | 0 .../.bin}/Scripts/functions/windows_setup.py | 0 .../.bin}/Scripts/functions/winpe_menus.py | 0 .../.bin}/Scripts/settings/main.py | 0 .../.bin}/Scripts/settings/tools.py | 0 .../.bin}/Scripts/winpe_root_menu.py | 0 .gitignore => FAKE_PE_ROOT/.gitignore | 0 .../.pe_items}/System32/Winpeshl.ini | 0 .../.pe_items}/System32/menu.cmd | 0 .../.pe_items}/_include/CPU-Z/cpuz.ini | 0 .../.pe_items}/_include/ConEmu/ConEmu.xml | 0 .../.pe_items}/_include/HWiNFO/HWiNFO.INI | 0 .../.pe_items}/_include/NotepadPlusPlus/config.xml | 0 .../.pe_items}/_include/NotepadPlusPlus/npp.cmd | 0 .../_include/NotepadPlusPlus/stylers.model.xml | 0 .../.pe_items}/_include/Q-Dir/Q-Dir.ini | 0 Build PE.cmd => FAKE_PE_ROOT/Build PE.cmd | 0 {Images => FAKE_PE_ROOT/Images}/WinPE.jpg | Bin LICENSE.txt => FAKE_PE_ROOT/LICENSE.txt | 0 README.md => FAKE_PE_ROOT/README.md | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/build_pe.ps1 (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/backup.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/common.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/data.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/disk.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/partition_uids.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/windows_setup.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/functions/winpe_menus.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/settings/main.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/settings/tools.py (100%) rename {.bin => FAKE_PE_ROOT/.bin}/Scripts/winpe_root_menu.py (100%) rename .gitignore => FAKE_PE_ROOT/.gitignore (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/System32/Winpeshl.ini (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/System32/menu.cmd (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/CPU-Z/cpuz.ini (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/ConEmu/ConEmu.xml (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/HWiNFO/HWiNFO.INI (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/NotepadPlusPlus/config.xml (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/NotepadPlusPlus/npp.cmd (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/NotepadPlusPlus/stylers.model.xml (100%) rename {.pe_items => FAKE_PE_ROOT/.pe_items}/_include/Q-Dir/Q-Dir.ini (100%) rename Build PE.cmd => FAKE_PE_ROOT/Build PE.cmd (100%) rename {Images => FAKE_PE_ROOT/Images}/WinPE.jpg (100%) rename LICENSE.txt => FAKE_PE_ROOT/LICENSE.txt (100%) rename README.md => FAKE_PE_ROOT/README.md (100%) diff --git a/.bin/Scripts/build_pe.ps1 b/FAKE_PE_ROOT/.bin/Scripts/build_pe.ps1 similarity index 100% rename from .bin/Scripts/build_pe.ps1 rename to FAKE_PE_ROOT/.bin/Scripts/build_pe.ps1 diff --git a/.bin/Scripts/functions/backup.py b/FAKE_PE_ROOT/.bin/Scripts/functions/backup.py similarity index 100% rename from .bin/Scripts/functions/backup.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/backup.py diff --git a/.bin/Scripts/functions/common.py b/FAKE_PE_ROOT/.bin/Scripts/functions/common.py similarity index 100% rename from .bin/Scripts/functions/common.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/common.py diff --git a/.bin/Scripts/functions/data.py b/FAKE_PE_ROOT/.bin/Scripts/functions/data.py similarity index 100% rename from .bin/Scripts/functions/data.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/data.py diff --git a/.bin/Scripts/functions/disk.py b/FAKE_PE_ROOT/.bin/Scripts/functions/disk.py similarity index 100% rename from .bin/Scripts/functions/disk.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/disk.py diff --git a/.bin/Scripts/functions/partition_uids.py b/FAKE_PE_ROOT/.bin/Scripts/functions/partition_uids.py similarity index 100% rename from .bin/Scripts/functions/partition_uids.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/partition_uids.py diff --git a/.bin/Scripts/functions/windows_setup.py b/FAKE_PE_ROOT/.bin/Scripts/functions/windows_setup.py similarity index 100% rename from .bin/Scripts/functions/windows_setup.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/windows_setup.py diff --git a/.bin/Scripts/functions/winpe_menus.py b/FAKE_PE_ROOT/.bin/Scripts/functions/winpe_menus.py similarity index 100% rename from .bin/Scripts/functions/winpe_menus.py rename to FAKE_PE_ROOT/.bin/Scripts/functions/winpe_menus.py diff --git a/.bin/Scripts/settings/main.py b/FAKE_PE_ROOT/.bin/Scripts/settings/main.py similarity index 100% rename from .bin/Scripts/settings/main.py rename to FAKE_PE_ROOT/.bin/Scripts/settings/main.py diff --git a/.bin/Scripts/settings/tools.py b/FAKE_PE_ROOT/.bin/Scripts/settings/tools.py similarity index 100% rename from .bin/Scripts/settings/tools.py rename to FAKE_PE_ROOT/.bin/Scripts/settings/tools.py diff --git a/.bin/Scripts/winpe_root_menu.py b/FAKE_PE_ROOT/.bin/Scripts/winpe_root_menu.py similarity index 100% rename from .bin/Scripts/winpe_root_menu.py rename to FAKE_PE_ROOT/.bin/Scripts/winpe_root_menu.py diff --git a/.gitignore b/FAKE_PE_ROOT/.gitignore similarity index 100% rename from .gitignore rename to FAKE_PE_ROOT/.gitignore diff --git a/.pe_items/System32/Winpeshl.ini b/FAKE_PE_ROOT/.pe_items/System32/Winpeshl.ini similarity index 100% rename from .pe_items/System32/Winpeshl.ini rename to FAKE_PE_ROOT/.pe_items/System32/Winpeshl.ini diff --git a/.pe_items/System32/menu.cmd b/FAKE_PE_ROOT/.pe_items/System32/menu.cmd similarity index 100% rename from .pe_items/System32/menu.cmd rename to FAKE_PE_ROOT/.pe_items/System32/menu.cmd diff --git a/.pe_items/_include/CPU-Z/cpuz.ini b/FAKE_PE_ROOT/.pe_items/_include/CPU-Z/cpuz.ini similarity index 100% rename from .pe_items/_include/CPU-Z/cpuz.ini rename to FAKE_PE_ROOT/.pe_items/_include/CPU-Z/cpuz.ini diff --git a/.pe_items/_include/ConEmu/ConEmu.xml b/FAKE_PE_ROOT/.pe_items/_include/ConEmu/ConEmu.xml similarity index 100% rename from .pe_items/_include/ConEmu/ConEmu.xml rename to FAKE_PE_ROOT/.pe_items/_include/ConEmu/ConEmu.xml diff --git a/.pe_items/_include/HWiNFO/HWiNFO.INI b/FAKE_PE_ROOT/.pe_items/_include/HWiNFO/HWiNFO.INI similarity index 100% rename from .pe_items/_include/HWiNFO/HWiNFO.INI rename to FAKE_PE_ROOT/.pe_items/_include/HWiNFO/HWiNFO.INI diff --git a/.pe_items/_include/NotepadPlusPlus/config.xml b/FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/config.xml similarity index 100% rename from .pe_items/_include/NotepadPlusPlus/config.xml rename to FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/config.xml diff --git a/.pe_items/_include/NotepadPlusPlus/npp.cmd b/FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/npp.cmd similarity index 100% rename from .pe_items/_include/NotepadPlusPlus/npp.cmd rename to FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/npp.cmd diff --git a/.pe_items/_include/NotepadPlusPlus/stylers.model.xml b/FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/stylers.model.xml similarity index 100% rename from .pe_items/_include/NotepadPlusPlus/stylers.model.xml rename to FAKE_PE_ROOT/.pe_items/_include/NotepadPlusPlus/stylers.model.xml diff --git a/.pe_items/_include/Q-Dir/Q-Dir.ini b/FAKE_PE_ROOT/.pe_items/_include/Q-Dir/Q-Dir.ini similarity index 100% rename from .pe_items/_include/Q-Dir/Q-Dir.ini rename to FAKE_PE_ROOT/.pe_items/_include/Q-Dir/Q-Dir.ini diff --git a/Build PE.cmd b/FAKE_PE_ROOT/Build PE.cmd similarity index 100% rename from Build PE.cmd rename to FAKE_PE_ROOT/Build PE.cmd diff --git a/Images/WinPE.jpg b/FAKE_PE_ROOT/Images/WinPE.jpg similarity index 100% rename from Images/WinPE.jpg rename to FAKE_PE_ROOT/Images/WinPE.jpg diff --git a/LICENSE.txt b/FAKE_PE_ROOT/LICENSE.txt similarity index 100% rename from LICENSE.txt rename to FAKE_PE_ROOT/LICENSE.txt diff --git a/README.md b/FAKE_PE_ROOT/README.md similarity index 100% rename from README.md rename to FAKE_PE_ROOT/README.md