Compare commits

..

No commits in common. "dev" and "repo-merge-prep" have entirely different histories.

632 changed files with 6572 additions and 51473 deletions

8
.gitignore vendored
View file

@ -1,8 +0,0 @@
**/__pycache__
**/*.7z
**/*.DS_Store
**/*.bak
**/*.exe
**/*.swp
setup/BUILD*
setup/OUT*

View file

@ -1,6 +0,0 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.257'
hooks:
- id: ruff

View file

@ -0,0 +1,603 @@
# Wizard Kit: Windows PE Build Tool
## 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
$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"
$Host.UI.RawUI.ForegroundColor = "White"
$HostSystem32 = "{0}\System32" -f $Env:SystemRoot
$DISM = "{0}\DISM.exe" -f $Env:DISMRoot
## Functions ##
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 = @(
"$Build\Mount",
"$Build\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: $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"
$DownloadErrors += 1
}
}
function FindDynamicUrl ($SourcePage, $RegEx) {
# 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'
# Remove tmp_page
Remove-Item "tmp_page"
$Url | Select-Object -First 1
}
function WKPause ($Message = "Press Enter to continue... ") {
Write-Host $Message -NoNewLine
Read-Host
}
## 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`n`n`n`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"
MakeClean
New-Item -Type Directory $LogDir 2>&1 | Out-Null
if (Ask-User "Update Tools?") {
$DownloadErrors = 0
## Download Tools ##
$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"),
# 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"),
# 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"),
# 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]
}
## 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 "$HostSystem32\msiexec.exe" -ArgumentList $ArgumentList -Wait
$SevenZip = "$Temp\7zi\Files\7-Zip\7z.exe"
$ArgumentList = @(
"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$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 = "$Build\bin\x86\7-Zip\7za.exe"
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# Blue Screen View
Write-Host "Extracting: BlueScreenView"
try {
$ArgumentList = @(
"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$Build\bin\x86\BlueScreenView",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
Remove-Item "$Temp\bluescreenview*"
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# ConEmu
Write-Host "Extracting: ConEmu"
try {
$ArgumentList = @(
"x", "$Temp\ConEmuPack.7z", "-o$Build\bin\amd64\ConEmu",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
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$Build\bin\x86\ConEmu",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
Remove-Item "$Build\bin\x86\ConEmu\ConEmu64.exe"
Remove-Item "$Build\bin\x86\ConEmu\ConEmu64.map"
Remove-Item "$Temp\ConEmuPack*"
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# Fast Copy
Write-Host "Extracting: FastCopy"
try {
$ArgumentList = @(
"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$Build\bin\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"
}
# Killer Network Driver
Write-Host "Extracting: Killer Network Driver"
try {
$ArgumentList = @(
"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$Build\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 {
$ArgumentList = @(
"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$Build\bin\x86\HWiNFO",
"-aoa", "-bso0", "-bse0", "-bsp0", "HWiNFO32.exe")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
Remove-Item "$Temp\hwinfo*"
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"
}
# Notepad++
Write-Host "Extracting: Notepad++"
try {
$ArgumentList = @(
"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$Build\bin\x86\NotepadPlusPlus",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
Remove-Item "$Temp\npp*"
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"
}
# NT Password Editor
Write-Host "Extracting: NT Password Editor"
try {
$ArgumentList = @(
"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 "$Build\bin\amd64\NT Password Editor\ntpwedit64.exe" "$Build\bin\amd64\NT Password Editor\ntpwedit.exe" -Force
$ArgumentList = @(
"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
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$Build\bin\amd64\TestDisk",
"-aoa", "-bso0", "-bse0", "-bsp0")
# Remove destination since Move-Item -Force can't handle this recursive merge
Remove-Item "$Build\bin\amd64\TestDisk" -Recurse -Force 2>&1 | Out-Null
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
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$Build\bin\x86\TestDisk",
"-aoa", "-bso0", "-bse0", "-bsp0")
# Remove destination since Move-Item -Force can't handle this recursive merge
Remove-Item "$Build\bin\x86\TestDisk" -Recurse -Force 2>&1 | Out-Null
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
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 {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# Prime95
Write-Host "Extracting: Prime95"
try {
$ArgumentList = @(
"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$Build\bin\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$Build\bin\amd64\ProduKey",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
$ArgumentList = @(
"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*"
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# Python (x64)
Write-Host "Extracting: Python (x64)"
try {
$ArgumentList = @(
"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$Build\bin\amd64\python",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# Python (x32)
Write-Host "Extracting: Python (x32)"
try {
$ArgumentList = @(
"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$Build\bin\x86\python",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
}
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 = @(
"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$Build\bin\x86",
"-aoa", "-bso0", "-bse0", "-bsp0")
Start-Process -FilePath $SevenZip -ArgumentList $ArgumentList -NoNewWindow -Wait
Remove-Item "$Temp\qdir*"
}
catch {
Write-Host (" ERROR: Failed to extract files." ) -ForegroundColor "Red"
}
# wimlib-imagex
try {
$ArgumentList = @(
"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$Build\bin\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 ##
foreach ($Arch in @("amd64", "x86")) {
$Drivers = "$Build\Drivers\$Arch"
$Mount = "$Build\Mount"
$PEFiles = "$Build\PEFiles\$Arch"
# Copy WinPE files
Write-Host "Copying files..."
$Cmd = ("{0}\copype.cmd" -f $Env:WinPERoot)
Start-Process -FilePath $Cmd -ArgumentList @($Arch, $PEFiles) -NoNewWindow -Wait
# 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..."
New-Item -Path $Mount -ItemType "directory" -Force | 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 -LogPath "$LogDir\DISM.log"
# 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}.cab" -f $Env:WinPERoot, $Arch, $Package)
Write-Host " $Package..."
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 -LogPath "$LogDir\DISM.log"
}
}
# Set RamDisk size
$ArgumentList = @(
('/Image:"{0}"' -f $Mount),
"/Set-ScratchSpace:512",
('/LogPath:"{0}\DISM.log"' -f $LogDir)
)
Start-Process -FilePath $DISM -ArgumentList $ArgumentList -NoNewWindow -Wait
# Add tools
Write-Host "Copying tools..."
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 {
$DestIni = "$Mount\.bin\HWiNFO\HWiNFO32.INI"
}
Move-Item -Path "$Mount\.bin\HWiNFO\HWiNFO.INI" -Destination $DestIni -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
$HostSystem32 = "{0}\System32" -f $Env:SystemRoot
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")
Start-Process -FilePath "$HostSystem32\icacls.exe" -ArgumentList $ArgumentList -NoNewWindow -Wait
Copy-Item -Path "$Root\Images\WinPE.jpg" -Destination "$Mount\Windows\System32\winpe.jpg" -Recurse -Force
# Load registry hives
Write-Host "Updating Registry..."
$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 tools to path
## .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%\.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
$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/
Start-Sleep -Seconds 2
[gc]::collect()
# Unload registry hives
Start-Sleep -Seconds 2
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..."
Dismount-WindowsImage -Path $Mount -Save -LogPath "$LogDir\DISM.log"
# Create 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
Write-Host "`nDone."
WKPause "Press Enter to exit... "
}

View file

@ -0,0 +1,150 @@
# 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, par):
if par.get('Image Exists', False) 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(par)]
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 = '{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'])
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(display)
else:
display = ' {}'.format(display)
# Append rest of Display String for valid/clobber partitions
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
# 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.")

View file

@ -0,0 +1,713 @@
# 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'], 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_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}}{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)
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.")

View file

@ -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_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.")

View file

@ -0,0 +1,372 @@
# Wizard Kit PE: Functions - Disk
from functions.common import *
from functions 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():
remove_volume_letters()
# 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'
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 = {}
script = [
'select disk {}'.format(disk['Number']),
'detail disk']
# Run
try:
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
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 = []
try:
# Run script
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])
disks.append({'Number': num, 'Size': size})
return disks
def get_partition_details(disk, partition):
details = {}
script = [
'select disk {}'.format(disk['Number']),
'select partition {}'.format(partition['Number']),
'detail partition']
# Diskpart details
try:
# Run script
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':
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', '')[:29],
'OS': guid.get('OS', '')[:26]})
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:
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
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 = []
script = [
'select disk {}'.format(disk['Number']),
'list partition']
try:
# Run script
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]
size = human_readable_size(tmp[1])
partitions.append({'Number': num, 'Size': size})
return partitions
def get_table_type(disk):
part_type = 'Unknown'
script = [
'select disk {}'.format(disk['Number']),
'uniqueid disk']
try:
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'
return part_type
def get_volumes():
vols = []
try:
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]})
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 = '{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
script = [
'select volume {}'.format(letter),
'remove noerr',
'assign letter={}'.format(new_letter)]
try:
run_diskpart(script)
except subprocess.CalledProcessError:
pass
else:
return new_letter
def remove_volume_letters(keep=None):
if not keep:
keep = ''
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_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)
sleep(2)
return result
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_name = '{YELLOW}{p_name}{CLEAR}'.format(
p_name=p_name, **COLORS)
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'])
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 GenericAbort
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -0,0 +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.")

View file

@ -0,0 +1,226 @@
# Wizard Kit PE: Functions - Windows Setup
from functions.data import *
from functions.disk import *
# STATIC VARIABLES
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 WINDOWS_SERVER['Mounted']:
for ext in ['esd', 'wim', 'swm']:
path = r'\\{}\{}\images\{}.{}'.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 GenericAbort
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."""
script = [
# Partition table
'select disk {}'.format(disk['Number']),
'clean',
'convert gpt',
# System partition
# NOTE: ESP needs to be >= 260 for Advanced Format 4K disks
'create partition efi size=500',
'format quick fs=fat32 label="System"',
'assign letter="S"',
# Microsoft Reserved (MSR) partition
'create partition msr size=128',
# Windows partition
'create partition primary',
'format quick fs=ntfs label="Windows"',
'assign letter="W"',
# Recovery Tools partition
'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."""
script = [
# Partition table
'select disk {}'.format(disk['Number']),
'clean',
# System partition
'create partition primary size=100',
'format fs=ntfs quick label="System Reserved"',
'active',
'assign letter="S"',
# Windows partition
'create partition primary',
'format fs=ntfs quick label="Windows"',
'assign letter="W"',
# Recovery Tools partition
'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."""
if not WINDOWS_SERVER['Mounted']:
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 GenericAbort
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(
global_vars['Env']['SYSTEMDRIVE']),
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.")

View file

@ -0,0 +1,428 @@
# 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 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
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()
print_standard('{}\n'.format(global_vars['Title']))
ticket_number = get_ticket_number()
# Mount backup shares
mount_backup_shares()
# Select destination
destination = select_backup_destination(auto_select=False)
# 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_data(message='Ticket:', data=ticket_number)
show_data(
message = 'Source:',
data = '[{Table}] ({Type}) {Name} {Size}'.format(**disk),
)
show_data(
message = 'Destination:',
data = destination.get('Display Name', destination['Name']),
)
for par in disk['Partitions']:
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
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,
par = par)
if not result['CS'] and not isinstance(result['Error'], GenericAbort):
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
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:
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():
check_pe_tools()
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 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'):
run_program(['wpeutil', 'reboot'])
elif (selection == 'S'):
run_program(['wpeutil', 'shutdown'])
else:
sys.exit()
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
clear_screen()
print_standard('{}\n'.format(global_vars['Title']))
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 dest_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_data(message='Ticket:', data=ticket_number)
show_data(message='Installing:', data=windows_version['Name'])
show_data(
message = 'Boot Method:',
data = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')
show_data(message='Using Image:', data=windows_image['Path'])
show_data(
message = 'ERASING:',
data = '[{Table}] ({Type}) {Name} {Size}\n'.format(**dest_disk),
warning = True)
for par in dest_disk['Partitions']:
show_data(
message = 'Partition {}:'.format(par['Number']),
data = par['Display String'],
warning = True)
print_warning(dest_disk['Format Warnings'])
if (not ask('Is this correct?')):
raise GenericAbort
# Safety check
print_standard('\nSAFETY CHECK')
print_warning('All data will be DELETED from the '
'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?')):
raise GenericAbort
# 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.')
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():
tools = [{'Name': 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()):
name = tools[int(selection)-1]['Name']
cmd = [PE_TOOLS[name]['Path']] + PE_TOOLS[name].get('Args', [])
if name == '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 {}'.format(name))
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')
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.")

View file

@ -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.")

View file

@ -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.")

View file

@ -0,0 +1,20 @@
# 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 SystemExit:
pass
except:
major_exception()

3
FAKE_PE_ROOT/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
**/__pycache__/*
BUILD
OUT_PE

View file

@ -0,0 +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\winpe_root_menu.py"

View file

@ -0,0 +1,2 @@
@echo off
python "%SystemDrive%\.bin\Scripts\winpe_root_menu.py"

View file

@ -0,0 +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

View file

@ -1,56 +1,56 @@
<?xml version="1.0" encoding="Windows-1252" ?>
<NotepadPlus>
<FindHistory nbMaxFindHistoryPath="10" nbMaxFindHistoryFilter="10" nbMaxFindHistoryFind="10" nbMaxFindHistoryReplace="10" matchWord="no" matchCase="no" wrap="yes" directionDown="yes" fifRecuisive="yes" fifInHiddenFolder="no" dlgAlwaysVisible="no" fifFilterFollowsDoc="no" fifFolderFollowsDoc="no" searchMode="0" transparencyMode="1" transparency="150" dotMatchesNewline="no" />
<History nbMaxFile="10" inSubMenu="no" customLength="-1" />
<GUIConfigs>
<GUIConfig name="ToolBar" visible="no">standard</GUIConfig>
<GUIConfig name="StatusBar">hide</GUIConfig>
<GUIConfig name="TabBar" dragAndDrop="yes" drawTopBar="yes" drawInactiveTab="yes" reduce="yes" closeButton="yes" doubleClick2Close="no" vertical="no" multiLine="no" hide="no" quitOnEmpty="no" />
<GUIConfig name="ScintillaViewsSplitter">vertical</GUIConfig>
<GUIConfig name="UserDefineDlg" position="undocked">hide</GUIConfig>
<GUIConfig name="TabSetting" replaceBySpace="yes" size="4" />
<GUIConfig name="noUpdate" intervalDays="15" nextUpdateDate="20080426">no</GUIConfig>
<GUIConfig name="Auto-detection">yes</GUIConfig>
<GUIConfig name="CheckHistoryFiles">no</GUIConfig>
<GUIConfig name="TrayIcon">no</GUIConfig>
<GUIConfig name="MaitainIndent">yes</GUIConfig>
<GUIConfig name="TagsMatchHighLight" TagAttrHighLight="yes" HighLightNonHtmlZone="no">yes</GUIConfig>
<GUIConfig name="RememberLastSession">no</GUIConfig>
<GUIConfig name="DetectEncoding">yes</GUIConfig>
<GUIConfig name="NewDocDefaultSettings" format="0" encoding="4" lang="0" codepage="-1" openAnsiAsUTF8="yes" />
<GUIConfig name="langsExcluded" gr0="0" gr1="0" gr2="0" gr3="0" gr4="0" gr5="0" gr6="0" gr7="0" langMenuCompact="yes" />
<GUIConfig name="Print" lineNumber="yes" printOption="3" headerLeft="" headerMiddle="" headerRight="" footerLeft="" footerMiddle="" footerRight="" headerFontName="" headerFontStyle="0" headerFontSize="0" footerFontName="" footerFontStyle="0" footerFontSize="0" margeLeft="0" margeRight="0" margeTop="0" margeBottom="0" />
<GUIConfig name="Backup" action="0" useCustumDir="no" dir="" isSnapshotMode="no" snapshotBackupTiming="7000" />
<GUIConfig name="TaskList">yes</GUIConfig>
<GUIConfig name="MRU">yes</GUIConfig>
<GUIConfig name="URL">2</GUIConfig>
<GUIConfig name="globalOverride" fg="no" bg="no" font="yes" fontSize="no" bold="no" italic="no" underline="no" />
<GUIConfig name="auto-completion" autoCAction="3" triggerFromNbChar="1" autoCIgnoreNumbers="yes" funcParams="yes" />
<GUIConfig name="auto-insert" parentheses="no" brackets="no" curlyBrackets="no" quotes="no" doubleQuotes="no" htmlXmlTag="no" />
<GUIConfig name="sessionExt"></GUIConfig>
<GUIConfig name="workspaceExt"></GUIConfig>
<GUIConfig name="MenuBar">hide</GUIConfig>
<GUIConfig name="Caret" width="1" blinkRate="600" />
<GUIConfig name="ScintillaGlobalSettings" enableMultiSelection="no" />
<GUIConfig name="openSaveDir" value="0" defaultDirPath="" />
<GUIConfig name="titleBar" short="no" />
<GUIConfig name="wordCharList" useDefault="yes" charsAdded="" />
<GUIConfig name="delimiterSelection" leftmostDelimiter="40" rightmostDelimiter="41" delimiterSelectionOnEntireDocument="no" />
<GUIConfig name="multiInst" setting="0" />
<GUIConfig name="MISC" fileSwitcherWithoutExtColumn="no" backSlashIsEscapeCharacterForSql="yes" newStyleSaveDlg="no" isFolderDroppedOpenFiles="no" />
<GUIConfig name="searchEngine" searchEngineChoice="1" searchEngineCustom="" />
<GUIConfig name="SmartHighLight" matchCase="no" wholeWordOnly="no" useFindSettings="no" onAnotherView="no">yes</GUIConfig>
<GUIConfig name="ScintillaPrimaryView" lineNumberMargin="show" bookMarkMargin="show" indentGuideLine="show" folderMarkStyle="box" lineWrapMethod="aligned" currentLineHilitingShow="show" scrollBeyondLastLine="no" disableAdvancedScrolling="no" wrapSymbolShow="hide" Wrap="no" borderEdge="yes" edge="no" edgeNbColumn="80" zoom="0" zoom2="0" whiteSpaceShow="hide" eolShow="hide" borderWidth="2" smoothFont="no" />
<GUIConfig name="DockingManager" leftWidth="200" rightWidth="200" topHeight="200" bottomHeight="200">
<ActiveTabs cont="0" activeTab="-1" />
<ActiveTabs cont="1" activeTab="-1" />
<ActiveTabs cont="2" activeTab="-1" />
<ActiveTabs cont="3" activeTab="-1" />
</GUIConfig>
</GUIConfigs>
<ProjectPanels>
<ProjectPanel id="0" workSpaceFile="" />
<ProjectPanel id="1" workSpaceFile="" />
<ProjectPanel id="2" workSpaceFile="" />
</ProjectPanels>
</NotepadPlus>
<?xml version="1.0" encoding="Windows-1252" ?>
<NotepadPlus>
<FindHistory nbMaxFindHistoryPath="10" nbMaxFindHistoryFilter="10" nbMaxFindHistoryFind="10" nbMaxFindHistoryReplace="10" matchWord="no" matchCase="no" wrap="yes" directionDown="yes" fifRecuisive="yes" fifInHiddenFolder="no" dlgAlwaysVisible="no" fifFilterFollowsDoc="no" fifFolderFollowsDoc="no" searchMode="0" transparencyMode="1" transparency="150" dotMatchesNewline="no" />
<History nbMaxFile="10" inSubMenu="no" customLength="-1" />
<GUIConfigs>
<GUIConfig name="ToolBar" visible="no">standard</GUIConfig>
<GUIConfig name="StatusBar">hide</GUIConfig>
<GUIConfig name="TabBar" dragAndDrop="yes" drawTopBar="yes" drawInactiveTab="yes" reduce="yes" closeButton="yes" doubleClick2Close="no" vertical="no" multiLine="no" hide="no" quitOnEmpty="no" />
<GUIConfig name="ScintillaViewsSplitter">vertical</GUIConfig>
<GUIConfig name="UserDefineDlg" position="undocked">hide</GUIConfig>
<GUIConfig name="TabSetting" replaceBySpace="yes" size="4" />
<GUIConfig name="noUpdate" intervalDays="15" nextUpdateDate="20080426">no</GUIConfig>
<GUIConfig name="Auto-detection">yes</GUIConfig>
<GUIConfig name="CheckHistoryFiles">no</GUIConfig>
<GUIConfig name="TrayIcon">no</GUIConfig>
<GUIConfig name="MaitainIndent">yes</GUIConfig>
<GUIConfig name="TagsMatchHighLight" TagAttrHighLight="yes" HighLightNonHtmlZone="no">yes</GUIConfig>
<GUIConfig name="RememberLastSession">no</GUIConfig>
<GUIConfig name="DetectEncoding">yes</GUIConfig>
<GUIConfig name="NewDocDefaultSettings" format="0" encoding="4" lang="0" codepage="-1" openAnsiAsUTF8="yes" />
<GUIConfig name="langsExcluded" gr0="0" gr1="0" gr2="0" gr3="0" gr4="0" gr5="0" gr6="0" gr7="0" langMenuCompact="yes" />
<GUIConfig name="Print" lineNumber="yes" printOption="3" headerLeft="" headerMiddle="" headerRight="" footerLeft="" footerMiddle="" footerRight="" headerFontName="" headerFontStyle="0" headerFontSize="0" footerFontName="" footerFontStyle="0" footerFontSize="0" margeLeft="0" margeRight="0" margeTop="0" margeBottom="0" />
<GUIConfig name="Backup" action="0" useCustumDir="no" dir="" isSnapshotMode="no" snapshotBackupTiming="7000" />
<GUIConfig name="TaskList">yes</GUIConfig>
<GUIConfig name="MRU">yes</GUIConfig>
<GUIConfig name="URL">2</GUIConfig>
<GUIConfig name="globalOverride" fg="no" bg="no" font="yes" fontSize="no" bold="no" italic="no" underline="no" />
<GUIConfig name="auto-completion" autoCAction="3" triggerFromNbChar="1" autoCIgnoreNumbers="yes" funcParams="yes" />
<GUIConfig name="auto-insert" parentheses="no" brackets="no" curlyBrackets="no" quotes="no" doubleQuotes="no" htmlXmlTag="no" />
<GUIConfig name="sessionExt"></GUIConfig>
<GUIConfig name="workspaceExt"></GUIConfig>
<GUIConfig name="MenuBar">hide</GUIConfig>
<GUIConfig name="Caret" width="1" blinkRate="600" />
<GUIConfig name="ScintillaGlobalSettings" enableMultiSelection="no" />
<GUIConfig name="openSaveDir" value="0" defaultDirPath="" />
<GUIConfig name="titleBar" short="no" />
<GUIConfig name="wordCharList" useDefault="yes" charsAdded="" />
<GUIConfig name="delimiterSelection" leftmostDelimiter="40" rightmostDelimiter="41" delimiterSelectionOnEntireDocument="no" />
<GUIConfig name="multiInst" setting="0" />
<GUIConfig name="MISC" fileSwitcherWithoutExtColumn="no" backSlashIsEscapeCharacterForSql="yes" newStyleSaveDlg="no" isFolderDroppedOpenFiles="no" />
<GUIConfig name="searchEngine" searchEngineChoice="1" searchEngineCustom="" />
<GUIConfig name="SmartHighLight" matchCase="no" wholeWordOnly="no" useFindSettings="no" onAnotherView="no">yes</GUIConfig>
<GUIConfig name="ScintillaPrimaryView" lineNumberMargin="show" bookMarkMargin="show" indentGuideLine="show" folderMarkStyle="box" lineWrapMethod="aligned" currentLineHilitingShow="show" scrollBeyondLastLine="no" disableAdvancedScrolling="no" wrapSymbolShow="hide" Wrap="no" borderEdge="yes" edge="no" edgeNbColumn="80" zoom="0" zoom2="0" whiteSpaceShow="hide" eolShow="hide" borderWidth="2" smoothFont="no" />
<GUIConfig name="DockingManager" leftWidth="200" rightWidth="200" topHeight="200" bottomHeight="200">
<ActiveTabs cont="0" activeTab="-1" />
<ActiveTabs cont="1" activeTab="-1" />
<ActiveTabs cont="2" activeTab="-1" />
<ActiveTabs cont="3" activeTab="-1" />
</GUIConfig>
</GUIConfigs>
<ProjectPanels>
<ProjectPanel id="0" workSpaceFile="" />
<ProjectPanel id="1" workSpaceFile="" />
<ProjectPanel id="2" workSpaceFile="" />
</ProjectPanels>
</NotepadPlus>

View file

@ -0,0 +1,3 @@
@echo off
start "" %SystemDrive%\.bin\NotepadPlusPlus\notepadplusplus.exe %2 %3 %4 %5 %6 %7 %8 %9

View file

@ -0,0 +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

View file

@ -1,23 +1,24 @@
:: WizardKit: Windows PE Build Tool ::
:: Wizard Kit: Windows PE Build Tool Launcher ::
@echo off
:Init
setlocal EnableDelayedExpansion
title WizardKit: Build Tool
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 Update environment using WADK script
set "dandi_set_env=%adk_root%\Deployment Tools\DandISetEnv.bat"
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
set "script=%~dp0\pe\build_pe.ps1"
powershell -executionpolicy bypass -noprofile -file %script% || goto ErrorUnknown
PowerShell -ExecutionPolicy bypass -File %ps_script%"
goto Exit
:: Functions ::
@ -30,9 +31,9 @@ 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
call :RequestElevation
rem reset errorlevel to 1 to abort the current non-elevated script
color 00
)
@exit /b %errorlevel%
@ -40,7 +41,7 @@ if %errorlevel% neq 0 (
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")
if /i "%%f" == "/DEBUG" (@echo on & set "DEBUG=/DEBUG")
)
@exit /b 0
@ -53,12 +54,12 @@ 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"
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
set adk_root=%%j\Assessment and Deployment Kit
)
rem Set errorlevel if necessary
if not defined adk_root color 00
@ -85,6 +86,11 @@ 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.

View file

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 168 KiB

View file

@ -1,7 +1,7 @@
Copyright (c) 2023 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:
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.
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.

18
FAKE_PE_ROOT/README.md Normal file
View file

@ -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

View file

@ -1,39 +0,0 @@
# WizardKit #
A collection of tools to help technicians service computers.
## Overview ##
There are a few main parts to this project and their uses:
* Live Linux image
* Hardware diagnostics
* CPU stress tests with temperature monitoring
* Health checks/tests for storage drives
* Misc other diagnostics
* Data recovery
* General data transfers from many possible filesystems
* Bit-level drive duplication based on ddrescue
* Live macOS image
* Hardware diagnostics
* CPU stress tests with temperature monitoring
* Health checks/tests for storage drives
* Data recovery
* _(Currently under development)_
* Live WinPE image
* _(Currently under development)_
* Windows Kit _(intended for UFDs)_
* Automated repairs
* AV scans
* Windows health checks
* Automated setup
* Install software
* System configuration
## Combined UFD ##
All parts can be combined onto a single UFD!
* Compatible with most legacy and UEFI bootloaders
* Custom boot menus
* To get started run `build-ufd` under the live Linux image

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

View file

@ -1,122 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
id="svg2"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="logo.svg"
inkscape:export-filename="/home/thewizardpp/projects/logos/logo512x512.png"
inkscape:export-xdpi="1440"
inkscape:export-ydpi="1440">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<filter
id="filter3668"
inkscape:label="Drop shadow"
width="1.5"
height="1.5"
x="-.25"
y="-.25">
<feGaussianBlur
id="feGaussianBlur3670"
in="SourceAlpha"
stdDeviation="1,000000"
result="blur" />
<feColorMatrix
id="feColorMatrix3672"
result="bluralpha"
type="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0,500000 0 " />
<feOffset
id="feOffset3674"
in="bluralpha"
dx="1,000000"
dy="1,000000"
result="offsetBlur" />
<feMerge
id="feMerge3676">
<feMergeNode
id="feMergeNode3678"
in="offsetBlur" />
<feMergeNode
id="feMergeNode3680"
in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="16.469461"
inkscape:cy="15.775995"
inkscape:document-units="px"
inkscape:current-layer="layer2"
showgrid="false"
inkscape:window-width="1152"
inkscape:window-height="844"
inkscape:window-x="-2"
inkscape:window-y="93"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer"
style="display:inline">
<g
id="g3613"
transform="matrix(1.0696952,0,0,1.0696952,-1.9682871,1.2767394)">
<path
sodipodi:nodetypes="cssssss"
d="m 28.466519,15.480445 c -1.690444,-0.411311 -3.880242,0.0024 -6.862802,1.703057 -4.343818,2.477 -5.647804,4.7124 -10.531132,6.5262 -2.7416801,1.0184 -7.1725478,1.2727 -6.7296333,-1.9563 0.4055207,-2.9564 4.8746766,-5.683963 10.7473903,-5.268022 7.253753,0.513753 7.780294,2.643843 11.236758,2.445771 4.073631,-0.233438 3.02577,-3.235043 2.139419,-3.450706 z"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path2822"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccscsc"
id="path2832"
d="m 22.349625,16.595174 c -5.498466,2.959917 -4.603518,5.10607 -10.999048,3.821601 1.40216,-4.418086 4.962036,-16.95097 7.147841,-17.2692571 1.878431,-0.2735287 4.924495,4.2931483 4.924495,4.2931483 0,0 -3.661803,-2.9673231 -4.16688,-1.7046325 -0.593183,1.4829546 2.39459,8.4145833 3.093592,10.8591403 z"
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccc"
id="path3611"
d="m 22.074942,15.74979 c 1.515307,-0.313608 1.831341,-0.3546 3.377477,-0.485523 1.799175,-0.173029 3.187957,0.237433 3.187957,0.237433"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

View file

@ -1,508 +0,0 @@
:: WizardKit: Wrapper for launching programs and scripts.
::
:: Some features:
:: * If the OS is 64-bit then the WorkingDir is scanned for a 64-bit version of the programs
:: * Allows for centralized terminal emulation settings management
:: * Allows for smaller "launcher" scripts to be used as they will rely on this script.
@echo off
if defined DEBUG (@echo on)
:Init
setlocal EnableDelayedExpansion
title WizardKit: Launcher
pushd "%~dp0"
call :FindBin
call :DeQuote L_ITEM
call :DeQuote L_PATH
call :DeQuote L_TYPE
:SetVariables
rem Set variables using settings\main.py file
set "SETTINGS=%bin%\Scripts\wk\cfg\main.py"
for %%v in (ARCHIVE_PASSWORD KIT_NAME_FULL OFFICE_SERVER_IP QUICKBOOKS_SERVER_IP) do (
set "var=%%v"
for /f "tokens=* usebackq" %%f in (`findstr "!var!=" "%SETTINGS%"`) do (
set "_v=%%f"
set "_v=!_v:*'=!"
set "%%v=!_v:~0,-1!"
)
)
rem Set ARCH to 32 as a gross assumption and check for x86_64 status
set ARCH=32
if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "ARCH=64"
set "SEVEN_ZIP=%bin%\7-Zip\7z.exe"
set "CON=%bin%\ConEmu\ConEmu.exe"
set "FASTCOPY=%bin%\FastCopy\FastCopy.exe"
set "POWERSHELL=%systemroot%\system32\WindowsPowerShell\v1.0\powershell.exe"
set "PYTHON=%bin%\Python\x32\python.exe"
if %ARCH% equ 64 (
set "CON=%bin%\ConEmu\ConEmu64.exe"
set "FASTCOPY=%bin%\FastCopy\FastCopy64.exe"
set "PYTHON=%bin%\Python\x64\python.exe"
)
:UpdateTitle
rem Sets title using KIT_NAME_FULL from settings\main.py (unless %window_title% already set)
if defined window_title (
title %window_title%
) else (
set "window_title=%*"
if not defined window_title set "window_title=Launcher"
set "window_title=%KIT_NAME_FULL%: %window_title%"
title %window_title%
)
:CheckUsage
rem Check for empty passed variables
if not defined L_TYPE (goto Usage)
if not defined L_PATH (goto Usage)
if not defined L_ITEM (goto Usage)
rem Assume if not "True" then False (i.e. undefine variable)
if /i not "%L_ELEV%" == "True" (set "L_ELEV=")
if /i not "%L_NCMD%" == "True" (set "L_NCMD=")
if /i not "%L__CLI%" == "True" (set "L__CLI=")
:RelaunchInConEmu
set RELOAD_IN_CONEMU=True
if defined ConEmuBuild set "RELOAD_IN_CONEMU="
if defined L_NCMD set "RELOAD_IN_CONEMU="
if "%L_TYPE%" == "Executable" set "RELOAD_IN_CONEMU="
if "%L_TYPE%" == "PSScript" set "RELOAD_IN_CONEMU="
if "%L_TYPE%" == "PyScript" set "RELOAD_IN_CONEMU="
if defined RELOAD_IN_CONEMU (
set "con_args=-new_console:n"
rem If in DEBUG state then force ConEmu to stay open
if defined DEBUG (set "con_args=!con_args! -new_console:c")
start "" "%CON%" -run ""%~0" %*" !con_args! || goto ErrorUnknown
exit /b 0
)
:CheckLaunchType
rem Jump to the selected launch type or show usage
if /i "%L_TYPE%" == "Executable" (goto LaunchExecutable)
if /i "%L_TYPE%" == "Folder" (goto LaunchFolder)
if /i "%L_TYPE%" == "Office" (goto LaunchOffice)
if /i "%L_TYPE%" == "PSScript" (goto LaunchPSScript)
if /i "%L_TYPE%" == "PyScript" (goto LaunchPyScript)
if /i "%L_TYPE%" == "QuickBooks" (goto LaunchQuickBooksSetup)
goto Usage
:LaunchExecutable
rem Prep
call :ExtractOrFindPath || goto ErrorProgramNotFound
rem Check for 64-bit prog (if running on 64-bit system)
set "prog=%_path%\%L_ITEM%"
if %ARCH% equ 64 (
if exist "%_path%\%L_ITEM:.=64.%" set "prog=%_path%\%L_ITEM:.=64.%"
) else (
if exist "%_path%\%L_ITEM:.=32.%" set "prog=%_path%\%L_ITEM:.=32.%"
)
if not exist "%prog%" goto ErrorProgramNotFound
rem Run
popd && pushd "%_path%"
if defined L__CLI goto LaunchExecutableCLI
if defined L_ELEV (
goto LaunchExecutableElev
) else (
goto LaunchExecutableUser
)
:LaunchExecutableCLI
rem Prep
set "con_args=-new_console:n"
if defined DEBUG (set "con_args=%con_args% -new_console:c")
if defined L_ELEV (set "con_args=%con_args% -new_console:a")
rem Run
start "" "%CON%" -run "%prog%" %L_ARGS% %con_args% || goto ErrorUnknown
goto Exit
:LaunchExecutableElev
rem Prep
call :DeQuote prog
call :DeQuote L_ARGS
rem Create VB script
mkdir "%bin%\tmp" 2>nul
echo Set UAC = CreateObject^("Shell.Application"^) > "%bin%\tmp\Elevate.vbs"
echo UAC.ShellExecute "%prog%", "%L_ARGS%", "", "runas", 1 >> "%bin%\tmp\Elevate.vbs"
rem Run
"%systemroot%\System32\cscript.exe" //nologo "%bin%\tmp\Elevate.vbs" || goto ErrorUnknown
goto Exit
:LaunchExecutableUser
rem Run
start "" "%prog%" %L_ARGS% || goto ErrorUnknown
goto Exit
:LaunchFolder
rem Prep
call :ExtractOrFindPath || goto ErrorProgramNotFound
rem Run
start "" "explorer.exe" "%_path%" || goto ErrorUnknown
goto Exit
:LaunchOffice
call "%bin%\Scripts\init_client_dir.cmd" /Office
set "_odt=False"
if %L_PATH% equ 2016 (set "_odt=True")
if %L_PATH% equ 2019 (set "_odt=True")
if "%_odt%" == "True" (
goto LaunchOfficeODT
) else (
goto LaunchOfficeSetup
)
:LaunchOfficeODT
rem Prep
set "args=-aoa -bso0 -bse0 -bsp0 -p%ARCHIVE_PASSWORD%"
set "config=%L_ITEM%"
set "dest=%client_dir%\Office\ODT"
set "odt_exe=setup.exe"
set "source=%cbin%\_Office.7z"
rem Extract
if not exist "%source%" (goto ErrorODTSourceNotFound)
"%SEVEN_ZIP%" e "%source%" %args% -o"%dest%" %odt_exe% %config% || exit /b 1
"%systemroot%\System32\ping.exe" -n 2 127.0.0.1>nul
rem Verify
if not exist "%dest%\setup.exe" (goto ErrorODTSourceNotFound)
if not exist "%dest%\%config%" (goto ErrorODTSourceNotFound)
pushd "%dest%"
rem Run
rem # The line below jumps to ErrorUnknown even when it runs correctly??
rem start "" "setup.exe" /configure %L_ITEM% || popd & goto ErrorUnknown
rem # Going to assume it extracted correctly and blindly start setup.exe
start "" "setup.exe" /configure %config%
popd
goto Exit
:LaunchOfficeSetup
rem Prep
set "fastcopy_args=/cmd=diff /no_ui /auto_close"
set "product=%L_PATH%\%L_ITEM%"
set "product_name=%L_ITEM%"
call :GetBasename product_name || goto ErrorBasename
set "source=\\%OFFICE_SERVER_IP%\Office\%product%"
set "dest=%client_dir%\Office"
rem Verify
if not exist "%source%" (goto ErrorOfficeSourceNotFound)
rem Copy
echo Copying setup file(s) for %product_name%...
start "" /wait "%FASTCOPY%" %fastcopy_args% "%source%" /to="%dest%\"
rem Run
if exist "%dest%\%product_name%\setup.exe" (
start "" "%dest%\%product_name%\setup.exe" || goto ErrorUnknown
) else if "%product_name:~-3,3%" == "exe" (
start "" "%dest%\%product_name%" || goto ErrorUnknown
) else if "%product_name:~-3,3%" == "msi" (
start "" "%dest%\%product_name%" || goto ErrorUnknown
) else (
rem Office source not supported by this script
goto ErrorOfficeUnsupported
)
goto Exit
:LaunchPSScript
rem Prep
call :ExtractOrFindPath || goto ErrorProgramNotFound
set "script=%_path%\%L_ITEM%"
set "ps_args=-ExecutionPolicy Bypass -NoProfile"
rem Verify
if not exist "%script%" goto ErrorScriptNotFound
rem Run
popd && pushd "%_path%"
if defined L_ELEV (
goto LaunchPSScriptElev
) else (
goto LaunchPSScriptUser
)
:LaunchPSScriptElev
rem Prep
call :DeQuote script
rem Create VB script
mkdir "%bin%\tmp" 2>nul
echo Set UAC = CreateObject^("Shell.Application"^) > "%bin%\tmp\Elevate.vbs"
if defined L_NCMD (
rem use Powershell's window instead of %CON%
echo UAC.ShellExecute "%POWERSHELL%", "%ps_args% -File "%script%"", "", "runas", 3 >> "%bin%\tmp\Elevate.vbs"
) else (
echo UAC.ShellExecute "%CON%", "-run %POWERSHELL% %ps_args% -File "^"%script%^"" -new_console:n", "", "runas", 1 >> "%bin%\tmp\Elevate.vbs"
)
rem Run
"%systemroot%\System32\cscript.exe" //nologo "%bin%\tmp\Elevate.vbs" || goto ErrorUnknown
goto Exit
:LaunchPSScriptUser
rem Run
if defined L_NCMD (
start "" "%POWERSHELL%" %ps_args% -File "%script%" || goto ErrorUnknown
) else (
start "" "%CON%" -run "%POWERSHELL%" %ps_args% -File "%script%" -new_console:n || goto ErrorUnknown
)
goto Exit
:LaunchPyScript
rem Prep
call :ExtractOrFindPath || goto ErrorProgramNotFound
set "script=%_path%\%L_ITEM%"
rem Verify
"%PYTHON%" --version >nul || goto ErrorPythonUnsupported
if not exist "%script%" goto ErrorScriptNotFound
rem Run
if defined L_ELEV (
goto LaunchPyScriptElev
) else (
goto LaunchPyScriptUser
)
:LaunchPyScriptElev
rem Prep
call :DeQuote script
rem Create VB script
mkdir "%bin%\tmp" 2>nul
echo Set UAC = CreateObject^("Shell.Application"^) > "%bin%\tmp\Elevate.vbs"
if defined L_NCMD (
echo UAC.ShellExecute "%PYTHON%", """%script%"" %L_ARGS%", "", "runas", 3 >> "%bin%\tmp\Elevate.vbs"
) else (
echo UAC.ShellExecute "%CON%", "-run ""%PYTHON%"" ""%script%"" %L_ARGS% -new_console:n", "", "runas", 1 >> "%bin%\tmp\Elevate.vbs"
)
rem Run
"%systemroot%\System32\cscript.exe" //nologo "%bin%\tmp\Elevate.vbs" || goto ErrorUnknown
goto Exit
:LaunchPyScriptUser
if defined L_NCMD (
start "" "%PYTHON%" "%script%" %L_ARGS% || goto ErrorUnknown
) else (
start "" "%CON%" -run "%PYTHON%" "%script%" %L_ARGS% -new_console:n || goto ErrorUnknown
)
goto Exit
:LaunchQuickBooksSetup
rem Prep
call "%bin%\Scripts\init_client_dir.cmd" /QuickBooks
set "fastcopy_args=/cmd=diff /no_ui /auto_close"
set "product=%L_PATH%\%L_ITEM%"
set "product_name=%L_ITEM%"
call :GetBasename product_name || goto ErrorBasename
set "source=\\%QUICKBOOKS_SERVER_IP%\QuickBooks\%product%"
set "dest=%client_dir%\QuickBooks"
rem Verify
if not exist "%source%" (goto ErrorQuickBooksSourceNotFound)
rem Copy
echo Copying setup file(s) for %L_ITEM%...
start "" /wait "%FASTCOPY%" %fastcopy_args% "%source%" /to="%dest%\"
rem Run
if exist "%dest%\%product_name%\Setup.exe" (
pushd "%dest%\%product_name%"
start "" "%dest%\%product_name%\Setup.exe" || goto ErrorUnknown
popd
) else (
rem QuickBooks source not supported by this script
goto ErrorQuickBooksUnsupported
)
goto Exit
:Usage
echo.
echo.Usage (via defined variables):
echo. L_TYPE L_PATH L_ITEM L_ARGS
echo. Executable Working Dir Program Args [L_7ZIP] [L_ELEV] [L__CLI]
echo. Folder Folder '.' [L_7ZIP]
echo. Office Year Product [L_7ZIP]
echo. PSScript Scripts Script [L_7ZIP] [L_ELEV] [L_NCMD]
echo. PyScript Scripts Script Args [L_7ZIP] [L_ELEV] [L_NCMD]
echo. QuickBooks Year Product [L_7ZIP]
echo.
echo.L_7ZIP: Extra arguments for 7-Zip (in the :ExtractCBin label)
echo.L_ELEV: Elevate to run as Admin
echo.L_NCMD: Do not run script inside ConEmu (i.e. use the native window)
echo.L__CLI: Run executable in ConEmu
echo.
goto Abort
:: Functions ::
:DeQuote
rem Code taken from http://ss64.com/nt/syntax-dequote.html
if not defined %1 (@exit /b 1)
for /f "delims=" %%a in ('echo %%%1%%') do set %1=%%~a
@exit /b 0
:ExtractCBin
rem Extract %cbin% archive into %bin%
echo Extracting "%L_PATH%"...
set "source=%cbin%\%L_PATH%.7z"
set "dest=%bin%\%L_PATH%"
set "args=-aos -bso0 -bse0 -bsp0 -p%ARCHIVE_PASSWORD%"
if defined DEBUG (set "args=-aos -p%ARCHIVE_PASSWORD%")
"%SEVEN_ZIP%" x "%source%" %args% -o"%dest%" %L_7ZIP% || exit /b 1
ping.exe -n 2 127.0.0.1>nul
exit /b 0
:FindBin
rem Checks the current directory and all parents for the ".bin" folder
rem NOTE: Has not been tested for UNC paths
set bin=
pushd "%~dp0"
:FindBinInner
if exist ".bin" (goto FindBinDone)
if "%~d0\" == "%cd%" (popd & @exit /b 1)
cd ..
goto FindBinInner
:FindBinDone
set "bin=%cd%\.bin"
set "cbin=%cd%\.cbin"
popd
@exit /b 0
:GetBasename
rem Loop over passed variable to remove all text left of the last '\' character
rem NOTE: This function should be called as 'call :GetBasename VarName || goto ErrorBasename' to catch variables that become empty.
for /f "delims=" %%a in ('echo %%%1%%') do (set "_tmp=%%~a")
:GetBasenameInner
set "_tmp=%_tmp:*\=%"
if not defined _tmp (@exit /b 1)
if not "%_tmp%" == "%_tmp:*\=%" (goto GetBasenameInner)
:GetBasenameDone
set "%1=%_tmp%"
@exit /b 0
:ExtractOrFindPath
rem Test L_PATH in the following order:
rem 1: %cbin%\L_PATH.7z (which will be extracted to %bin%\L_PATH)
rem 2: %bin%\L_PATH
rem 3. %L_PATH% (i.e. treat L_PATH as an absolute path)
rem NOTE: This function should be called as 'call :ExtractOrFindPath || goto ErrorProgramNotFound' to catch invalid paths.
set _path=
if exist "%cbin%\%L_PATH%.7z" (
call :ExtractCBin
) else if exist "%cbin%\%L_PATH%\%L_ITEM:~0,-4%.7z" (
call :ExtractCBin
)
if exist "%bin%\%L_PATH%" (set "_path=%bin%\%L_PATH%")
if not defined _path (set "_path=%L_PATH%")
rem Raise error if path is still not available
if not exist "%_path%" (exit /b 1)
exit /b 0
:: Errors ::
:ErrorBasename
echo.
echo ERROR: GetBasename resulted in an empty variable.
goto Abort
:ErrorNoBin
echo.
echo ERROR: ".bin" folder not found.
goto Abort
:ErrorODTSourceNotFound
echo.
echo ERROR: Office Deployment Tool source not found.
goto Abort
:ErrorOfficeSourceNotFound
echo.
echo ERROR: Office source "%L_ITEM%" not found.
goto Abort
:ErrorOfficeUnsupported
rem Source is not an executable nor is a folder with a setup.exe file inside. Open explorer to local setup file(s) instead.
echo.
echo ERROR: Office version not supported by this script.
start "" "explorer.exe" "%client_dir%\Office"
goto Abort
:ErrorPythonUnsupported
rem The Windows installation lacks Windows update KB2999226 needed to run Python
echo.
echo ERROR: Failed to run Python, try installing Windows update KB2999226.
echo NOTE: That update is from October 2015 so this system is SEVERELY outdated
if exist "%bin%\..\Installers\Extras\Windows Updates" (
start "" "explorer.exe" "%bin%\..\Installers\Extras\Windows Updates"
)
goto Abort
:ErrorQuickBooksSourceNotFound
echo.
echo ERROR: QuickBooks source "%L_ITEM%" not found.
goto Abort
:ErrorQuickBooksUnsupported
rem Source is not an executable nor is a folder with a setup.exe file inside. Open explorer to local setup file(s) instead.
echo.
echo ERROR: QuickBooks version not supported by this script.
start "" "explorer.exe" "%client_dir%\QuickBooks"
goto Abort
:ErrorProgramNotFound
echo.
echo ERROR: Program "%prog%" not found.
goto Abort
:ErrorScriptNotFound
echo.
echo ERROR: Script "%script%" not found.
goto Abort
:ErrorUnknown
echo.
echo ERROR: Unknown error encountered.
goto Abort
:Abort
rem Handle color theme for both the native console and ConEmu
if defined ConEmuBuild (
color c4
) else (
color 4e
)
echo Aborted.
echo.
echo DETAILS: L_TYPE: %L_TYPE%
echo. L_PATH: %L_PATH%
echo. L_ITEM: %L_ITEM%
echo. L_ARGS: %L_ARGS%
echo. L_7ZIP: %L_7ZIP%
echo. L_ELEV: %L_ELEV%
echo. L_NCMD: %L_NCMD%
echo. L__CLI: %L__CLI%
echo. CON: %CON%
echo. DEBUG: %DEBUG%
echo. PYTHON: %PYTHON%
echo Press any key to exit...
pause>nul
rem reset color and reset errorlevel to 0
rem NOTE: This is done to avoid causing a ErrorLaunchCMD in the launcher.cmd
color 07
goto Exit
:: Cleanup and exit ::
:Exit
popd
endlocal
exit /b %errorlevel%

View file

@ -1,113 +0,0 @@
:: WizardKit: Launcher Script ::
::
:: This script works by setting env variables and then calling Launch.cmd
:: which inherits the variables. This bypasses batch file argument parsing
:: which is awful.
@echo off
:Init
setlocal EnableDelayedExpansion
title WizardKit: Launcher
call :CheckFlags %*
call :FindBin
call :SetTitle Launcher
:Optional
:: This section is for any work that needs done before launching L_ITEM
rem EXTRA_CODE
:DefineLaunch
:: See %bin%\Scripts\Launch.cmd for details under :Usage label
set L_TYPE=
set L_PATH=
set L_ITEM=
set L_ARGS=
set L__CLI=
set L_7ZIP=
set L_ELEV=
set L_NCMD=
:::::::::::::::::::::::::::::::::::::::::::
:: Do not edit anything below this line! ::
:::::::::::::::::::::::::::::::::::::::::::
:LaunchPrep
rem Verifies the environment before launching item
if not defined bin (goto ErrorNoBin)
if not exist "%bin%\Scripts\Launch.cmd" (goto ErrorLaunchCMDMissing)
:Launch
rem Calls the Launch.cmd script using the variables defined above
call "%bin%\Scripts\Launch.cmd" || goto ErrorLaunchCMD
goto Exit
:: Functions ::
: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
:FindBin
rem Checks the current directory and all parents for the ".bin" folder
rem NOTE: Has not been tested for UNC paths
set bin=
pushd "%~dp0"
:FindBinInner
if exist ".bin" (goto FindBinDone)
if "%~d0\" == "%cd%" (popd & @exit /b 1)
cd ..
goto FindBinInner
:FindBinDone
set "bin=%cd%\.bin"
set "cbin=%cd%\.cbin"
popd
@exit /b 0
:SetTitle
rem Sets title using KIT_NAME_FULL from wk\cfg\main.py
set "SETTINGS=%bin%\Scripts\wk\cfg\main.py"
for /f "tokens=* usebackq" %%f in (`findstr KIT_NAME_FULL "%SETTINGS%"`) do (
set "_v=%%f"
set "_v=!_v:*'=!"
set "KIT_NAME_FULL=!_v:~0,-1!"
)
set "window_title=%*"
if not defined window_title set "window_title=Launcher"
set "window_title=%KIT_NAME_FULL%: %window_title%"
title %window_title%
@exit /b 0
:: Errors ::
:ErrorLaunchCMD
echo.
echo ERROR: Launch.cmd did not run correctly. Try using the /DEBUG flag?
goto Abort
:ErrorLaunchCMDMissing
echo.
echo ERROR: Launch.cmd script not found.
goto Abort
:ErrorNoBin
echo.
echo ERROR: ".bin" folder not found.
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%

View file

@ -1,2 +0,0 @@
# WizardKit: Scripts #

View file

@ -1,37 +0,0 @@
#!/bin/bash
#
## WizardKit: Apple fan speed tool
SMCPATH="/sys/devices/platform/applesmc.768"
SET_MAX="True"
function usage {
echo "Usage: $(basename "$0") auto|max"
echo " e.g. $(basename "$0") max"
}
# Set mode
case $1 in
auto)
SET_MAX="False";;
max)
SET_MAX="True";;
*)
usage
exit 1;;
esac
if [[ -e "$SMCPATH" ]]; then
if [[ "$SET_MAX" == "True" ]]; then
# Set fans to max RPM
for fan in $SMCPATH/fan*max; do
echo '1' | sudo tee ${fan:0:-4}_manual > /dev/null
cat $fan | sudo tee ${fan:0:-4}_output > /dev/null
done
else
# Set fans to auto
for fan in $SMCPATH/fan*manual; do
echo '0' | sudo tee $fan > /dev/null
done
fi
fi

View file

@ -1,100 +0,0 @@
"""WizardKit: Auto Repair Tool"""
# vim: sts=2 sw=2 ts=2
from typing import Any
import wk
# Classes
REBOOT_STR = wk.ui.ansi.color_string('Reboot', 'YELLOW')
class MenuEntry():
"""Simple class to allow cleaner code below."""
def __init__(
self,
name: str,
function: str | None = None,
selected: bool = True,
**kwargs):
self.name: str = name
self.details: dict[str, Any] = {
'Function': function,
'Selected': selected,
**kwargs,
}
# STATIC VARIABLES
BASE_MENUS = {
'Groups': {
'Backup Settings': (
MenuEntry('Enable RegBack', 'auto_enable_regback'),
MenuEntry('Enable System Restore', 'auto_system_restore_enable'),
MenuEntry('Set System Restore Size', 'auto_system_restore_set_size'),
MenuEntry('Create System Restore', 'auto_system_restore_create'),
MenuEntry('Backup Browsers', 'auto_backup_browser_profiles'),
MenuEntry('Backup Power Plans', 'auto_backup_power_plans'),
MenuEntry('Reset Power Plans', 'auto_reset_power_plans'),
MenuEntry('Set Custom Power Plan', 'auto_set_custom_power_plan'),
MenuEntry('Backup Registry', 'auto_backup_registry'),
),
'Windows Repairs': (
MenuEntry('Disable Windows Updates', 'auto_windows_updates_disable'),
MenuEntry('Reset Windows Updates', 'auto_windows_updates_reset'),
MenuEntry(REBOOT_STR, 'auto_reboot'),
MenuEntry('CHKDSK', 'auto_chkdsk'),
MenuEntry('DISM RestoreHealth', 'auto_dism'),
MenuEntry('SFC Scan', 'auto_sfc'),
MenuEntry('Clear Proxy Settings', 'auto_reset_proxy'),
MenuEntry('Disable Pending Renames', 'auto_disable_pending_renames'),
MenuEntry('Registry Repairs', 'auto_repair_registry'),
MenuEntry('Reset UAC', 'auto_restore_uac_defaults'),
MenuEntry('Reset Windows Policies', 'auto_reset_windows_policies'),
),
'Malware Cleanup': (
MenuEntry('BleachBit', 'auto_bleachbit'),
MenuEntry('HitmanPro', 'auto_hitmanpro'),
MenuEntry('KVRT', 'auto_kvrt'),
MenuEntry('Windows Defender', 'auto_microsoft_defender'),
MenuEntry('Remove Custom Power Plan', 'auto_remove_power_plan'),
MenuEntry(REBOOT_STR, 'auto_reboot'),
),
'Manual Steps': (
MenuEntry('AdwCleaner', 'auto_adwcleaner'),
MenuEntry('Bulk Crap Uninstaller', 'auto_bcuninstaller'),
MenuEntry('Enable Windows Updates', 'auto_windows_updates_enable'),
),
},
'Options': (
MenuEntry('Kill Explorer', selected=False),
MenuEntry('Run AVRemover (once)'),
MenuEntry('Run RKill'),
MenuEntry('Sync Clock'),
MenuEntry('Use Autologon', selected=False),
),
'Actions': (
MenuEntry('Load Preset'),
MenuEntry('Options'),
MenuEntry('Start', Separator=True),
MenuEntry('Quit'),
),
}
PRESETS = {
'Default': { # Will be expanded at runtime using BASE_MENUS
'Options': (
'Run RKill',
'Sync Clock',
),
},
'Custom': {}, # Will remain empty at runtime
}
if __name__ == '__main__':
try:
wk.repairs.win.run_auto_repairs(BASE_MENUS, PRESETS)
except KeyboardInterrupt:
wk.ui.cli.abort()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,175 +0,0 @@
"""WizardKit: Auto System Setup Tool"""
# vim: sts=2 sw=2 ts=2
from typing import Any
import wk
# Classes
class MenuEntry():
"""Simple class to allow cleaner code below."""
def __init__(
self,
name: str,
function: str | None = None,
selected: bool = True,
**kwargs):
self.name: str = name
self.details: dict[str, Any] = {
'Function': function,
'Selected': selected,
**kwargs,
}
# STATIC VARIABLES
BASE_MENUS = {
'Groups': {
'Backup Settings': (
MenuEntry('Backup Browsers', 'auto_backup_browser_profiles'),
MenuEntry('Backup Power Plans', 'auto_backup_power_plans'),
MenuEntry('Reset Power Plans', 'auto_reset_power_plans'),
MenuEntry('Set Custom Power Plan', 'auto_set_custom_power_plan'),
),
'Install Software': (
MenuEntry('Winget', 'auto_install_winget'),
MenuEntry('Firefox', 'auto_install_firefox'),
MenuEntry('LibreOffice', 'auto_install_libreoffice', selected=False),
MenuEntry('Open Shell', 'auto_install_open_shell'),
MenuEntry('Software Bundle', 'auto_install_software_bundle'),
MenuEntry('Software Upgrades', 'auto_install_software_upgrades'),
MenuEntry('Visual C++ Runtimes', 'auto_install_vcredists'),
),
'Configure System': (
MenuEntry('Open Shell', 'auto_config_open_shell'),
MenuEntry('Disable Password Expiration', 'auto_disable_password_expiration'),
MenuEntry('Enable BSoD MiniDumps', 'auto_enable_bsod_minidumps'),
MenuEntry('Enable RegBack', 'auto_enable_regback'),
MenuEntry('Enable System Restore', 'auto_system_restore_enable'),
MenuEntry('Set System Restore Size', 'auto_system_restore_set_size'),
MenuEntry('Enable Windows Updates', 'auto_windows_updates_enable'),
MenuEntry('Windows Activation', 'auto_activate_windows'),
MenuEntry('Windows Explorer', 'auto_config_explorer'),
MenuEntry(r'Windows\Temp Fix', 'auto_windows_temp_fix'),
MenuEntry('Configure Browsers', 'auto_config_browsers'),
MenuEntry('Create System Restore', 'auto_system_restore_create'),
),
'System Information': (
MenuEntry('AIDA64 Report', 'auto_export_aida64_report'),
MenuEntry('Backup Registry', 'auto_backup_registry'),
),
'System Summary': (
MenuEntry('Operating System', 'auto_show_os_name'),
MenuEntry('Windows Activation', 'auto_show_os_activation'),
MenuEntry('Secure Boot', 'auto_show_secure_boot_status'),
MenuEntry('Installed RAM', 'auto_show_installed_ram'),
MenuEntry('Storage Status', 'auto_show_storage_status'),
MenuEntry('Virus Protection', 'auto_show_installed_antivirus'),
MenuEntry('Partitions 4K Aligned', 'auto_show_4k_alignment_check'),
),
'Run Programs': (
MenuEntry('Device Manager', 'auto_open_device_manager'),
MenuEntry('HWiNFO Sensors', 'auto_open_hwinfo_sensors'),
MenuEntry('Microsoft Store Updates', 'auto_open_microsoft_store_updates'),
MenuEntry('Snappy Driver Installer', 'auto_open_snappy_driver_installer_origin'),
MenuEntry('Windows Activation', 'auto_open_windows_activation'),
MenuEntry('Windows Updates', 'auto_open_windows_updates'),
MenuEntry('XMPlay', 'auto_open_xmplay'),
),
},
'Actions': (
MenuEntry('Load Preset'),
MenuEntry('Start', Separator=True),
MenuEntry('Quit'),
),
}
PRESETS = {
'Default': {}, # Will be built at runtime using BASE_MENUS
'Additional User': {
'Configure System': (
'Configure Browsers',
'Open Shell',
'uBlock Origin',
'Enable BSoD MiniDumps',
'Enable RegBack',
'Enable System Restore',
'Set System Restore Size',
'Enable Windows Updates',
'Windows Explorer',
),
'Install Software': (
'Firefox', # Needed to handle profile upgrade nonsense
),
'Run Programs': (
'Microsoft Store Updates',
),
'System Summary': (
'Operating System',
'Windows Activation',
'Secure Boot',
'Installed RAM',
'Storage Status',
'Virus Protection',
'Partitions 4K Aligned',
),
},
'Hardware': {
'Configure System': (
'Enable BSoD MiniDumps',
'Enable RegBack',
'Enable System Restore',
'Set System Restore Size',
'Enable Windows Updates',
),
'System Information': (
'Backup Registry',
),
'System Summary': (
'Operating System',
'Windows Activation',
'Secure Boot',
'Installed RAM',
'Storage Status',
'Virus Protection',
'Partitions 4K Aligned',
),
'Run Programs': (
'Device Manager',
'HWiNFO Sensors',
'XMPlay',
),
},
'Verify': {
'Configure System': (
'Enable BSoD MiniDumps',
'Enable RegBack',
'Enable System Restore',
'Set System Restore Size',
'Enable Windows Updates',
'Windows Explorer',
),
'System Summary': (
'Operating System',
'Windows Activation',
'Secure Boot',
'Installed RAM',
'Storage Status',
'Virus Protection',
'Installed Office',
'Partitions 4K Aligned',
),
},
'Custom': {}, # Will remain empty at runtime
}
if __name__ == '__main__':
try:
wk.setup.win.run_auto_setup(BASE_MENUS, PRESETS)
except KeyboardInterrupt:
wk.ui.cli.abort()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,14 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Build UFD Tool"""
# vim: sts=2 sw=2 ts=2
import wk
if __name__ == '__main__':
try:
wk.kit.ufd.build_ufd()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,15 +0,0 @@
"""WizardKit: Build Kit (Windows)."""
# vim: sts=2 sw=2 ts=2
import wk
if __name__ == '__main__':
try:
wk.kit.build.build_kit()
except KeyboardInterrupt:
wk.ui.cli.abort()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,13 +0,0 @@
# WizardKit: Check Antivirus
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "WizardKit: Check Antivirus"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-CimInstance -Namespace "root\SecurityCenter2" -ClassName AntivirusProduct | select displayName,productState | ConvertTo-Json

View file

@ -1,13 +0,0 @@
# WizardKit: Check Partition Alignment
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "WizardKit: Check Partition Alignment"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-CimInstance -Query "Select * from Win32_DiskPartition" | select Name,Size,StartingOffset | ConvertTo-Json

View file

@ -1,29 +0,0 @@
#!/bin/bash
#
## WizardKit: ddrescue TUI Launcher
__OS_NAME="$(uname -s)"
if [[ "$__OS_NAME" == "Darwin" ]]; then
__OS_NAME="macOS"
fi
__NOTICE="This script is not fully supported under $__OS_NAME!
Limitations:
Map files are saved to a RAM disk so you can't resume after a restart.
Only whole devices are supported.
Press Enter to continue..."
# Check if running under Linux
if [[ "$__OS_NAME" != "Linux" ]]; then
echo "${__NOTICE}"
read -r _dontcare
fi
source launch-in-tmux
SESSION_NAME="ddrescue-tui"
WINDOW_NAME="ddrescue TUI"
TMUX_CMD="ddrescue-tui.py"
launch_in_tmux "$@"

View file

@ -1,14 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: ddrescue TUI"""
# vim: sts=2 sw=2 ts=2
import wk
if __name__ == '__main__':
try:
wk.clone.ddrescue.main()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,13 +0,0 @@
# WizardKit: Disable Password Expiration (Local Accounts)
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "Disable Password Expiration"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# Main
Get-LocalUser | Set-LocalUser -PasswordNeverExpires $true

View file

@ -1,12 +0,0 @@
#!/bin/bash
#
## WizardKit: "echo" text to screen and "hold" by waiting for user input
function usage {
echo "Usage: $(basename "$0") \"text\""
echo " e.g. $(basename "$0") \"Some text to show\""
}
echo -en "$@" && read -r __dont_care
exit 0

View file

@ -1,24 +0,0 @@
"""WizardKit: Embedded Python helper.
This saves the keystrokes needed to fix the path and import wk. To use:
python.exe -i embedded_python_env.py
"""
# vim: sts=2 sw=2 ts=2
import pickle
import wk
# Functions
def load_state():
with open('debug/state.pickle', 'rb') as f:
return pickle.load(f)
# Main
wk.ui.cli.print_colored(
(wk.cfg.main.KIT_NAME_FULL, ': ', 'Debug Console'),
('GREEN', None, 'YELLOW'),
sep='',
)
print('')

View file

@ -1,6 +0,0 @@
"""WizardKit: Export Bitlocker Tool"""
# vim: sts=2 sw=2 ts=2
import wk
wk.os.win.export_bitlocker_info()

View file

@ -1,3 +0,0 @@
# WizardKit: Get RAW disks
Get-Disk | Where-Object {$_.PartitionStyle -eq "RAW"} | Select FriendlyName,Size,PartitionStyle | ConvertTo-JSON

View file

@ -1,11 +0,0 @@
#!/bin/bash
#
## WizardKit: HW Diagnostics Launcher
source launch-in-tmux
SESSION_NAME="hw-diags"
WINDOW_NAME="Hardware Diagnostics"
TMUX_CMD="hw-diags.py"
launch_in_tmux "$@"

View file

@ -1,14 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Hardware Diagnostics"""
# vim: sts=2 sw=2 ts=2
import wk
if __name__ == '__main__':
try:
wk.hw.diags.main()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,49 +0,0 @@
#!/bin/bash
#
BLUE='\033[34m'
CLEAR='\033[0m'
IFS=$'\n'
# Check if running under Linux
os_name="$(uname -s)"
if [[ "$os_name" == "Darwin" ]]; then
os_name="macOS"
fi
if [[ "$os_name" != "Linux" ]]; then
echo "This script is not supported under $os_name." 1>&2
exit 1
fi
# List devices
for line in $(lsblk -do NAME,TRAN,SIZE,VENDOR,MODEL,SERIAL); do
if [[ "${line:0:4}" == "NAME" ]]; then
echo -e "${BLUE}${line}${CLEAR}"
else
echo "${line}"
fi
done
echo ""
# List loopback devices
if [[ "$(losetup -l | wc -l)" > 0 ]]; then
for line in $(losetup -lO NAME,PARTSCAN,RO,BACK-FILE); do
if [[ "${line:0:4}" == "NAME" ]]; then
echo -e "${BLUE}${line}${CLEAR}"
else
echo "${line}" | sed -r 's#/dev/(loop[0-9]+)#\1 #'
fi
done
echo ""
fi
# List partitions
for line in $(lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT); do
if [[ "${line:0:4}" == "NAME" ]]; then
echo -e "${BLUE}${line}${CLEAR}"
else
echo "${line}"
fi
done
echo ""

View file

@ -1,117 +0,0 @@
#!/bin/bash
#
# COLORS
CLEAR="\e[0m"
RED="\e[31m"
GREEN="\e[32m"
YELLOW="\e[33m"
BLUE="\e[34m"
function print_in_columns() {
string="$1"
label="$(echo "$string" | sed -r 's/^\s*(.*:).*/\1/')"
value="$(echo "$string" | sed -r 's/^\s*.*:\s*(.*)/\1/')"
printf ' %-18s%s\n' "$label" "$value"
}
function print_dmi_value() {
name="$1"
file="/sys/devices/virtual/dmi/id/$2"
value="UNKNOWN"
if [[ -e "$file" ]]; then
value="$(cat "$file")"
fi
print_in_columns "$name: $value"
}
# Check if running under Linux
os_name="$(uname -s)"
if [[ "$os_name" == "Darwin" ]]; then
os_name="macOS"
fi
if [[ "$os_name" != "Linux" ]]; then
echo "This script is not supported under $os_name." 1>&2
exit 1
fi
# System
echo -e "${BLUE}System Information${CLEAR}"
print_dmi_value "Vendor" "sys_vendor"
print_dmi_value "Name" "product_name"
print_dmi_value "Serial" "product_serial"
echo ""
# Motherboard
echo -e "${BLUE}Motherboard${CLEAR}"
print_dmi_value "Vendor" "board_vendor"
print_dmi_value "Name" "board_name"
print_dmi_value "Version" "board_version"
print_dmi_value "Serial" "board_serial"
echo ""
# BIOS
echo -e "${BLUE}BIOS${CLEAR}"
print_dmi_value "Vendor" "bios_vendor"
print_dmi_value "Version" "bios_version"
print_dmi_value "Release Date" "bios_date"
echo ""
# Processor
echo -e "${BLUE}Processor${CLEAR}"
lscpu | grep -E '^(Arch|CPU.s.|Core|Thread|Model name|Virt)' \
| sed -r 's/\(s\)(.*:)/s\1 /' \
| sed -r 's/CPUs: /Threads:/' \
| sed -r 's/^(.*:) / \1/'
echo ""
# Memory
echo -e "${BLUE}Memory${CLEAR}"
first_device="True"
while read -r line; do
if [[ "$line" == "Memory Device" ]]; then
if [[ "$first_device" == "True" ]]; then
first_device="False"
else
# Add space between devices
echo ""
fi
else
print_in_columns "$line"
fi
done <<< $(sudo dmidecode -t memory \
| grep -E '^(Memory Device|\s+(Type|Size|Speed|Manuf.*|Locator|Part Number):)')
echo ""
# Graphics
echo -e "${BLUE}Graphics${CLEAR}"
lspci | grep 'VGA' | sed -r 's/^.*:/ Device: /' \
| sed 's/Intel Corporation/Intel/' \
| sed 's/Generation Core Processor Family/Gen/' \
| sed 's/Integrated Graphics Controller.*/iGPU/'
glxinfo 2>/dev/null | grep 'OpenGL renderer' | sed -r 's/^.*:/ OpenGL Renderer: /' \
| sed 's/Mesa DRI //'
echo ""
# Audio
echo -e "${BLUE}Audio${CLEAR}"
while read -r line; do
if [[ "$line" = .*no.soundcards.found.* ]]; then
echo " No soundcards found"
else
print_in_columns "$line"
fi
done <<< $(aplay -l 2>&1 | grep -Ei '(^card|no soundcards found)' | sed -r 's/.*\[(.*)\].*\[(.*)\].*/\1: \2/')
echo ""
# Network
echo -e "${BLUE}Network${CLEAR}"
lspci | grep -Ei '(ethernet|network|wireless|wifi)' \
| sed -r 's/.*: (.*)$/ \1/'
echo ""
# Drives
echo -e "${BLUE}Drives${CLEAR}"
hw-drive-info | sed 's/^/ /'
echo ""

View file

@ -1,46 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Hardware Sensors"""
# vim: sts=2 sw=2 ts=2
import platform
import wk
def main() -> None:
"""Show sensor data on screen."""
sensors = wk.hw.sensors.Sensors()
if platform.system() == 'Darwin':
wk.ui.cli.clear_screen()
while True:
print('\033[100A', end='')
sensors.update_sensor_data()
wk.ui.cli.print_report(sensors.generate_report('Current', 'Max'))
wk.std.sleep(1)
elif platform.system() == 'Linux':
proc = wk.exe.run_program(cmd=['mktemp'])
sensors.start_background_monitor(
out_path=proc.stdout.strip(),
exit_on_thermal_limit=False,
temp_labels=('Current', 'Max'),
)
watch_cmd = [
'watch',
'--color',
'--exec',
'--no-title',
'--interval', '1',
'cat',
proc.stdout.strip(),
]
wk.exe.run_program(watch_cmd, check=False, pipe=False)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,80 +0,0 @@
:: WizardKit: Create client_dir folder(s)
@echo off
if defined DEBUG (@echo on)
:SafetyCheck
if not defined bin (goto Abort)
: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%
:SetVars
set "SETTINGS=%bin%\Scripts\wk\cfg\main.py"
for /f "tokens=* usebackq" %%f in (`findstr KIT_NAME_SHORT "%SETTINGS%"`) do (
set "_v=%%f"
set "_v=!_v:*'=!"
set "KIT_NAME_SHORT=!_v:~0,-1!"
)
set "client_dir=%systemdrive%\%KIT_NAME_SHORT%"
set "log_dir=%client_dir%\Logs\%iso_date%"
:Flags
set _backups=
set _info=
set _office=
set _quarantine=
set _quickbooks=
set _transfer=
for %%f in (%*) do (
if /i "%%f" == "/DEBUG" (@echo on)
if /i "%%f" == "/Backups" set _backups=True
if /i "%%f" == "/Logs" set _logs=True
if /i "%%f" == "/Office" set _office=True
if /i "%%f" == "/Quarantine" set _quarantine=True
if /i "%%f" == "/QuickBooks" set _quickbooks=True
if /i "%%f" == "/Transfer" set _transfer=True
)
:CreateDirs
if defined _backups mkdir "%client_dir%\Backups">nul 2>&1
if defined _logs (
mkdir "%log_dir%\%KIT_NAME_FULL%">nul 2>&1
mkdir "%log_dir%\Tools">nul 2>&1)
if defined _office mkdir "%client_dir%\Office">nul 2>&1
if defined _quarantine mkdir "%client_dir%\Quarantine">nul 2>&1
if defined _quickbooks mkdir "%client_dir%\QuickBooks">nul 2>&1
if defined _transfer mkdir "%client_dir%\Transfer_%iso_date%">nul 2>&1
goto Done
: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
:Done
goto Exit
:Exit

View file

@ -1,37 +0,0 @@
# WizardKit: Install winget (if needed)
#Requires -Version 3.0
if (Test-Path Env:\DEBUG) {
Set-PSDebug -Trace 1
}
$Host.UI.RawUI.WindowTitle = "WizardKit: Winget installer"
$Host.UI.RawUI.BackgroundColor = "black"
$Host.UI.RawUI.ForegroundColor = "white"
$ProgressPreference = "SilentlyContinue"
# STATIC VARIABLES
$EXIT_OK = 0
$EXIT_INSTALLED = 1
$EXIT_FAILED_TO_INSTALL = 2
# Main
$NeedsInstalled = $false
try {
$_ = $(winget --version)
}
catch {
$NeedsInstalled = $true
}
# Install
if (! $NeedsInstalled) {
exit $EXIT_INSTALLED
}
try {
Add-AppxPackage -ErrorAction Stop -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe
}
catch {
exit $EXIT_FAILED_TO_INSTALL
}
exit $EXIT_OK

View file

@ -1,7 +0,0 @@
#!/bin/bash
#
## Monitor journal log for data recovery related events
echo -e 'Monitoring journal output...\n'
journalctl -kf \
| grep -Ei --color=always 'ata|nvme|scsi|sd[a..z]+|usb|comreset|critical|error'

View file

@ -1,74 +0,0 @@
#!/bin/bash
#
## WizardKit: TMUX Launcher
# Live macOS env workaround
tmux_args=()
if [[ -e "/.wk-live-macos" ]]; then
tmux_args=(-f "/etc/tmux.conf" -S "/Volumes/RAM_Disk/.tmux.socket")
fi
function ask() {
while :; do
read -p "$1 [Y/N] " -r answer
if echo "$answer" | grep -Eiq '^(y|yes|sure)$'; then
return 0
elif echo "$answer" | grep -Eiq '^(n|no|nope)$'; then
return 1
fi
done
}
function err () {
echo "$0:" "$@" >&2
return 1
}
function launch_in_tmux() {
# Check for required vars
[[ -n "${SESSION_NAME:-}" ]] || return $(err "Required variable missing (SESSION_NAME)")
[[ -n "${WINDOW_NAME:-}" ]] || return $(err "Required variable missing (WINDOW_NAME)")
[[ -n "${TMUX_CMD:-}" ]] || return $(err "Required variable missing (TMUX_CMD)")
# Check for running session
if tmux "${tmux_args[@]}" list-session 2>&1 | grep -q "$SESSION_NAME"; then
echo "WARNING: tmux session $SESSION_NAME already exists."
echo ""
if ask "Connect to current session?"; then
if [[ -n "${TMUX:-}" ]]; then
# Running inside TMUX, switch to session
tmux "${tmux_args[@]}" switch-client -t "$SESSION_NAME"
if ! jobs %% >/dev/null 2>&1; then
# No running jobs, try exiting abandoned tmux session
exit 0
fi
else
# Running outside TMUX, attach to session
tmux "${tmux_args[@]}" attach-session -t "$SESSION_NAME"
fi
return 0
elif ask "Kill current session and start new session?"; then
tmux "${tmux_args[@]}" kill-session -t "$SESSION_NAME" || \
die "Failed to kill session: $SESSION_NAME"
else
echo "Aborted."
return 1
fi
fi
# Start session
if [[ -n "${TMUX:-}" ]]; then
# Running inside TMUX, save current session/window names
ORIGINAL_SESSION_NAME="$(tmux "${tmux_args[@]}" display-message -p '#S')"
ORIGINAL_WINDOW_NAME="$(tmux "${tmux_args[@]}" display-message -p '#W')"
tmux "${tmux_args[@]}" rename-session "$SESSION_NAME"
tmux "${tmux_args[@]}" rename-window "$WINDOW_NAME"
"$TMUX_CMD" "$@"
# Restore previous session/window names
tmux "${tmux_args[@]}" rename-session "${ORIGINAL_SESSION_NAME}"
tmux "${tmux_args[@]}" rename-window "${ORIGINAL_WINDOW_NAME}"
else
# Running outside TMUX, start/attach to session
tmux "${tmux_args[@]}" new-session -s "$SESSION_NAME" -n "$WINDOW_NAME" "$TMUX_CMD" "$@"
fi
}

View file

@ -1,99 +0,0 @@
"""WizardKit: Launch Snappy Driver Installer Origin"""
# vim: sts=2 sw=2 ts=2
from subprocess import CompletedProcess
import wk
from wk.cfg.net import SDIO_SERVER
# STATIC VARIABLES
MOUNT_EXCEPTIONS = (
RuntimeError,
wk.exe.subprocess.CalledProcessError,
)
SDIO_LOCAL_PATH = wk.kit.tools.get_tool_path("SDIO", "SDIO")
SDIO_REMOTE_PATH = wk.io.get_path_obj(
(
fr'\\{SDIO_SERVER["Address"]}\{SDIO_SERVER["Share"]}\{SDIO_SERVER["Path"]}'
fr'\SDIO{"64" if wk.os.win.ARCH == "64" else ""}.exe'
),
resolve=False,
)
# Functions
def try_again() -> bool:
"""Ask to try again or quit."""
if wk.ui.cli.ask(' Try again?'):
return True
if not wk.ui.cli.ask(' Use local version?'):
wk.ui.cli.abort()
return False
def use_network_sdio() -> bool:
"""Try to mount SDIO server."""
use_network = False
def _mount_server() -> CompletedProcess:
print('Connecting to server... (Press CTRL+c to use local copy)')
return wk.net.mount_network_share(SDIO_SERVER, read_write=False)
# Bail early
if not SDIO_SERVER['Address']:
return use_network
# Main loop
while True:
try:
proc = _mount_server()
except KeyboardInterrupt:
break
except MOUNT_EXCEPTIONS as err:
wk.ui.cli.print_error(f' {err}')
if not try_again():
break
else:
if proc.returncode == 0:
# Network copy available
use_network = True
break
# Failed to mount
wk.ui.cli.print_error(' Failed to mount server')
if not try_again():
break
# Done
return use_network
if __name__ == '__main__':
wk.ui.cli.set_title(
f'{wk.cfg.main.KIT_NAME_FULL}: Snappy Driver Installer Origin Launcher',
)
log_dir = wk.log.format_log_path(tool=True).parent
USE_NETWORK = False
# Windows 11 workaround
if wk.os.win.OS_VERSION == 11:
appid_services = ['appid', 'appidsvc', 'applockerfltr']
for svc in appid_services:
wk.os.win.stop_service(svc)
if any([wk.os.win.get_service_status(s) != 'stopped' for s in appid_services]):
raise wk.std.GenericWarning('Failed to stop AppID services')
# Try to mount server
try:
USE_NETWORK = use_network_sdio()
except KeyboardInterrupt:
wk.ui.cli.abort()
# Run SDIO
EXE_PATH = SDIO_LOCAL_PATH
if USE_NETWORK:
EXE_PATH = SDIO_REMOTE_PATH
print('Using network copy!')
else:
print('Using local copy!')
cmd = [EXE_PATH, '-log_dir', log_dir]
wk.exe.run_program(cmd, check=False, cwd=EXE_PATH.parent)

View file

@ -1,67 +0,0 @@
#!/bin/env python3
#
import json
import re
import subprocess
from typing import Any
CPU_REGEX = re.compile(r'(core|k\d+)temp', re.IGNORECASE)
NON_TEMP_REGEX = re.compile(r'^(fan|in|curr)', re.IGNORECASE)
def get_data() -> dict[Any, Any]:
cmd = ('sensors', '-j')
data = {}
raw_data = []
try:
proc = subprocess.run(
args=cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf-8',
check=True,
)
except subprocess.CalledProcessError:
return data
for line in proc.stdout.splitlines():
if line.strip() == ',':
# Assuming malformatted line caused by missing data
continue
raw_data.append(line)
try:
data = json.loads('\n'.join(raw_data))
except json.JSONDecodeError:
# Still broken, just return the empty dict
pass
return data
def get_max_temp(data) -> str:
cpu_temps = []
max_cpu_temp = '??° C'
for adapter, sources in data.items():
if not CPU_REGEX.search(adapter):
continue
sources.pop('Adapter', None)
for labels in sources.values():
for label, temp in sorted(labels.items()):
if 'input' not in label or NON_TEMP_REGEX.search(label):
continue
cpu_temps.append(temp)
# Format data
if cpu_temps:
max_cpu_temp = int(max(cpu_temps))
max_cpu_temp = f'{max_cpu_temp:02d}° C'
# Done
return max_cpu_temp
if __name__ == '__main__':
sensor_data = get_data()
print(get_max_temp(sensor_data))

View file

@ -1,41 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Mount all volumes"""
# vim: sts=2 sw=2 ts=2
import sys
import wk
# Functions
def main() -> None:
"""Mount all volumes and show results."""
wk.ui.cli.print_standard(f'{wk.cfg.main.KIT_NAME_FULL}: Volume mount tool')
wk.ui.cli.print_standard(' ')
# Mount volumes and get report
wk.ui.cli.print_standard('Mounting volumes...')
wk.os.linux.mount_volumes()
report = wk.os.linux.build_volume_report()
# Show results
wk.ui.cli.print_info('Results')
wk.ui.cli.print_report(report)
# GUI mode
if 'gui' in sys.argv:
wk.ui.cli.pause('Press Enter to exit...')
wk.exe.popen_program(['nohup', 'thunar', '/media'])
if __name__ == '__main__':
if wk.std.PLATFORM != 'Linux':
os_name = wk.std.PLATFORM.replace('Darwin', 'macOS')
wk.ui.cli.print_error(f'This script is not supported under {os_name}.')
wk.ui.cli.abort()
try:
main()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,29 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Mount Backup Shares"""
# vim: sts=2 sw=2 ts=2
import wk
# Functions
def main() -> None:
"""Attempt to mount backup shares and print report."""
wk.ui.cli.print_info('Mounting Backup Shares')
report = wk.net.mount_backup_shares()
for line in report:
color = 'GREEN'
line = f' {line}'
if 'Failed' in line:
color = 'RED'
elif 'Already' in line:
color = 'YELLOW'
print(wk.ansi.color_string(line, color))
if __name__ == '__main__':
try:
main()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,32 +0,0 @@
#!/bin/bash
#
## WizardKit: RAW image mounting tool
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
LOOPDEV="$(losetup -f)"
function usage {
echo "Usage: $(basename "$0") [image]"
echo " e.g. $(basename "$0") HDD.dd"
}
if [[ -f "${1:-}" ]]; then
sudo losetup -P "${LOOPDEV}" "${1:-}"
sleep 1
if [[ -b "${LOOPDEV}p1" ]]; then
# losetup detected partitions
for dev in "${LOOPDEV}p"*; do
udevil mount -o ro "${dev}" || true
done
else
# losetup did not detect partitions, attempt whole image
udevil mount -o ro "${LOOPDEV}" || true
fi
else
usage
exit 1
fi

View file

@ -1,79 +0,0 @@
#!/bin/python3
#
## WizardKit: MS Word content search tool
import os
import re
import sys
import wk
# STATIC VARIABLES
SCANDIR = os.getcwd()
USAGE = '''Usage: {script} <search-terms>...
e.g. {script} "Book Title" "Keyword" "etc"
This script will search all doc/docx files below the current directory for
the search-terms provided (case-insensitive).'''.format(script=__file__)
REGEX_DOC_FILES = re.compile(r'\.docx?$', re.IGNORECASE)
def scan_for_docs(path):
for entry in os.scandir(path):
if entry.is_dir(follow_symlinks=False):
yield from scan_for_docs(entry.path)
elif entry.is_file and REGEX_DOC_FILES.search(entry.name):
yield entry
def scan_file(file_path, search):
match = False
try:
if entry.name.lower().endswith('.docx'):
result = wk.exe.run_program(['unzip', '-p', entry.path])
else:
# Assuming .doc
result = wk.exe.run_program(['antiword', entry.path])
out = result.stdout.decode()
match = re.search(search, out, re.IGNORECASE)
except Exception:
# Ignore errors since files may be corrupted
pass
return entry.path if match else None
if __name__ == '__main__':
try:
# Prep
wk.ui.cli.clear_screen()
terms = [re.sub(r'\s+', r'\s*', t) for t in sys.argv[1:]]
search = '({})'.format('|'.join(terms))
if len(sys.argv) == 1:
# Print usage
wk.ui.cli.print_standard(USAGE)
else:
matches = []
for entry in scan_for_docs(SCANDIR):
matches.append(scan_file(entry.path, search))
# Strip None values (i.e. non-matching entries)
matches = [m for m in matches if m]
if matches:
wk.ui.cli.print_success('Found {} {}:'.format(
len(matches),
'Matches' if len(matches) > 1 else 'Match'))
for match in matches:
wk.ui.cli.print_standard(match)
else:
wk.ui.cli.print_error('No matches found.')
# Done
wk.ui.cli.print_standard('\nDone.')
#pause("Press Enter to exit...")
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -1,10 +0,0 @@
#!/bin/env bash
#
## Enable numlock if no battery is detected
## Credit: https://wiki.archlinux.org/title/Activating_numlock_on_bootup#With_systemd_service
if ! compgen -G "/sys/class/power_supply/BAT*" >/dev/null; then
for tty in /dev/tty{1..6}; do
/usr/bin/setleds -D +num < "$tty"
done
fi

View file

@ -1,18 +0,0 @@
#!/bin/bash
#
## WizardKit: Update pacman settings to usage in live sessions
# Disable custom repo (used at build-time)
sudo sed -i -r "s/^(\[custom\])/#\1/" /etc/pacman.conf
sudo sed -i -r "s/^(SigLevel = Optional TrustAll)/#\1/" /etc/pacman.conf
sudo sed -i -r "s/^(Server = )/#\1/" /etc/pacman.conf
# Disable signature checks
sudo sed -i -r "s/^SigLevel.*/SigLevel = Never/" /etc/pacman.conf
# Init Pacman keyring
sudo systemctl start pacman-init.service
# Refresh package databases and install packages (if provided)
sudo pacman -Sy "$@"

View file

@ -1,19 +0,0 @@
[tool.ruff.per-file-ignores]
# Init files
"wk/__init__.py" = ["F401"]
"wk/cfg/__init__.py" = ["F401"]
"wk/clone/__init__.py" = ["F401"]
"wk/hw/__init__.py" = ["F401"]
"wk/kit/__init__.py" = ["F401"]
"wk/os/__init__.py" = ["F401"]
"wk/repairs/__init__.py" = ["F401"]
"wk/setup/__init__.py" = ["F401"]
"wk/ui/__init__.py" = ["F401"]
# Long lines
"wk/borrowed/acpi.py" = ["E501", "F841"]
"wk/cfg/ddrescue.py" = ["E501"]
"wk/cfg/hw.py" = ["E501"]
"wk/cfg/launchers.py" = ["E501"]
"wk/cfg/setup.py" = ["E501"]
"wk/cfg/sources.py" = ["E501"]

View file

@ -1,21 +0,0 @@
#!/bin/bash
#
## WizardKit: Volume remount tool
if ! mount | grep -q "$1"; then
echo "ERROR: Can't remount $1"
sleep 2s
exit 1
fi
DEVICE=$(mount | grep "$1" | cut -d' ' -f1)
# Remount read-write
echo "Remounting: $DEVICE"
udevil umount $DEVICE
if udevil mount $DEVICE; then
echo "Done"
else
echo "Failed"
fi
exit 0

View file

@ -1,33 +0,0 @@
#!/bin/bash
#
# Magic numbers:
## Width: | 20 | term_x | 20 | 180 (conky) | 20 |
## Height: | 24 | 10 (titlebar) | term_y | 24 | 30 (Tint2) |
## X Offset: 20 - 5 (shadow?)
## Y Offset: 24 - 5 (shadow?)
conky_width=180
gap_x=20
gap_y=24
picom_shadow=5
tint2_height=30
titlebar_height=10
source ~/.screen_data
if [[ "${dpi}" -ge 192 ]]; then
conky_width=360
gap_x=40
gap_y=48
picom_shadow=5
tint2_height=60
titlebar_height=20
fi
offset_x=$(echo "$gap_x - $picom_shadow" | bc)
offset_y=$(echo "$gap_y - $picom_shadow" | bc)
term_width="$(echo "$width_px - ($gap_x * 3) - $conky_width" | bc)"
term_height="$(echo "$height_px - ($gap_y * 2) - $titlebar_height - $tint2_height" | bc)"
sleep 0.1s
wmctrl -r :ACTIVE: -e "0,$offset_x,$offset_y,$term_width,$term_height" && "$@"

View file

@ -1,4 +0,0 @@
#!/bin/bash
#
wmctrl -r:ACTIVE: -b toggle,maximized_vert,maximized_horz && "$@"

View file

@ -1,27 +0,0 @@
#!/usr/bin/env python3
"""WizardKit: Unmount Backup Shares"""
# vim: sts=2 sw=2 ts=2
import wk
# Functions
def main() -> None:
"""Attempt to mount backup shares and print report."""
wk.ui.cli.print_info('Unmounting Backup Shares')
report = wk.net.unmount_backup_shares()
for line in report:
color = 'GREEN'
line = f' {line}'
if 'Not mounted' in line:
color = 'YELLOW'
print(wk.ui.ansi.color_string(line, color))
if __name__ == '__main__':
try:
main()
except SystemExit:
raise
except: # noqa: E722
wk.ui.cli.major_exception()

View file

@ -1,89 +0,0 @@
#!/usr/bin/env python3
# vim: sts=2 sw=2 ts=2
"""WizardKit: Upload Logs"""
import datetime
import os
import pathlib
import pytz
import requests
import wk
# STATIC VARIABLES
LOG_DIR = pathlib.Path('~/Logs').expanduser().resolve()
PLATFORM = wk.std.PLATFORM.replace('Darwin', 'macOS')
TIMEZONE = pytz.timezone(wk.cfg.main.LINUX_TIME_ZONE)
NOW = datetime.datetime.now(tz=TIMEZONE)
# Safety check
if PLATFORM not in ('macOS', 'Linux'):
raise OSError(f'This script is not supported under {PLATFORM}')
# Functions
def main() -> None:
"""Upload logs for review."""
lines = []
try_and_print = wk.ui.cli.TryAndPrint()
# Set log
wk.log.update_log_path(dest_name='Upload-Logs', timestamp=True)
# Instructions
wk.ui.cli.print_success(f'{wk.cfg.main.KIT_NAME_FULL}: Upload Logs')
wk.ui.cli.print_standard('')
wk.ui.cli.print_standard('Please state the reason for the review.')
wk.ui.cli.print_info(' End note with an empty line.')
wk.ui.cli.print_standard('')
# Get reason note
while True:
text = wk.ui.cli.input_text('> ')
if not text:
lines.append('')
break
lines.append(text)
with open(f'{LOG_DIR}/__reason__.txt', 'a') as _f:
_f.write('\n'.join(lines))
# Compress and upload logs
result = try_and_print.run(
message='Uploading logs...',
function=upload_log_dir,
reason='Review',
)
if not result['Failed']:
raise SystemExit(1)
def upload_log_dir(reason='Testing') -> None:
"""Upload compressed log_dir to the crash server."""
server = wk.cfg.net.CRASH_SERVER
dest = pathlib.Path(f'~/{reason}_{NOW.strftime("%Y-%m-%dT%H%M%S%z")}.txz')
dest = dest.expanduser().resolve()
# Compress LOG_DIR (relative to parent dir)
os.chdir(LOG_DIR.parent)
cmd = ['tar', 'caf', dest.name, LOG_DIR.name]
wk.exe.run_program(cmd, check=False)
# Upload compressed data
url = f'{server["Url"]}/{dest.name}'
result = requests.put(
url,
data=dest.read_bytes(),
headers=server['Headers'],
auth=(server['User'], server['Pass']),
)
# Check result
if not result.ok:
raise wk.std.GenericError('Failed to upload logs')
if __name__ == '__main__':
main()

View file

@ -1,11 +0,0 @@
#!/bin/zsh
#
## watch-like utility
WATCH_FILE="${1}"
while :; do
echo -n "\e[100A"
cat "${WATCH_FILE}"
sleep 1s
done

View file

@ -1,5 +0,0 @@
#!/bin/bash
#
## WizardKit: Debug Launcher
python3 -i /usr/local/bin/wk_debug.py

View file

@ -1,52 +0,0 @@
#!/bin/bash
#
## Wizard Kit: Wrapper for logout, reboot, & poweroff
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
# Functions
function linux_power_cmd() {
case "${1:-x}" in
poweroff)
sudo systemctl poweroff;;
reboot)
sudo systemctl reboot;;
*)
openbox --exit;;
esac
}
function macos_power_cmd() {
case "${1:-x}" in
poweroff)
shutdown -h now;;
reboot)
shutdown -r now;;
*)
exit;;
esac
}
# "Main"
if [[ -e "/.wk-live-macos" ]]; then
# Flush write cache
sync
# Perform requested action
macos_power_cmd "${1:-x}"
else
# Unmount filesystems
find /media -maxdepth 1 -mindepth 1 -type d \
-exec udevil umount "{}" \;
# Flush write cache
sudo sync
# Perform requested action
linux_power_cmd "${1:-x}"
fi
exit 0

View file

@ -1,39 +0,0 @@
"""WizardKit: wk module init"""
# vim: sts=2 sw=2 ts=2
from sys import stderr, version_info
from . import cfg
from . import clone
from . import debug
from . import exe
from . import graph
from . import hw
from . import io
from . import kit
from . import log
from . import net
from . import os
from . import repairs
from . import setup
from . import std
from . import ui
# Check env
if version_info < (3, 10):
# Unsupported
raise RuntimeError(
'This package is unsupported on Python '
f'{version_info.major}.{version_info.minor}'
)
# Init
try:
log.start()
except UserWarning as err:
print(err, file=stderr)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,57 +0,0 @@
import sys
# Code borrowed from https://github.com/aeruder/get_win8key
if sys.platform.startswith('win32'):
import ctypes
import ctypes.wintypes
def EnumAcpiTables():
#returns a list of the names of the ACPI tables on this system
FirmwareTableProviderSignature=ctypes.wintypes.DWORD(1094930505)
pFirmwareTableBuffer=ctypes.create_string_buffer(0)
BufferSize=ctypes.wintypes.DWORD(0)
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms724259
EnumSystemFirmwareTables=ctypes.WinDLL("Kernel32").EnumSystemFirmwareTables
ret=EnumSystemFirmwareTables(FirmwareTableProviderSignature, pFirmwareTableBuffer, BufferSize)
pFirmwareTableBuffer=None
pFirmwareTableBuffer=ctypes.create_string_buffer(ret)
BufferSize.value=ret
ret2=EnumSystemFirmwareTables(FirmwareTableProviderSignature, pFirmwareTableBuffer, BufferSize)
return [pFirmwareTableBuffer.value[i:i+4] for i in range(0, len(pFirmwareTableBuffer.value), 4)]
def GetAcpiTable(table):
#returns raw contents of ACPI table
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms724379x
tableID = 0
for b in reversed(table):
tableID = (tableID << 8) + b
GetSystemFirmwareTable=ctypes.WinDLL("Kernel32").GetSystemFirmwareTable
FirmwareTableProviderSignature=ctypes.wintypes.DWORD(1094930505)
FirmwareTableID=ctypes.wintypes.DWORD(int(tableID))
pFirmwareTableBuffer=ctypes.create_string_buffer(0)
BufferSize=ctypes.wintypes.DWORD(0)
ret = GetSystemFirmwareTable(FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize)
pFirmwareTableBuffer=None
pFirmwareTableBuffer=ctypes.create_string_buffer(ret)
BufferSize.value=ret
ret2 = GetSystemFirmwareTable(FirmwareTableProviderSignature, FirmwareTableID, pFirmwareTableBuffer, BufferSize)
return pFirmwareTableBuffer.raw
elif sys.platform.startswith('linux'):
import os
TABLE_ROOT = b'/sys/firmware/acpi/tables'
def EnumAcpiTables():
return os.listdir(TABLE_ROOT)
def GetAcpiTable(table):
with open(os.path.join(TABLE_ROOT, table), 'rb') as o:
return o.read()
else:
raise NotImplementedError('acpi support only implemented for linux and win32')
def FindAcpiTable(table):
#checks if specific ACPI table exists and returns True/False
tables = EnumAcpiTables()
if table in tables:
return True
else:
return False

View file

@ -1,14 +0,0 @@
"""WizardKit: cfg module init"""
from . import ddrescue
from . import hw
from . import launchers
from . import log
from . import main
from . import music
from . import net
from . import repairs
from . import setup
from . import sources
from . import ufd
from . import windows_builds

View file

@ -1,76 +0,0 @@
"""WizardKit: Config - ddrescue"""
# vim: sts=2 sw=2 ts=2
# Layout
TMUX_SIDE_WIDTH = 21
TMUX_LAYOUT = {
'Source': {'height': 2, 'Check': True},
'Started': {'width': TMUX_SIDE_WIDTH, 'Check': True},
'Progress': {'width': TMUX_SIDE_WIDTH, 'Check': True},
}
# ddrescue
AUTO_PASS_THRESHOLDS = {
# NOTE: The scrape key is set to infinity to force a break
'read-skip': 50,
'read-full': 95,
'trim': 98,
'scrape': float('inf'),
}
DDRESCUE_MAP_TEMPLATE = '''# Mapfile. Created by {name}
0x0 ? 1
0x0 {size:#x} ?
'''
DDRESCUE_SETTINGS = {
'Default': {
'--binary-prefixes': {'Selected': True, 'Hidden': True, },
'--complete-only': {'Selected': True, 'Hidden': True, },
'--data-preview': {'Selected': True, 'Value': '5', 'Hidden': True, },
'--idirect': {'Selected': True, },
'--odirect': {'Selected': True, },
'--input-position': {'Selected': False, 'Value': '0', },
'--max-error-rate': {'Selected': True, 'Value': '100MiB', },
'--max-read-rate': {'Selected': False, 'Value': '1MiB', },
'--min-read-rate': {'Selected': True, 'Value': '64KiB', },
'--reopen-on-error': {'Selected': False, },
'--retry-passes': {'Selected': True, 'Value': '0', },
'--reverse': {'Selected': False, },
'--skip-size': {'Selected': True, 'Value': '0.001,0.02', }, # Percentages of source size
'--test-mode': {'Selected': False, },
'--timeout': {'Selected': True, 'Value': '30m', },
'-vvvv': {'Selected': True, 'Hidden': True, },
},
'Fast': {
'--max-error-rate': {'Selected': True, 'Value': '32MiB', },
'--min-read-rate': {'Selected': True, 'Value': '1MiB', },
'--timeout': {'Selected': True, 'Value': '5m', },
},
'Safe': {
'--max-read-rate': {'Selected': True, 'Value': '64MiB', },
'--min-read-rate': {'Selected': True, 'Value': '1KiB', },
'--timeout': {'Selected': False, 'Value': '30m', },
},
}
DDRESCUE_SPECIFIC_PASS_SETTINGS = {
'read-skip': ['--no-scrape', '--no-trim', '--cpass=1,2'],
'read-full': ['--no-scrape', '--no-trim'],
'trim': ['--no-scrape'],
}
DRIVE_POWEROFF_TIMEOUT = 90
PARTITION_TYPES = {
'GPT': {
'NTFS': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7', # Basic Data Partition
'VFAT': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7', # Basic Data Partition
'EXFAT': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7', # Basic Data Partition
},
'MBR': {
'EXFAT': '7',
'NTFS': '7',
'VFAT': 'b',
},
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,173 +0,0 @@
"""WizardKit: Config - Hardware"""
# vim: sts=2 sw=2 ts=2
import re
# STATIC VARIABLES
ATTRIBUTE_COLORS = (
# NOTE: Ordered by ascending importance
('Warning', 'YELLOW'),
('Error', 'RED'),
('Maximum', 'PURPLE'),
)
# NOTE: Force 4K read block size for disks >= 3TB
BADBLOCKS_EXTRA_LARGE_DISK = 15 * 1024**4
BADBLOCKS_LARGE_DISK = 3 * 1024**4
BADBLOCKS_REGEX = re.compile(
r'^Pass completed, (\d+) bad blocks found. .(\d+)/(\d+)/(\d+) errors',
re.IGNORECASE,
)
BADBLOCKS_RESULTS_REGEX = re.compile(r'^(.*?)\x08.*\x08(.*)')
BADBLOCKS_SKIP_REGEX = re.compile(r'^(Checking|\[)', re.IGNORECASE)
CPU_TEMPS = {
'Cooling Delta': 25,
'Cooling Low Cutoff': 50,
'Critical': 100,
'Idle Delta': 25,
'Idle High': 70,
}
CPU_TEST_MINUTES = 7
IO_GRAPH_WIDTH = 40
IO_ALT_TEST_SIZE_FACTOR = 0.01
IO_BLOCK_SIZE = 512 * 1024
IO_CHUNK_SIZE = 32 * 1024**2
IO_MINIMUM_TEST_SIZE = 10 * 1024**3
IO_RATE_REGEX = re.compile(
r'(?P<bytes>\d+) bytes.* (?P<seconds>\S+) s(?:,|ecs )',
)
KEY_NVME = 'nvme_smart_health_information_log'
KEY_SMART = 'ata_smart_attributes'
KNOWN_DISK_ATTRIBUTES = {
# NVMe
'critical_warning': {'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
'media_errors': {'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
'power_on_hours': {'Blocking': False, 'Warning': 17532, 'Error': 26298, 'Maximum': 100000,},
'unsafe_shutdowns': {'Blocking': False, 'Warning': 1, 'Error': None, 'Maximum': None, },
# SMART
5: {'Hex': '05', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
9: {'Hex': '09', 'Blocking': False, 'Warning': 17532, 'Error': 26298, 'Maximum': 100000,},
10: {'Hex': '10', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
184: {'Hex': 'B8', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
187: {'Hex': 'BB', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
188: {'Hex': 'BC', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
196: {'Hex': 'C4', 'Blocking': False, 'Warning': 1, 'Error': 10, 'Maximum': 10000, },
197: {'Hex': 'C5', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
198: {'Hex': 'C6', 'Blocking': True, 'Warning': None, 'Error': 1, 'Maximum': None, },
199: {'Hex': 'C7', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': None, },
201: {'Hex': 'C9', 'Blocking': False, 'Warning': None, 'Error': 1, 'Maximum': 10000, },
}
KNOWN_DISK_MODELS = {
# model_regex: model_attributes
r'CT(250|500|1000|2000)MX500SSD(1|4)': {
197: {'Warning': 1, 'Error': 2, 'Note': '(MX500 thresholds)',},
},
r'MZ(7|N)LN(128|256|512|1T0)HA(HQ|JQ|LR)-000H(1|7)': {
# Source: https://www.smartmontools.org/ticket/920
201: {'Error': 99, 'PercentageLife': True, 'Note': '(PM871b thresholds)'},
},
}
KNOWN_RAM_VENDOR_IDS = {
# https://github.com/hewigovens/hewigovens.github.com/wiki/Memory-vendor-code
'0x014F': 'Transcend',
'0x2C00': 'Micron',
'0x802C': 'Micron',
'0x80AD': 'Hynix',
'0x80CE': 'Samsung',
'0xAD00': 'Hynix',
'0xCE00': 'Samsung',
}
NVME_WARNING_KEYS = (
'spare_below_threshold',
'reliability_degraded',
'volatile_memory_backup_failed',
)
REGEX_POWER_ON_TIME = re.compile(
r'^(\d+)([Hh].*|\s+\(\d+\s+\d+\s+\d+\).*)'
)
SMART_SELF_TEST_START_TIMEOUT_IN_SECONDS = 120
SMC_IDS = {
# Sources: https://github.com/beltex/SMCKit/blob/master/SMCKit/SMC.swift
# http://www.opensource.apple.com/source/net_snmp/
# https://github.com/jedda/OSX-Monitoring-Tools
'TA0P': {'CPU Temp': False, 'Source': 'Ambient'},
'TA0S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 Ambient'},
'TA1P': {'CPU Temp': False, 'Source': 'Ambient'},
'TA1S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 PCB'},
'TA2S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 Ambient'},
'TA3S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 PCB'},
'TC0C': {'CPU Temp': True, 'Source': 'CPU Core 1'},
'TC0D': {'CPU Temp': True, 'Source': 'CPU Diode'},
'TC0H': {'CPU Temp': True, 'Source': 'CPU Heatsink'},
'TC0P': {'CPU Temp': True, 'Source': 'CPU Proximity'},
'TC1C': {'CPU Temp': True, 'Source': 'CPU Core 2'},
'TC1P': {'CPU Temp': True, 'Source': 'CPU Proximity 2'},
'TC2C': {'CPU Temp': True, 'Source': 'CPU Core 3'},
'TC2P': {'CPU Temp': True, 'Source': 'CPU Proximity 3'},
'TC3C': {'CPU Temp': True, 'Source': 'CPU Core 4'},
'TC3P': {'CPU Temp': True, 'Source': 'CPU Proximity 4'},
'TCAC': {'CPU Temp': True, 'Source': 'CPU core from PCECI'},
'TCAH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
'TCBC': {'CPU Temp': True, 'Source': 'CPU B core from PCECI'},
'TCBH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
'Te1P': {'CPU Temp': False, 'Source': 'PCIE Ambient'},
'Te1S': {'CPU Temp': False, 'Source': 'PCIE slot 1'},
'Te2S': {'CPU Temp': False, 'Source': 'PCIE slot 2'},
'Te3S': {'CPU Temp': False, 'Source': 'PCIE slot 3'},
'Te4S': {'CPU Temp': False, 'Source': 'PCIE slot 4'},
'TG0C': {'CPU Temp': False, 'Source': 'Mezzanine GPU Core'},
'TG0P': {'CPU Temp': False, 'Source': 'Mezzanine GPU Exhaust'},
'TH0P': {'CPU Temp': False, 'Source': 'Drive Bay 0'},
'TH1P': {'CPU Temp': False, 'Source': 'Drive Bay 1'},
'TH2P': {'CPU Temp': False, 'Source': 'Drive Bay 2'},
'TH3P': {'CPU Temp': False, 'Source': 'Drive Bay 3'},
'TH4P': {'CPU Temp': False, 'Source': 'Drive Bay 4'},
'TM0P': {'CPU Temp': False, 'Source': 'CPU DIMM Exit Ambient'},
'Tp0C': {'CPU Temp': False, 'Source': 'PSU1 Inlet Ambient'},
'Tp0P': {'CPU Temp': False, 'Source': 'PSU1 Inlet Ambient'},
'Tp1C': {'CPU Temp': False, 'Source': 'PSU1 Secondary Component'},
'Tp1P': {'CPU Temp': False, 'Source': 'PSU1 Primary Component'},
'Tp2P': {'CPU Temp': False, 'Source': 'PSU1 Secondary Component'},
'Tp3P': {'CPU Temp': False, 'Source': 'PSU2 Inlet Ambient'},
'Tp4P': {'CPU Temp': False, 'Source': 'PSU2 Primary Component'},
'Tp5P': {'CPU Temp': False, 'Source': 'PSU2 Secondary Component'},
'TS0C': {'CPU Temp': False, 'Source': 'CPU B DIMM Exit Ambient'},
}
STATUS_COLORS = {
'Passed': 'GREEN',
'Aborted': 'YELLOW',
'N/A': 'YELLOW',
'Skipped': 'YELLOW',
'Unknown': 'YELLOW',
'Working': 'YELLOW',
'Denied': 'RED',
'ERROR': 'RED',
'Failed': 'RED',
'TimedOut': 'RED',
}
TEMP_COLORS = {
float('-inf'): 'CYAN',
00: 'BLUE',
60: 'GREEN',
70: 'YELLOW',
80: 'ORANGE',
90: 'RED',
100: 'ORANGE_RED',
}
TESTSTATION_FILE = '/run/archiso/bootmnt/teststation.name'
TEST_MODE_BADBLOCKS_LIMIT = '10000' # Last block to read
TEST_MODE_CPU_LIMIT = 0.25 # Number of minutes to test
# THRESHOLDS: Rates used to determine HDD/SSD pass/fail
THRESH_HDD_MIN = 50 * 1024**2
THRESH_HDD_AVG_HIGH = 75 * 1024**2
THRESH_HDD_AVG_LOW = 65 * 1024**2
THRESH_SSD_MIN = 90 * 1024**2
THRESH_SSD_AVG_HIGH = 135 * 1024**2
THRESH_SSD_AVG_LOW = 100 * 1024**2
# VOLUME THRESHOLDS in percent
VOLUME_WARNING_THRESHOLD = 70
VOLUME_FAILURE_THRESHOLD = 85
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,287 +0,0 @@
"""WizardKit: Config - Launchers (Windows)"""
# vim: sts=2 sw=2 ts=2
LAUNCHERS = {
r'': { # Root Dir
'0) Export BitLocker': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
'L_ITEM': 'export_bitlocker.py',
'L_ELEV': 'True',
},
'1) Auto Repairs': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
'L_ITEM': 'auto_repairs.py',
'L_ELEV': 'True',
},
'2) Store & Windows Updates': {
'L_TYPE': 'Executable',
'L_PATH': r'%SystemRoot%\System32',
'L_ITEM': 'control.exe',
'L_ARGS': 'update',
'Extra Code': ['explorer ms-windows-store:updates'],
},
'3) Snappy Driver Installer Origin': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
'L_ITEM': 'launch_sdio.py',
'L_ELEV': 'True',
},
'4) Auto Setup': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
'L_ITEM': 'auto_setup.py',
'L_ELEV': 'True',
},
},
r'Tools': {
'AIDA64': {
'L_TYPE': 'Executable',
'L_PATH': 'AIDA64',
'L_ITEM': 'aida64.exe',
},
'Autoruns (with VirusTotal Scan)': {
'L_TYPE': 'Executable',
'L_PATH': 'Sysinternals',
'L_ITEM': 'Autoruns.exe',
'L_ARGS': '-e',
'Extra Code': [
r'reg add HKCU\Software\Sysinternals\AutoRuns /v checkvirustotal /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v EulaAccepted /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v shownomicrosoft /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v shownowindows /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v showonlyvirustotal /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v submitvirustotal /t REG_DWORD /d 0 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns /v verifysignatures /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns\SigCheck /v EulaAccepted /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns\Streams /v EulaAccepted /t REG_DWORD /d 1 /f >nul',
r'reg add HKCU\Software\Sysinternals\AutoRuns\VirusTotal /v VirusTotalTermsAccepted /t REG_DWORD /d 1 /f >nul',
],
},
'BleachBit': {
'L_TYPE': 'Executable',
'L_PATH': 'BleachBit',
'L_ITEM': 'bleachbit.exe',
},
'BlueScreenView': {
'L_TYPE': 'Executable',
'L_PATH': 'BlueScreenView',
'L_ITEM': 'BlueScreenView.exe',
},
'BCUninstaller': {
'L_TYPE': 'Executable',
'L_PATH': 'BCUninstaller',
'L_ITEM': 'BCUninstaller.exe',
'L_ELEV': 'True',
},
'ConEmu (as ADMIN)': {
'L_TYPE': 'Executable',
'L_PATH': 'ConEmu',
'L_ITEM': 'ConEmu.exe',
'L_ELEV': 'True',
},
'ConEmu': {
'L_TYPE': 'Executable',
'L_PATH': 'ConEmu',
'L_ITEM': 'ConEmu.exe',
},
'Debug Console (Command Prompt)': {
'L_TYPE': 'Executable',
'L_PATH': 'ConEmu',
'L_ITEM': 'ConEmu.exe',
'L_ARGS': r'-Dir %bin%\Scripts',
'L_ELEV': 'True',
},
'Debug Console (Python)': {
'L_TYPE': 'Executable',
'L_PATH': 'ConEmu',
'L_ITEM': 'ConEmu.exe',
'L_ARGS': r'-Dir %bin%\Scripts -Run ..\Python\x%ARCH%\python.exe -i embedded_python_env.py',
'L_ELEV': 'True',
'Extra Code': [
'set ARCH=32',
'if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "ARCH=64"',
],
},
'Device Cleanup': {
'L_TYPE': 'Executable',
'L_PATH': 'DeviceCleanup',
'L_ITEM': 'DeviceCleanup.exe',
'L_ELEV': 'True',
},
'Display Driver Uninstaller': {
'L_TYPE': 'Executable',
'L_PATH': 'DDU',
'L_ITEM': 'Display Driver Uninstaller.exe',
'L_ELEV': 'True',
},
'ERUNT': {
'L_TYPE': 'Executable',
'L_PATH': 'erunt',
'L_ITEM': 'ERUNT.EXE',
'L_ARGS': r'%client_dir%\Backups\Registry\%iso_date% sysreg curuser otherusers',
'L_ELEV': 'True',
'Extra Code': [
r'call "%bin%\Scripts\init_client_dir.cmd" /Logs',
],
},
'Everything': {
'L_TYPE': 'Executable',
'L_PATH': 'Everything',
'L_ITEM': 'Everything.exe',
'L_ARGS': '-nodb',
'L_ELEV': 'True',
},
'FastCopy (as ADMIN)': {
'L_TYPE': 'Executable',
'L_PATH': 'FastCopy',
'L_ITEM': 'FastCopy.exe',
'L_ARGS': (
r' /logfile=%log_dir%\Tools\FastCopy.log'
r' /acl'
r' /cmd=noexist_only'
r' /skip_empty_dir'
r' /linkdest'
r' /exclude='
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'
r' /to=%client_dir%\Transfer_%iso_date%\ '
),
'L_ELEV': 'True',
'Extra Code': [
r'call "%bin%\Scripts\init_client_dir.cmd" /Logs /Transfer',
],
},
'FastCopy': {
'L_TYPE': 'Executable',
'L_PATH': 'FastCopy',
'L_ITEM': 'FastCopy.exe',
'L_ARGS': (
r' /logfile=%log_dir%\Tools\FastCopy.log'
r' /acl'
r' /cmd=noexist_only'
r' /skip_empty_dir'
r' /linkdest'
r' /exclude='
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'
r' /to=%client_dir%\Transfer_%iso_date%\ '
),
'Extra Code': [
r'call "%bin%\Scripts\init_client_dir.cmd" /Logs /Transfer',
],
},
'FurMark': {
'L_TYPE': 'Executable',
'L_PATH': 'FurMark',
'L_ITEM': 'FurMark.exe',
},
'HWiNFO': {
'L_TYPE': 'Executable',
'L_PATH': 'HWiNFO',
'L_ITEM': 'HWiNFO.exe',
'Extra Code': [
r'for %%a in (32 64) do (',
r' copy /y "%bin%\HWiNFO\general.ini" "%bin%\HWiNFO\HWiNFO%%a.ini"',
r' (echo SensorsOnly=0)>>"%bin%\HWiNFO\HWiNFO%%a.ini"',
r' (echo SummaryOnly=0)>>"%bin%\HWiNFO\HWiNFO%%a.ini"',
r')',
],
},
'HWiNFO (Sensors)': {
'L_TYPE': 'Executable',
'L_PATH': 'HWiNFO',
'L_ITEM': 'HWiNFO.exe',
'Extra Code': [
r'for %%a in (32 64) do (',
r' copy /y "%bin%\HWiNFO\general.ini" "%bin%\HWiNFO\HWiNFO%%a.ini"',
r' (echo SensorsOnly=1)>>"%bin%\HWiNFO\HWiNFO%%a.ini"',
r' (echo SummaryOnly=0)>>"%bin%\HWiNFO\HWiNFO%%a.ini"',
r')',
],
},
'Notepad++': {
'L_TYPE': 'Executable',
'L_PATH': 'notepadplusplus',
'L_ITEM': 'notepadplusplus.exe',
},
'PuTTY': {
'L_TYPE': 'Executable',
'L_PATH': 'PuTTY',
'L_ITEM': 'PUTTY.EXE',
},
'WizTree': {
'L_TYPE': 'Executable',
'L_PATH': 'WizTree',
'L_ITEM': 'WizTree.exe',
'L_ELEV': 'True',
},
'XMPlay': {
'L_TYPE': 'Executable',
'L_PATH': 'XMPlay',
'L_ITEM': 'xmplay.exe',
'L_ARGS': r'"%bin%\XMPlay\music.7z"',
},
},
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,18 +0,0 @@
"""WizardKit: Config - Log"""
# vim: sts=2 sw=2 ts=2
DEBUG = {
'level': 'DEBUG',
'format': '[%(asctime)s %(levelname)s] [%(name)s.%(funcName)s] %(message)s',
'datefmt': '%Y-%m-%d %H%M%S%z',
}
DEFAULT = {
'level': 'INFO',
'format': '[%(asctime)s %(levelname)s] %(message)s',
'datefmt': '%Y-%m-%d %H%M%z',
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,35 +0,0 @@
"""WizardKit: Config - Main
NOTE: Non-standard formating is used for BASH/BATCH/PYTHON compatibility
"""
# vim: sts=2 sw=2 ts=2
# Features
ENABLED_OPEN_LOGS=False
ENABLED_TICKET_NUMBERS=False
ENABLED_UPLOAD_DATA=False
# Main Kit
ARCHIVE_PASSWORD='Abracadabra'
KIT_NAME_FULL='WizardKit'
KIT_NAME_SHORT='WK'
SUPPORT_MESSAGE='Please let 2Shirt know by opening an issue on Gitea'
# Text Formatting
INDENT=4
WIDTH=32
# Live Linux
ROOT_PASSWORD='Abracadabra'
TECH_PASSWORD='Abracadabra'
# Time Zones
## See 'timedatectl list-timezones' for valid Linux values
## See 'tzutil /l' for valid Windows values
LINUX_TIME_ZONE='America/Los_Angeles'
WINDOWS_TIME_ZONE='Pacific Standard Time'
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,76 +0,0 @@
"""WizardKit: Config - Music Sources"""
# vim: sts=2 sw=2 ts=2
MUSIC_MOD = (
('33432', 'ambrozia.xm'),
('33460', 'amigatre.mod'),
('34594', 'CHARIOT.S3M'),
('34596', 'BUTTERFL.XM'),
('34654', 'CTGOBLIN.S3M'),
('35151', 'bananasplit.mod'),
('35280', 'DEADLOCK.XM'),
('38591', 'compo_liam.xm'),
('39987', 'crystald.s3m'),
('40475', 'ELYSIUM.MOD'),
('42146', 'enigma.mod'),
('42519', 'GHOST2.MOD'),
('42560', 'GSLINGER.MOD'),
('42872', 'existing.xm'),
('50427', 'nf-stven.xm'),
('51549', 'overture.mod'),
('54250', 'SATELL.S3M'),
('54313', 'realmk.s3m'),
('55789', 'scrambld.mod'),
('57934', 'spacedeb.mod'),
('59344', 'stardstm.mod'),
('60395', '2ND_PM.S3M'),
('66187', 'external.xm'),
('66343', 'beek-substitutionology.it'),
('67561', 'radix-unreal_superhero.xm'),
('70829', 'inside_out.s3m'),
('83779', 'beyond_music.mod'),
('104208', 'banana_boat.mod'),
('114971', 'tilbury_fair.mod'),
('132563', 'ufo_tune.mod'),
('135906', 'magnetik_girl.xm'),
('140628', 'autumn_in_budapest.xm'),
('143198', 'summer_memories_3.xm'),
('144405', 'hillbilly_billyboy.xm'),
('154795', '4mat_-_eternity.xm'),
('155845', 'bookworm.mo3'),
('155914', 'battleofsteel.xm'),
('158975', '1_channel_moog.it'),
('165495', 'trans.s3m'),
('168513', 'necros_-_introspection.s3m'),
('169628', 'radix_-_feng_shui_schematics.xm'),
('175238', 'unknown48_-_twilight.mod'),
)
MUSIC_SNES = (
'actr',
'crock',
'ct',
'dkc',
'dkq',
'ff6',
'fz',
'loz3',
'mmx',
'ptws',
'scv4',
'sf',
'sf2',
'sgng',
'smk',
'smw',
'yi',
'zamn',
)
MUSIC_SNES_BAD = {
'ct': ['ct-s*', 'ct-v*'],
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -1,41 +0,0 @@
"""WizardKit: Config - Net"""
# vim: sts=2 sw=2 ts=2
# Servers
BACKUP_SERVERS = {
#'Server One': {
# 'Address': '10.0.0.10',
# 'Share': 'Backups',
# 'RO-User': 'restore',
# 'RO-Pass': 'Abracadabra',
# 'RW-User': 'backup',
# 'RW-Pass': 'Abracadabra',
# },
#'Server Two': {
# 'Address': 'servertwo.example.com',
# 'Share': 'Backups',
# 'RO-User': 'restore',
# 'RO-Pass': 'Abracadabra',
# 'RW-User': 'backup',
# 'RW-Pass': 'Abracadabra',
# },
}
CRASH_SERVER = {
#'Name': 'CrashServer',
#'Url': '',
#'User': '',
#'Pass': '',
#'Headers': {'X-Requested-With': 'XMLHttpRequest'},
}
SDIO_SERVER = {
'Address': '',
'Share': '',
'Path': '',
'RO-User': '',
'RO-Pass': '',
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,99 +0,0 @@
"""WizardKit: Config - Repairs"""
# vim: sts=2 sw=2 ts=2
from wk.cfg.main import KIT_NAME_FULL
AUTO_REPAIR_DELAY_IN_SECONDS = 3
AUTO_REPAIR_KEY = fr'Software\{KIT_NAME_FULL}\Auto Repairs'
BLEACH_BIT_CLEANERS = (
# Applications
'adobe_reader.cache',
'adobe_reader.tmp',
'amule.temp',
'discord.cache',
'flash.cache',
'gimp.tmp',
'google_earth.temporary_files',
'gpodder.cache',
'hippo_opensim_viewer.cache',
'java.cache',
'miro.cache',
'openofficeorg.cache',
'pidgin.cache',
'seamonkey.cache',
'secondlife_viewer.Cache',
'silverlight.temp',
'slack.cache',
'smartftp.cache',
'thunderbird.cache',
'vuze.cache',
'vuze.temp',
'windows_media_player.cache',
'winrar.temp',
'yahoo_messenger.cache',
'zoom.cache',
# Browsers
'brave.cache',
'brave.session',
'chromium.cache',
'chromium.search_engines',
'chromium.session',
'firefox.cache',
'firefox.session_restore',
'google_chrome.cache',
'google_chrome.session',
'internet_explorer.cache',
'microsoft_edge.cache',
'microsoft_edge.session',
'opera.cache',
'opera.session',
'palemoon.cache',
'palemoon.session_restore',
'safari.cache',
'waterfox.cache',
'waterfox.session_restore',
# System
'system.clipboard',
'system.tmp',
'windows_defender.temp',
'windows_explorer.run',
'windows_explorer.thumbnails',
)
CUSTOM_POWER_PLAN_NAME = f'{KIT_NAME_FULL} Power Plan'
CUSTOM_POWER_PLAN_DESC = 'Customized for the best experience.'
POWER_PLANS = {
'Balanced': '381b4222-f694-41f0-9685-ff5bb260df2e',
'Custom': '01189998-8199-9119-725c-ccccccccccc3',
'High Performance': '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c',
}
POWER_PLAN_SLEEP_TIMEOUTS = {
'Balanced': ('1800', '900'),
'High Performance': ('0', '0'),
}
REG_UAC_DEFAULTS_WIN7 = {
'HKLM': {
r'Software\Microsoft\Windows\CurrentVersion\Policies\System': (
('ConsentPromptBehaviorAdmin', 5, 'DWORD'),
('EnableLUA', 1, 'DWORD'),
('PromptOnSecureDesktop', 1, 'DWORD'),
),
},
}
REG_UAC_DEFAULTS_WIN10 = {
'HKLM': {
r'Software\Microsoft\Windows\CurrentVersion\Policies\System': (
('ConsentPromptBehaviorAdmin', 5, 'DWORD'),
('ConsentPromptBehaviorUser', 3, 'DWORD'),
('EnableInstallerDetection', 1, 'DWORD'),
('EnableLUA', 1, 'DWORD'),
('EnableVirtualization', 1, 'DWORD'),
('PromptOnSecureDesktop', 1, 'DWORD'),
),
},
}
WIDTH = 50
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,219 +0,0 @@
"""WizardKit: Config - Setup"""
# vim: sts=2 sw=2 ts=2
BROWSER_PATHS = {
# Relative to PROGRAMFILES_64, PROGRAMFILES_32, LOCALAPPDATA (in that order)
'Google Chrome': 'Google/Chrome/Application/chrome.exe',
'Mozilla Firefox': 'Mozilla Firefox/firefox.exe',
'Microsoft Edge': 'Microsoft/Edge/Application/msedge.exe',
'Opera': 'Opera/launcher.exe',
}
DISABLED_ENTRIES_WINDOWS_11 = {
# Group Name: Option Name
'Install Software': 'Open Shell',
'Configure System': 'Open Shell',
}
LIBREOFFICE_XCU_DATA = '''<?xml version="1.0" encoding="UTF-8"?>
<oor:items xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<item oor:path="/org.openoffice.Setup/Office/Factories/org.openoffice.Setup:Factory['com.sun.star.presentation.PresentationDocument']"><prop oor:name="ooSetupFactoryDefaultFilter" oor:op="fuse"><value>Impress MS PowerPoint 2007 XML</value></prop></item>
<item oor:path="/org.openoffice.Setup/Office/Factories/org.openoffice.Setup:Factory['com.sun.star.sheet.SpreadsheetDocument']"><prop oor:name="ooSetupFactoryDefaultFilter" oor:op="fuse"><value>Calc MS Excel 2007 XML</value></prop></item>
<item oor:path="/org.openoffice.Setup/Office/Factories/org.openoffice.Setup:Factory['com.sun.star.text.TextDocument']"><prop oor:name="ooSetupFactoryDefaultFilter" oor:op="fuse"><value>MS Word 2007 XML</value></prop></item>
<item oor:path="/org.openoffice.Office.Common/Save/Document"><prop oor:name="WarnAlienFormat" oor:op="fuse"><value>false</value></prop></item>
</oor:items>
'''
REG_CHROME_UBLOCK_ORIGIN = {
'HKLM': {
r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm': (
('update_url', 'https://clients2.google.com/service/update2/crx', 'SZ', '32'),
)
},
}
REG_WINDOWS_BSOD_MINIDUMPS = {
'HKLM': {
# Enable small memory dumps
r'SYSTEM\CurrentControlSet\Control\CrashControl': (
('CrashDumpEnabled', 3, 'DWORD'),
)
}
}
REG_WINDOWS_EXPLORER = {
'HKLM': {
# Allow password sign-in for MS accounts
r'Software\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device': (
('DevicePasswordLessBuildVersion', 0, 'DWORD'),
),
# Disable Location Tracking
r'Software\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}': (
('SensorPermissionState', 0, 'DWORD'),
),
r'System\CurrentControlSet\Services\lfsvc\Service\Configuration': (
('Status', 0, 'DWORD'),
),
# Disable Telemetry
r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': (
('AllowTelemetry', 0, 'DWORD'),
('AllowTelemetry', 0, 'DWORD', '32'),
),
r'Software\Policies\Microsoft\Windows\DataCollection': (
('AllowTelemetry', 0, 'DWORD'),
),
# Disable floating Bing search widget
r'Software\Policies\Microsoft\Edge': (
('WebWidgetAllowed', 0, 'DWORD'),
),
# Disable Edge first run screen
r'Software\Policies\Microsoft\MicrosoftEdge\Main': (
('PreventFirstRunPage', 1, 'DWORD'),
),
# Disable Wi-Fi Sense
r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting': (
('Value', 0, 'DWORD'),
),
r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots': (
('Value', 0, 'DWORD'),
),
},
'HKCU': {
# Desktop theme (<= v1809 default)
r'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize': (
('AppsUseLightTheme', 1, 'DWORD'),
('SystemUsesLightTheme', 0, 'DWORD'),
),
# Disable features
r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': (
('SilentInstalledAppsEnabled', 0, 'DWORD'),
# Tips and Tricks
('SoftLandingEnabled ', 0, 'DWORD'),
('SubscribedContent-338389Enabled', 0, 'DWORD'),
),
# Disable news and interests from opening on hover
r'Software\Microsoft\Windows\CurrentVersion\Feeds': (
('ShellFeedsTaskbarOpenOnHover', 0, 'DWORD'),
),
# Disable search highlights
r'Software\Microsoft\Windows\CurrentVersion\Feeds\DSB': (
('ShowDynamicContent', 0, 'DWORD'),
),
# File Explorer
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': (
# Change default Explorer view to "Computer"
('LaunchTo', 1, 'DWORD'),
('SeparateProcess', 1, 'DWORD'),
),
# Hide People bar
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': (
('PeopleBand', 0, 'DWORD'),
),
# Hide Search button / box
r'Software\Microsoft\Windows\CurrentVersion\Search': (
('SearchboxTaskbarMode', 1, 'DWORD'),
),
# Disable search highlights from opening on hover
r'Software\Microsoft\Windows\CurrentVersion\SearchSettings': (
('IsDynamicSearchBoxEnabled', 0, 'DWORD'),
),
# Disable "Let's make Windows even better" screens
r'Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement': (
('ScoobeSystemSettingEnabled', 0, 'DWORD'),
),
},
}
REG_OPEN_SHELL_SETTINGS = {
'HKCU': {
r'Software\OpenShell\StartMenu': (
('ShowedStyle2', 1, 'DWORD'),
),
r'Software\OpenShell\StartMenu\Settings': (
('HighlightNew', 0, 'DWORD'),
('MenuStyle', 'Win7', 'SZ'),
('RecentPrograms', 'Recent', 'SZ'),
('SkinW7', 'Fluent-Metro', 'SZ'),
('SkinVariationW7', '', 'SZ'),
('SkipMetro', 1, 'DWORD'),
(
'SkinOptionsW7',
[
# NOTE: All options need to be specified to work
'DARK_MAIN=1', 'METRO_MAIN=0', 'LIGHT_MAIN=0', 'AUTOMODE_MAIN=0',
'DARK_SUBMENU=0', 'METRO_SUBMENU=0', 'LIGHT_SUBMENU=0', 'AUTOMODE_SUBMENU=1',
'SUBMENU_SEPARATORS=1', 'DARK_SEARCH=0', 'METRO_SEARCH=0', 'LIGHT_SEARCH=1',
'AUTOMODE_SEARCH=0', 'SEARCH_FRAME=1', 'SEARCH_COLOR=0', 'SMALL_SEARCH=0',
'MODERN_SEARCH=1', 'SEARCH_ITALICS=0', 'NONE=0', 'SEPARATOR=0',
'TWO_TONE=1', 'CLASSIC_SELECTOR=1', 'HALF_SELECTOR=0', 'CURVED_MENUSEL=1',
'CURVED_SUBMENU=0', 'SELECTOR_REVEAL=0', 'TRANSPARENT=0', 'OPAQUE_SUBMENU=1',
'OPAQUE_MENU=0', 'OPAQUE=0', 'STANDARD=1', 'SMALL_MAIN2=0',
'SMALL_ICONS=0', 'COMPACT_SUBMENU=0', 'PRESERVE_MAIN2=0', 'LESS_PADDING=0',
'EXTRA_PADDING=1', '24_PADDING=0', 'LARGE_PROGRAMS=0', 'TRANSPARENT_SHUTDOWN=0',
'OUTLINE_SHUTDOWN=0', 'BUTTON_SHUTDOWN=1', 'EXPERIMENTAL_SHUTDOWN=0', 'LARGE_FONT=0',
'CONNECTED_BORDER=1', 'FLOATING_BORDER=0', 'LARGE_SUBMENU=0', 'LARGE_LISTS=0',
'THIN_MAIN2=0', 'EXPERIMENTAL_MAIN2=1', 'USER_IMAGE=1', 'USER_OUTSIDE=0',
'SCALING_USER=1', '56=0', '64=0', 'TRANSPARENT_USER=0',
'UWP_SCROLLBAR=1', 'MODERN_SCROLLBAR=0', 'OLD_ICONS=0', 'NEW_ICONS=1',
'SMALL_ARROWS=0', 'ICON_FRAME=0', 'SEARCH_SEPARATOR=0', 'NO_PROGRAMS_BUTTON=0',
],
'MULTI_SZ',
),
),
},
}
REG_OPEN_SHELL_LOW_POWER_IDLE = {
'HKCU': {
r'Software\OpenShell\StartMenu': (
(
'CSettingsDlg',
b'h\x02\x00\x00\xa7\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\r\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00',
'BINARY',
),
(
'CEditMenuDlg7',
b'\xde\x02\x00\x00\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
'BINARY',
),
),
r'Software\OpenShell\StartMenu\Settings': (
('ShutdownW7', 'switch_user, logoff, lock, restart, hibernate', 'SZ'),
(
'MenuItems7',
[
'Item1.Command=user_files', 'Item1.Settings=NOEXPAND',
'Item2.Command=user_documents', 'Item2.Settings=NOEXPAND',
'Item3.Command=user_pictures', 'Item3.Settings=NOEXPAND',
'Item4.Command=user_music', 'Item4.Settings=NOEXPAND',
'Item5.Command=user_videos', 'Item5.Settings=ITEM_DISABLED',
'Item6.Command=downloads', 'Item6.Settings=ITEM_DISABLED',
'Item7.Command=homegroup', 'Item7.Settings=ITEM_DISABLED',
'Item8.Command=separator',
'Item9.Command=games', 'Item9.Settings=TRACK_RECENT|NOEXPAND|ITEM_DISABLED',
'Item10.Command=favorites', 'Item10.Settings=ITEM_DISABLED',
'Item11.Command=recent_documents',
'Item12.Command=computer', 'Item12.Settings=NOEXPAND',
'Item13.Command=network', 'Item13.Settings=ITEM_DISABLED',
'Item14.Command=network_connections', 'Item14.Settings=ITEM_DISABLED',
'Item15.Command=separator',
'Item16.Command=control_panel', 'Item16.Settings=TRACK_RECENT',
'Item17.Command=pc_settings', 'Item17.Settings=TRACK_RECENT',
'Item18.Command=admin', 'Item18.Settings=TRACK_RECENT|ITEM_DISABLED',
'Item19.Command=devices', 'Item19.Settings=NOEXPAND',
'Item20.Command=defaults',
'Item21.Command=help',
'Item22.Command=run',
'Item23.Command=monitor_off', 'Item23.Label=Sleep', 'Item23.Settings=NOEXPAND',
'Item24.Command=apps', 'Item24.Settings=ITEM_DISABLED',
'Item25.Command=windows_security',
],
'MULTI_SZ',
),
),
},
}
UBLOCK_ORIGIN_URLS = {
'Google Chrome': 'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm',
'Microsoft Edge': 'https://microsoftedge.microsoft.com/addons/detail/ublock-origin/odfafepnkmbhccpbejgmiehpchacaeak',
'Mozilla Firefox': 'https://addons.mozilla.org/addon/ublock-origin/',
'Opera': 'https://addons.opera.com/extensions/details/ublock/',
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,62 +0,0 @@
"""WizardKit: Config - Tool Sources"""
# vim: sts=2 sw=2 ts=2
# Download frequency in days
DOWNLOAD_FREQUENCY = 7
# Sources
SOURCES = {
# Main
'AVRemover32': 'https://download.eset.com/com/eset/tools/installers/av_remover/latest/avremover_nt32_enu.exe',
'AVRemover64': 'https://download.eset.com/com/eset/tools/installers/av_remover/latest/avremover_nt64_enu.exe',
'AdwCleaner': 'https://downloads.malwarebytes.com/file/adwcleaner',
'Autologon32': 'http://live.sysinternals.com/Autologon.exe',
'Autologon64': 'http://live.sysinternals.com/Autologon64.exe',
'Firefox32': 'https://download.mozilla.org/?product=firefox-latest-ssl&os=win&lang=en-US',
'Firefox64': 'https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US',
'HitmanPro32': 'https://dl.surfright.nl/HitmanPro.exe',
'HitmanPro64': 'https://dl.surfright.nl/HitmanPro_x64.exe',
'KVRT': 'https://devbuilds.s.kaspersky-labs.com/devbuilds/KVRT/latest/full/KVRT.exe',
'RKill': 'https://download.bleepingcomputer.com/grinler/rkill.exe',
'RegDelNull': 'https://live.sysinternals.com/RegDelNull.exe',
'RegDelNull64': 'https://live.sysinternals.com/RegDelNull64.exe',
# Build Kit
'AIDA64': 'https://download.aida64.com/aida64engineer692.zip',
'Adobe Reader DC': 'https://ardownload2.adobe.com/pub/adobe/reader/win/AcrobatDC/2300620360/AcroRdrDC2300620360_en_US.exe',
'Aria2': 'https://github.com/aria2/aria2/releases/download/release-1.36.0/aria2-1.36.0-win-32bit-build1.zip',
'Autoruns32': 'http://live.sysinternals.com/Autoruns.exe',
'Autoruns64': 'http://live.sysinternals.com/Autoruns64.exe',
'BleachBit': 'https://download.bleachbit.org/BleachBit-4.4.2-portable.zip',
'BlueScreenView32': 'http://www.nirsoft.net/utils/bluescreenview.zip',
'BlueScreenView64': 'http://www.nirsoft.net/utils/bluescreenview-x64.zip',
'BCUninstaller': 'https://github.com/Klocman/Bulk-Crap-Uninstaller/releases/download/v5.7/BCUninstaller_5.7_portable.zip',
'DDU': 'https://www.wagnardsoft.com/DDU/download/DDU%20v18.0.6.8.exe',
'ERUNT': 'http://www.aumha.org/downloads/erunt.zip',
'Everything32': 'https://www.voidtools.com/Everything-1.4.1.1024.x86.zip',
'Everything64': 'https://www.voidtools.com/Everything-1.4.1.1024.x64.zip',
'FastCopy': 'https://github.com/FastCopyLab/FastCopyDist2/raw/main/FastCopy5.4.2_installer.exe',
'Fluent-Metro': 'https://github.com/bonzibudd/Fluent-Metro/releases/download/v1.5.3/Fluent-Metro_1.5.3.zip',
'FurMark': 'https://geeks3d.com/dl/get/728',
'HWiNFO': 'https://www.sac.sk/download/utildiag/hwi_764.zip',
'LibreOffice32': 'https://download.documentfoundation.org/libreoffice/stable/7.6.2/win/x86/LibreOffice_7.6.2_Win_x86.msi',
'LibreOffice64': 'https://download.documentfoundation.org/libreoffice/stable/7.6.2/win/x86_64/LibreOffice_7.6.2_Win_x86-64.msi',
'Macs Fan Control': 'https://www.crystalidea.com/downloads/macsfancontrol_setup.exe',
'Neutron': 'http://keir.net/download/neutron.zip',
'Notepad++': 'https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.5.8/npp.8.5.8.portable.minimalist.7z',
'OpenShell': 'https://github.com/Open-Shell/Open-Shell-Menu/releases/download/v4.4.191/OpenShellSetup_4_4_191.exe',
'PuTTY': 'https://the.earth.li/~sgtatham/putty/latest/w32/putty.zip',
'SDIO Torrent': 'https://www.glenn.delahoy.com/downloads/sdio/SDIO_Update.torrent',
'WizTree': 'https://diskanalyzer.com/files/wiztree_4_15_portable.zip',
'XMPlay': 'https://support.xmplay.com/files/20/xmplay385.zip?v=47090',
'XMPlay 7z': 'https://support.xmplay.com/files/16/xmp-7z.zip?v=800962',
'XMPlay Game': 'https://support.xmplay.com/files/12/xmp-gme.zip?v=515637',
'XMPlay RAR': 'https://support.xmplay.com/files/16/xmp-rar.zip?v=409646',
'XMPlay Innocuous': 'https://support.xmplay.com/files/10/Innocuous%20(v1.7).zip?v=645281',
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,95 +0,0 @@
"""WizardKit: Config - UFD"""
# vim: sts=2 sw=2 ts=2
from wk.cfg.main import KIT_NAME_FULL
# General
SOURCES = {
'Linux': {'Arg': '--linux', 'Type': 'ISO'},
'WinPE': {'Arg': '--winpe', 'Type': 'ISO'},
'Main Kit': {'Arg': '--main-kit', 'Type': 'KIT'},
'Extra Dir': {'Arg': '--extra-dir', 'Type': 'DIR'},
}
# Definitions: Boot entries
BOOT_ENTRIES = {
# Path to check: Comment to remove
'/sources/boot.wim': 'UFD-WINPE',
}
BOOT_FILES = {
# Directory: extension
'/syslinux': 'cfg',
'/EFI/boot': 'conf',
}
IMAGE_BOOT_ENTRIES = {
'El Capitan': 'UFD-MACOS-10.11',
'High Sierra': 'UFD-MACOS-10.13',
'Catalina': 'UFD-MACOS-10.15',
}
# Definitions: Sources and Destinations
## NOTES: Paths are relative to the root of the ISO/UFD
## Sources use rsync's trailing slash syntax
ITEMS = {
'Extra Dir': (
('/', '/'),
),
'Linux': (
('/arch', '/'),
),
'Main Kit': (
('/', f'/{KIT_NAME_FULL}/'),
),
'WinPE': (
('/bootmgr', '/'),
('/bootmgr.efi', '/'),
('/en_us', '/'),
('/Boot/', '/boot/'),
('/EFI/Boot/', '/EFI/Microsoft/'),
('/EFI/Microsoft/', '/EFI/Microsoft/'),
('/Boot/BCD', '/sources/'),
('/Boot/boot.sdi', '/sources/'),
('/bootmgr', '/sources/'),
('/sources/boot.wim', '/sources/'),
),
}
ITEMS_FROM_LIVE = {
'WizardKit UFD base': (
('/usr/share/WizardKit/', '/'),
),
'rEFInd': (
('/usr/share/refind/drivers_x64/', '/EFI/Boot/drivers_x64/'),
('/usr/share/refind/icons/', '/EFI/Boot/icons/'),
('/usr/share/refind/refind_x64.efi', '/EFI/Boot/'),
),
'Syslinux': (
('/usr/lib/syslinux/bios/', '/syslinux/'),
),
'Memtest86': (
('/usr/share/memtest86-efi/', '/EFI/Memtest86/'),
),
'Wimboot': (
('/usr/share/wimboot/', '/syslinux/'),
),
}
ITEMS_HIDDEN = (
# Linux (all versions)
'arch',
'EFI',
'syslinux',
# Main Kit
f'{KIT_NAME_FULL}/.bin',
f'{KIT_NAME_FULL}/.cbin',
# WinPE
'boot',
'bootmgr',
'bootmgr.efi',
'en-us',
'images',
'sources',
)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,43 +0,0 @@
"""WizardKit: Config - Windows Builds"""
# vim: sts=2 sw=2 ts=2
OLDEST_SUPPORTED_BUILD = 19041 # Windows 10 20H1
OUTDATED_BUILD_NUMBERS = (
9600, # Windows 8.1 Update
18363, # Windows 10 19H2
)
WINDOWS_BUILDS = {
# Windows 7
'6.1.7600': 'RTM "Vienna"',
'6.1.7601': 'SP1 "Vienna"',
# Windows 8
'6.2.9200': 'RTM',
# Widnows 8.1
'6.3.9200': '"Blue"',
'6.3.9600': '"Update"',
# Windows 10
'10.0.10240': '1507 "Threshold 1"',
'10.0.10586': '1511 "Threshold 2"',
'10.0.14393': '1607 "Redstone 1"',
'10.0.15063': '1703 "Redstone 2"',
'10.0.16299': '1709 "Redstone 3"',
'10.0.17134': '1803 "Redstone 4"',
'10.0.17763': '1809 "Redstone 5"',
'10.0.18362': '1903 / 19H1',
'10.0.18363': '1909 / 19H2',
'10.0.19041': '2004 / 20H1',
'10.0.19042': '20H2',
'10.0.19043': '21H1',
'10.0.19044': '21H2',
'10.0.19045': '22H2',
# Windows 11
'10.0.22000': '21H2',
'10.0.22621': '22H2',
'10.0.22631': '23H2',
'10.0.26100': '24H2',
}

View file

@ -1,32 +0,0 @@
{
"$schema": "https://aka.ms/winget-packages.schema.2.0.json",
"CreationDate": "2023-06-25T01:40:45.003-00:00",
"Sources": [
{
"Packages": [
{
"PackageIdentifier": "7zip.7zip"
},
{
"PackageIdentifier": "Google.Chrome"
},
{
"PackageIdentifier": "Microsoft.Edge"
},
{
"PackageIdentifier": "Mozilla.Firefox"
},
{
"PackageIdentifier": "VideoLAN.VLC"
}
],
"SourceDetails": {
"Argument": "https://cdn.winget.microsoft.com/cache",
"Identifier": "Microsoft.Winget.Source_8wekyb3d8bbwe",
"Name": "winget",
"Type": "Microsoft.PreIndexed.Package"
}
}
],
"WinGetVersion": "1.4.11071"
}

View file

@ -1,29 +0,0 @@
{
"$schema": "https://aka.ms/winget-packages.schema.2.0.json",
"CreationDate": "2023-06-25T01:40:45.003-00:00",
"Sources": [
{
"Packages": [
{
"PackageIdentifier": "Microsoft.VCRedist.2013.x64"
},
{
"PackageIdentifier": "Microsoft.VCRedist.2013.x86"
},
{
"PackageIdentifier": "Microsoft.VCRedist.2015+.x64"
},
{
"PackageIdentifier": "Microsoft.VCRedist.2015+.x86"
}
],
"SourceDetails": {
"Argument": "https://cdn.winget.microsoft.com/cache",
"Identifier": "Microsoft.Winget.Source_8wekyb3d8bbwe",
"Name": "winget",
"Type": "Microsoft.PreIndexed.Package"
}
}
],
"WinGetVersion": "1.4.11071"
}

View file

@ -1,7 +0,0 @@
"""WizardKit: ddrescue-tui module init"""
from . import block_pair
from . import ddrescue
from . import image
from . import menus
from . import state

View file

@ -1,575 +0,0 @@
"""WizardKit: ddrescue TUI - Block Pairs"""
# vim: sts=2 sw=2 ts=2
import logging
import math
import os
import pathlib
import plistlib
import re
import subprocess
from wk import cfg, exe, std
from wk.clone import menus
from wk.hw import disk as hw_disk
from wk.ui import ansi, cli
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
DDRESCUE_LOG_REGEX = re.compile(
r'^\s*(?P<key>\S+):\s+'
r'(?P<size>\d+)\s+'
r'(?P<unit>[PTGMKB]i?B?)'
r'.*\(\s*(?P<percent>\d+\.?\d*)%\)$',
re.IGNORECASE,
)
# Classes
class BlockPair():
"""Object for tracking source to dest recovery data."""
def __init__(
self,
source_dev: hw_disk.Disk,
destination: pathlib.Path,
working_dir: pathlib.Path,
):
self.sector_size: int = source_dev.phy_sec
self.source: pathlib.Path = pathlib.Path(source_dev.path)
self.destination: pathlib.Path = destination
self.map_data: dict[str, bool | int] = {}
self.map_path: pathlib.Path = pathlib.Path()
self.size: int = source_dev.size
self.status: dict[str, float | int | str] = {
'read-skip': 'Pending',
'read-full': 'Pending',
'trim': 'Pending',
'scrape': 'Pending',
}
self.test_map: pathlib.Path | None = None
self.view_map: bool = 'DISPLAY' in os.environ or 'WAYLAND_DISPLAY' in os.environ
self.view_proc: subprocess.Popen | None = None
# Set map path
# e.g. '(Clone|Image)_Model_Serial[_p#]_Size[_Label].map'
map_name = f'{source_dev.model}_{source_dev.serial}'
if source_dev.bus == 'Image':
map_name = 'Image'
if source_dev.parent:
part_num = re.sub(r"^.*?(\d+)$", r"\1", self.source.name)
map_name += f'_p{part_num}'
size_str = std.bytes_to_string(
size=self.size,
use_binary=False,
)
map_name += f'_{size_str.replace(" ", "")}'
if source_dev.raw_details.get('label', ''):
map_name += f'_{source_dev.raw_details["label"]}'
map_name = map_name.replace(' ', '_')
map_name = map_name.replace('/', '_')
map_name = map_name.replace('\\', '_')
if destination.is_dir():
# Imaging
self.map_path = pathlib.Path(f'{destination}/Image_{map_name}.map')
self.destination = self.map_path.with_suffix('.dd')
self.destination.touch()
else:
# Cloning
self.map_path = pathlib.Path(f'{working_dir}/Clone_{map_name}.map')
# Create map file if needed
# NOTE: We need to set the domain size for --complete-only to work
if not self.map_path.exists():
self.map_path.write_text(
data=cfg.ddrescue.DDRESCUE_MAP_TEMPLATE.format(
name=cfg.main.KIT_NAME_FULL,
size=self.size,
),
encoding='utf-8',
)
# Set initial status
self.set_initial_status()
def __getstate__(self):
"""Override to allow pickling ddrescue.State() objects."""
bp_state = self.__dict__.copy()
del bp_state['view_proc']
return bp_state
def get_error_size(self) -> int:
"""Get error size in bytes, returns int."""
return self.size - self.get_rescued_size()
def get_percent_recovered(self) -> float:
"""Get percent rescued from map_data, returns float."""
return 100 * self.map_data.get('rescued', 0) / self.size
def get_rescued_size(self) -> int:
"""Get rescued size using map data.
NOTE: Returns 0 if no map data is available.
"""
self.load_map_data()
return self.map_data.get('rescued', 0)
def load_map_data(self) -> None:
"""Load map data from file.
NOTE: If the file is missing it is assumed that recovery hasn't
started yet so default values will be returned instead.
"""
data: dict[str, bool | int] = {'full recovery': False, 'pass completed': False}
# Get output from ddrescuelog
cmd = [
'ddrescuelog',
'--binary-prefixes',
'--show-status',
f'--size={self.size}',
self.map_path,
]
proc = exe.run_program(cmd, check=False)
# Parse output
for line in proc.stdout.splitlines():
_r = DDRESCUE_LOG_REGEX.search(line)
if _r:
if _r.group('key') == 'rescued' and _r.group('percent') == '100':
# Fix rounding errors from ddrescuelog output
data['rescued'] = self.size
else:
data[_r.group('key')] = std.string_to_bytes(
f'{_r.group("size")} {_r.group("unit")}',
)
data['pass completed'] = 'current status: finished' in line.lower()
# Check if 100% done (only if map is present and non-zero size
# NOTE: ddrescuelog returns 0 (i.e. 100% done) for empty files
if self.map_path.exists() and self.map_path.stat().st_size != 0:
cmd = [
'ddrescuelog',
'--done-status',
f'--size={self.size}',
self.map_path,
]
proc = exe.run_program(cmd, check=False)
data['full recovery'] = proc.returncode == 0
# Done
self.map_data.update(data)
def pass_complete(self, pass_name) -> bool:
"""Check if pass_name is complete based on map data, returns bool."""
pending_size = self.map_data['non-tried']
# Full recovery
if self.map_data.get('full recovery', False):
return True
# New recovery
if 'non-tried' not in self.map_data:
return False
# Initial read skip pass
if pass_name == 'read-skip':
pass_threshold = cfg.ddrescue.AUTO_PASS_THRESHOLDS[pass_name]
if self.get_percent_recovered() >= pass_threshold:
return True
# Recovery in progress
if pass_name in ('trim', 'scrape'):
pending_size += self.map_data['non-trimmed']
if pass_name == 'scrape':
pending_size += self.map_data['non-scraped']
if pending_size == 0:
# This is true when the previous and current passes are complete
return True
# This should never be reached
return False
def safety_check(self) -> None:
"""Run safety check and abort if necessary."""
# TODO: Expand section to support non-Linux systems
dest_size = -1
if self.destination.is_block_device():
cmd = [
'lsblk', '--bytes', '--json',
'--nodeps', '--noheadings', '--output=size',
self.destination,
]
json_data = exe.get_json_from_command(cmd)
dest_size = json_data['blockdevices'][0]['size']
del json_data
# Check destination size if cloning
if not self.destination.is_file() and dest_size < self.size:
cli.print_error(f'Invalid destination: {self.destination}')
raise std.GenericAbort()
def set_initial_status(self) -> None:
"""Read map data and set initial statuses."""
self.load_map_data()
percent = self.get_percent_recovered()
for name in self.status:
if self.pass_complete(name):
self.status[name] = percent
else:
# Stop checking
if percent > 0:
self.status[name] = percent
break
def skip_pass(self, pass_name) -> None:
"""Mark pass as skipped if applicable."""
if self.status[pass_name] == 'Pending':
self.status[pass_name] = 'Skipped'
def update_progress(self, pass_name) -> None:
"""Update progress via map data."""
self.load_map_data()
# Update status
percent = self.get_percent_recovered()
if percent > 0:
self.status[pass_name] = percent
# Mark future passes as skipped if applicable
if percent == 100:
status_keys = list(self.status.keys())
for pass_n in status_keys[status_keys.index(pass_name)+1:]:
self.status[pass_n] = 'Skipped'
# Functions
def add_clone_block_pairs(state) -> list[hw_disk.Disk]:
"""Add device to device block pairs and set settings if necessary."""
source_sep = get_partition_separator(state.source.path.name)
dest_sep = get_partition_separator(state.destination.path.name)
settings = {}
# Clone settings
settings = state.load_settings(discard_unused_settings=True)
# Add pairs from previous run
if settings['Partition Mapping']:
source_parts = []
for part_map in settings['Partition Mapping']:
bp_source = hw_disk.Disk(
f'{state.source.path}{source_sep}{part_map[0]}',
)
bp_dest = pathlib.Path(
f'{state.destination.path}{dest_sep}{part_map[1]}',
)
source_parts.append(bp_source)
state.add_block_pair(bp_source, bp_dest)
return source_parts
# Add pairs from selection
source_parts = menus.select_disk_parts('Clone', state.source)
if state.source.path.samefile(source_parts[0].path):
# Whole disk (or single partition via args), skip settings
bp_dest = state.destination.path
state.add_block_pair(state.source, bp_dest)
return source_parts
# New run, use new settings file
settings['Needs Format'] = True
offset = 0
user_choice = cli.choice(
'Format clone using GPT, MBR, or match Source type?',
['G', 'M', 'S'],
)
if user_choice == 'G':
settings['Table Type'] = 'GPT'
elif user_choice == 'M':
settings['Table Type'] = 'MBR'
else:
# Match source type
settings['Table Type'] = get_table_type(state.source.path)
if cli.ask('Create an empty Windows boot partition on the clone?'):
settings['Create Boot Partition'] = True
offset = 2 if settings['Table Type'] == 'GPT' else 1
# Add pairs
for dest_num, part in enumerate(source_parts):
dest_num += offset + 1
bp_dest = pathlib.Path(
f'{state.destination.path}{dest_sep}{dest_num}',
)
state.add_block_pair(part, bp_dest)
# Add to settings file
source_num = re.sub(r'^.*?(\d+)$', r'\1', part.path.name)
settings['Partition Mapping'].append([source_num, dest_num])
# Save settings
state.save_settings(settings)
# Done
return source_parts
def add_image_block_pairs(state) -> list[hw_disk.Disk]:
"""Add device to image file block pairs."""
source_parts = menus.select_disk_parts(state.mode, state.source)
for part in source_parts:
state.add_block_pair(part, state.destination)
# Done
return source_parts
def build_block_pair_report(block_pairs, settings) -> list:
"""Build block pair report, returns list."""
report = []
notes = []
if block_pairs:
report.append(ansi.color_string('Block Pairs', 'GREEN'))
else:
# Bail early
return report
# Show block pair mapping
if settings and settings['Create Boot Partition']:
if settings['Table Type'] == 'GPT':
report.append(f'{" —— ":<9} --> EFI System Partition')
report.append(f'{" —— ":<9} --> Microsoft Reserved Partition')
elif settings['Table Type'] == 'MBR':
report.append(f'{" —— ":<9} --> System Reserved')
for pair in block_pairs:
report.append(f'{pair.source.name:<9} --> {pair.destination.name}')
# Show resume messages as necessary
if settings:
if not settings['First Run']:
notes.append(
ansi.color_string(
['NOTE:', 'Clone settings loaded from previous run.'],
['BLUE', None],
),
)
if settings['Needs Format'] and settings['Table Type']:
msg = f'Destination will be formatted using {settings["Table Type"]}'
notes.append(
ansi.color_string(
['NOTE:', msg],
['BLUE', None],
),
)
if any(pair.get_rescued_size() > 0 for pair in block_pairs):
notes.append(
ansi.color_string(
['NOTE:', 'Resume data loaded from map file(s).'],
['BLUE', None],
),
)
# Add notes to report
if notes:
report.append(' ')
report.extend(notes)
# Done
return report
def build_sfdisk_partition_line(table_type, dev_path, size, details) -> str:
"""Build sfdisk partition line using passed details, returns str."""
line = f'{dev_path} : size={size}'
dest_type = ''
source_filesystem = str(details.get('fstype', '')).upper()
source_table_type = ''
source_type = details.get('parttype', '')
# Set dest type
if re.match(r'^0x\w+$', source_type):
# Source is a MBR type
source_table_type = 'MBR'
if table_type == 'MBR':
dest_type = source_type.replace('0x', '').lower()
elif re.match(r'^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$', source_type):
# Source is a GPT type
source_table_type = 'GPT'
if table_type == 'GPT':
dest_type = source_type.upper()
if not dest_type:
# Assuming changing table types, set based on FS
if source_filesystem in cfg.ddrescue.PARTITION_TYPES.get(table_type, {}):
dest_type = cfg.ddrescue.PARTITION_TYPES[table_type][source_filesystem]
line += f', type={dest_type}'
# Safety Check
if not dest_type:
cli.print_error(f'Failed to determine partition type for: {dev_path}')
raise std.GenericAbort()
# Add extra details
if details.get('partlabel', ''):
line += f', name="{details["partlabel"]}"'
if details.get('partuuid', '') and source_table_type == table_type:
# Only add UUID if source/dest table types match
line += f', uuid={details["partuuid"].upper()}'
# Done
return line
def get_partition_separator(name) -> str:
"""Get partition separator based on device name, returns str."""
separator = ''
if re.search(r'(loop|mmc|nvme)', name, re.IGNORECASE):
separator = 'p'
return separator
def get_table_type(disk_path) -> str:
"""Get disk partition table type, returns str.
NOTE: If resulting table type is not GPT or MBR
then an exception is raised.
"""
disk_path = str(disk_path)
table_type = None
# Linux
if std.PLATFORM == 'Linux':
cmd = f'lsblk --json --output=pttype --nodeps {disk_path}'.split()
json_data = exe.get_json_from_command(cmd)
table_type = json_data['blockdevices'][0].get('pttype', '').upper()
table_type = table_type.replace('DOS', 'MBR')
# macOS
if std.PLATFORM == 'Darwin':
cmd = ['diskutil', 'list', '-plist', disk_path]
proc = exe.run_program(cmd, check=False, encoding=None, errors=None)
try:
plist_data = plistlib.loads(proc.stdout)
except (TypeError, ValueError):
# Invalid / corrupt plist data? return empty dict to avoid crash
pass
else:
disk_details = plist_data.get('AllDisksAndPartitions', [{}])[0]
table_type = disk_details['Content']
table_type = table_type.replace('FDisk_partition_scheme', 'MBR')
table_type = table_type.replace('GUID_partition_scheme', 'GPT')
# Check type
if table_type not in ('GPT', 'MBR'):
cli.print_error(f'Unsupported partition table type: {table_type}')
raise std.GenericAbort()
# Done
return table_type
def prep_destination(
state,
source_parts: list[hw_disk.Disk],
dry_run: bool = True,
) -> None:
"""Prep destination as necessary."""
# TODO: Split into Linux and macOS
# logical sector size is not easily found under macOS
# It might be easier to rewrite this section using macOS tools
dest_prefix = str(state.destination.path)
dest_prefix += get_partition_separator(state.destination.path.name)
esp_type = 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B'
msr_type = 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE'
part_num = 0
sfdisk_script = []
settings = state.load_settings()
# Bail early
if not settings['Needs Format']:
return
# Add partition table settings
if settings['Table Type'] == 'GPT':
sfdisk_script.append('label: gpt')
else:
sfdisk_script.append('label: dos')
sfdisk_script.append('unit: sectors')
sfdisk_script.append('')
# Add boot partition if requested
if settings['Create Boot Partition']:
if settings['Table Type'] == 'GPT':
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type='GPT',
dev_path=f'{dest_prefix}{part_num}',
size='260MiB',
details={'parttype': esp_type, 'partlabel': 'EFI System'},
),
)
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type=settings['Table Type'],
dev_path=f'{dest_prefix}{part_num}',
size='16MiB',
details={'parttype': msr_type, 'partlabel': 'Microsoft Reserved'},
),
)
elif settings['Table Type'] == 'MBR':
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type='MBR',
dev_path=f'{dest_prefix}{part_num}',
size='100MiB',
details={'parttype': '0x7', 'partlabel': 'System Reserved'},
),
)
# Add selected partition(s)
for part in source_parts:
num_sectors = part.size / state.destination.log_sec
num_sectors = math.ceil(num_sectors)
part_num += 1
sfdisk_script.append(
build_sfdisk_partition_line(
table_type=settings['Table Type'],
dev_path=f'{dest_prefix}{part_num}',
size=num_sectors,
details=part.raw_details,
),
)
# Save sfdisk script
script_path = (
f'{state.working_dir}/'
f'sfdisk_{state.destination.path.name}.script'
)
with open(script_path, 'w', encoding='utf-8') as _f:
_f.write('\n'.join(sfdisk_script))
# Skip real format for dry runs
if dry_run:
LOG.info('Dry run, refusing to format destination')
return
# Format disk
LOG.warning('Formatting destination: %s', state.destination.path)
with open(script_path, 'r', encoding='utf-8') as _f:
proc = exe.run_program(
cmd=['sudo', 'sfdisk', state.destination.path],
stdin=_f,
check=False,
)
if proc.returncode != 0:
cli.print_error('Error(s) encoundtered while formatting destination')
raise std.GenericAbort()
# Update settings
settings['Needs Format'] = False
state.save_settings(settings)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,745 +0,0 @@
"""WizardKit: ddrescue TUI"""
# vim: sts=2 sw=2 ts=2
import argparse
import atexit
import datetime
import logging
import os
import pathlib
import subprocess
from random import randint
import pytz
from wk import cfg, exe, io, log, std
from wk.cfg.ddrescue import DDRESCUE_SPECIFIC_PASS_SETTINGS
from wk.clone import menus
from wk.clone.state import State, mark_non_recovered_as_non_tried
from wk.hw import disk as hw_disk
from wk.hw.smart import (
check_attributes,
smart_status_ok,
update_smart_details,
)
from wk.ui import ansi, cli
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
DETECT_DRIVES_NOTICE = '''
This option will force the drive controllers to rescan for devices.
The method used is not 100% reliable and may cause issues. If you see
any script errors or crashes after running this option then please
restart the computer and try again.
'''
DDRESCUE_OUTPUT_HEIGHT = 14
INITIAL_SKIP_MIN = 64 * 1024 # This is ddrescue's minimum accepted value
PLATFORM = std.PLATFORM
TIMEZONE = pytz.timezone(cfg.main.LINUX_TIME_ZONE)
# Functions
def argparse_helper() -> dict[str, None|bool|str]:
"""Helper function to setup and return args, returns dict.
NOTE: A dict is used to match the legacy code.
"""
parser = argparse.ArgumentParser(
prog='ddrescue-tui',
description=f'{cfg.main.KIT_NAME_FULL}: ddrescue TUI',
)
parser.add_argument('mode', choices=('clone', 'image'), nargs='?')
parser.add_argument('source', nargs='?')
parser.add_argument('destination', nargs='?')
parser.add_argument(
'-s', '--dry-run', action='store_true',
help='Print commands to be used instead of running them',
)
parser.add_argument(
'--force-local-map', action='store_true',
help='Skip mounting shares and save map to local drive',
)
parser.add_argument(
'--start-fresh', action='store_true',
help='Ignore previous runs and start new recovery',
)
args = parser.parse_args()
legacy_args = {
'clone': args.mode == 'clone',
'image': args.mode == 'image',
'<source>': args.source,
'<destination>': args.destination,
'--dry-run': args.dry_run,
'--force-local-map': args.force_local_map,
'--start-fresh': args.start_fresh,
}
return legacy_args
def build_ddrescue_cmd(block_pair, pass_name, settings_menu) -> list[str]:
"""Build ddrescue cmd using passed details, returns list."""
cmd = ['sudo', 'ddrescue']
if (block_pair.destination.is_block_device()
or block_pair.destination.is_char_device()):
cmd.append('--force')
cmd.extend(DDRESCUE_SPECIFIC_PASS_SETTINGS.get(pass_name, []))
# Fix domain size based on starting position
domain_size = block_pair.size
if settings_menu.options['--input-position']['Selected']:
settings_menu.options['--reverse']['Selected'] = False
input_position = std.string_to_bytes(
settings_menu.options['--input-position']['Value'],
)
domain_size -= input_position
cmd.append(f'--size={domain_size}')
# Determine skip sizes
if settings_menu.options['--skip-size']['Selected']:
skip_sizes = settings_menu.options['--skip-size']['Value'].split(',')
skip_sizes = [float(s) for s in skip_sizes]
initial_skip = max(INITIAL_SKIP_MIN, int(block_pair.size * skip_sizes[0]))
max_skip = min(int(block_pair.size * skip_sizes[1]), domain_size)
max_skip = max(INITIAL_SKIP_MIN, max_skip)
cmd.append(f'--skip-size={initial_skip},{max_skip}')
cmd.extend(get_ddrescue_settings(settings_menu))
# Add source physical sector size (if possible)
cmd.append(f'--sector-size={block_pair.sector_size}')
# Generate test map if needed
if '--test-mode' in cmd:
cmd.remove('--test-mode')
if not block_pair.test_map:
block_pair.test_map = block_pair.map_path.with_stem(
f'{block_pair.map_path.stem}-testing'
)
generate_test_map(map_path=block_pair.test_map, size=domain_size)
cmd.append(f'--test-mode={block_pair.test_map}')
# Add block pair and map file
if PLATFORM == 'Darwin':
# Use Raw disks if possible
for dev in (block_pair.source, block_pair.destination):
raw_dev = pathlib.Path(dev.with_name(f'r{dev.name}'))
if raw_dev.exists():
cmd.append(raw_dev)
else:
cmd.append(dev)
else:
cmd.append(block_pair.source)
cmd.append(block_pair.destination)
cmd.append(block_pair.map_path)
# Done
LOG.debug('ddrescue cmd: %s', cmd)
return cmd
def check_destination_health(destination) -> str:
"""Check destination health, returns str."""
result = ''
# Bail early
if not isinstance(destination, hw_disk.Disk):
# Return empty string
return result
# Check for critical errors
if not smart_status_ok(destination):
result = 'Critical error(s) detected for: {destination.path}'
# Check for minor errors
if not check_attributes(destination, only_blocking=False):
result = f'Attribute error(s) detected for: {destination.path}'
# Done
return result
def generate_test_map(map_path: pathlib.Path, size: int) -> None:
"""Generate test map with roughly 20% of the space marked as bad."""
chunk = 2*1024**2
output = [
'# Mapfile. Created by WizardKit',
'0x0 ? 1',
]
position = 0
# Generate "holes"
steps, remainder = divmod(size, chunk)
for _ in range(steps):
bad = randint(1, 5) % 5 == 0
output.append(f'{hex(position)} {hex(chunk)} {"-" if bad else "+"}')
position += chunk
if remainder:
output.append(f'{hex(position)} {hex(remainder)} +')
# Save map
map_path.write_text('\n'.join(output), encoding='utf-8')
def get_ddrescue_settings(settings_menu) -> list:
"""Get ddrescue settings from menu selections, returns list."""
settings = []
# Check menu selections
for name, details in settings_menu.options.items():
if name == '--skip-size':
continue
if details['Selected']:
if 'Value' in details:
settings.append(f'{name}={details["Value"]}')
else:
settings.append(name)
# Done
return settings
def finalize_recovery(state: State, dry_run: bool = True) -> None:
"""Show recovery finalization options and run selected functions."""
options = (
'Relocate Backup GPT',
'Zero-fill Gaps',
'Zero-fill Extra Space',
)
# Get destination size
dest_size = -1
if hasattr(state.destination, 'size'):
# hw_disk.Disk
dest_size = state.destination.size
if hasattr(state.destination, 'stat'):
# pathlib.Path
dest_size = state.destination.stat().st_size
# Run checks to disable item(s)
whole_disk = bool(
len(state.block_pairs) == 1
and not state.source.parent
)
disable_gpt_option = not bool(
## Breakdown of below tests:
## Only offer this option when cloning a whole, non-child device
## where the source is using a GUID_Partition_Table
## and the source is smaller than the destination
whole_disk
and str(state.source.raw_details.get('pttype', 'Unknown')).lower() == 'gpt'
and state.source.size < dest_size
)
# Build menu
menu = cli.Menu(title=ansi.color_string('ddrescue TUI: Finalization', 'GREEN'))
menu.separator = ' '
menu.add_action('Start')
menu.add_action('Quit')
for name in options:
details = {'Selected': True}
if 'GPT' in name and disable_gpt_option:
details['Disabled'] = True
details['Selected'] = False
if state.mode == 'Image':
details['Disabled'] = True
details['Selected'] = False
menu.add_option(name, details)
# Show menu
selection = menu.advanced_select()
if 'Quit' in selection:
return
# Run functions
if menu.options['Zero-fill Gaps']['Selected']:
zero_fill_gaps(
state,
dest_size=dest_size,
dry_run=dry_run,
extend_to_end=menu.options['Zero-fill Extra Space']['Selected'],
)
if menu.options['Relocate Backup GPT']['Selected']:
# NOTE: This needs to be run last to avoid corrupting/erasing the backup GPT
relocate_backup_gpt(state, dry_run=dry_run)
def is_missing_source_or_destination(state) -> bool:
"""Check if source or destination dissapeared, returns bool."""
missing = False
items = {
'Source': state.source,
'Destination': state.destination,
}
# Check items
for name, item in items.items():
if not item:
continue
if hasattr(item, 'path'):
if not item.path.exists():
missing = True
cli.print_error(f'{name} disappeared')
elif hasattr(item, 'exists'):
if not item.exists():
missing = True
cli.print_error(f'{name} disappeared')
else:
LOG.error('Unknown %s type: %s', name, item)
# Update top panes
state.update_top_panes()
# Done
return missing
def main() -> None:
"""Main function for ddrescue TUI."""
try:
args = argparse_helper()
except SystemExit:
print('')
cli.pause('Press Enter to exit...')
raise
# Log setup
log_path = log.format_log_path(log_name='main', sub_dir='ddrescue-TUI')
log.update_log_path(
dest_dir=log_path.parent,
dest_name=log_path.stem,
keep_history=False,
timestamp=False,
)
LOG.info('ddrescue-tui Start')
# Check if running inside tmux
if 'TMUX' not in os.environ:
LOG.error('tmux session not found')
raise RuntimeError('tmux session not found')
# Init
state = State(log_dir=log_path.parent)
try:
state.init_recovery(args)
except (FileNotFoundError, std.GenericAbort):
is_missing_source_or_destination(state)
cli.abort()
# Show menu
main_menu = menus.main()
settings_menu = menus.settings(state.mode)
while True:
selection = main_menu.advanced_select()
# Change settings
if 'Change settings' in selection[0]:
while True:
selection = settings_menu.settings_select()
if 'Load Preset' in selection:
# Rebuild settings menu using preset
settings_menu = menus.settings(state.mode, silent=False)
else:
break
# Detect drives
if 'Detect drives' in selection[0]:
cli.clear_screen()
cli.print_warning(DETECT_DRIVES_NOTICE)
if cli.ask('Are you sure you proceed?'):
cli.print_standard('Forcing controllers to rescan for devices...')
cmd = 'echo "- - -" | sudo tee /sys/class/scsi_host/host*/scan'
exe.run_program([cmd], check=False, shell=True)
if source_or_destination_changed(state):
cli.abort()
# Start recovery
if 'Start' in selection:
cli.clear_screen()
run_recovery(state, main_menu, settings_menu, dry_run=args['--dry-run'])
# Quit
if 'Quit' in selection:
total_percent = state.get_percent_recovered()
# Confirm exit if recovery is less than 100%
if total_percent < 100:
cli.print_warning('Recovery is less than 100%')
if not cli.ask('Are you sure you want to quit?'):
continue
finalize_recovery(state, dry_run=args['--dry-run'])
break
# Save results to log
LOG.info('')
for line in state.generate_report():
LOG.info(' %s', ansi.strip_colors(line))
def relocate_backup_gpt(state: State, dry_run: bool = True) -> None:
"""Relocate backup GPT on the destination if applicable and approved."""
cmd = ['sudo', 'sfdisk', '--relocate', 'gpt-bak-std', state.destination.path]
state.destination.update_details(skip_children=False)
# Safety checks
## Breakdown of below tests:
## Only offer this option when cloning a whole, non-child device
## where the source is smaller than the destination
## and both the source and destination are using a GUID_Partition_Table
if not (
len(state.block_pairs) == 1
and str(state.destination.raw_details.get('pttype', 'Unknown')).lower() == 'gpt'
and state.source.size < state.destination.size
and not state.source.parent
and str(state.source.raw_details.get('pttype', 'Unknown')).lower() == 'gpt'
):
LOG.warning('Refusing to attempt a backup GPT relocation.')
return
# Dry run
if dry_run:
cli.print_standard(f'Dry-run: Relocate GPT with command: {cmd}')
return
# Relocate GPT data
proc = exe.run_program(cmd, check=False)
if proc.returncode:
cli.print_error('ERROR: Failed to relocate backup GPT.')
LOG.error('sfdisk result: %s, %s', proc.stdout, proc.stderr)
def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
"""Run ddrescue using passed settings."""
cmd = build_ddrescue_cmd(block_pair, pass_name, settings)
poweroff_source_after_idle = True
state.update_progress_pane('Active')
state.ui.clear_current_pane()
state.ui.clear_on_resize = True
warning_message = ''
def _poweroff_source_drive(idle_minutes) -> None:
"""Power off source drive after a while."""
source_dev = state.source.path
# Bail early
if PLATFORM == 'Darwin':
return
# Sleep
for i in range(1, idle_minutes*60, 1):
if not poweroff_source_after_idle:
# Countdown canceled, exit without powering-down drives
return
if i % 60 == 0:
cli.print_warning(
f'Powering off source in {int((idle_minutes*60-i)/60)} minutes...',
)
std.sleep(1)
# Power off drive
cmd = ['sudo', 'hdparm', '-Y', source_dev]
proc = exe.run_program(cmd, check=False)
if proc.returncode:
cli.print_error(f'Failed to poweroff source {source_dev}')
else:
cli.print_warning(f'Powered off source {source_dev}')
cli.print_standard(
'Press Enter to return to main menu...', end='', flush=True,
)
def _update_smart_panes() -> None:
"""Update SMART panes every 30 seconds."""
now = datetime.datetime.now(tz=TIMEZONE).strftime('%Y-%m-%d %H:%M %Z')
for dev_str in ('source', 'destination'):
dev = getattr(state, dev_str)
# Safety check
if not hasattr(dev, 'attributes'):
continue
# Update SMART data
out_path = f'{state.log_dir}/smart_{dev_str}.out'
update_smart_details(dev)
with open(out_path, 'w', encoding='utf-8') as _f:
_f.write(
ansi.color_string(
['SMART Attributes', f'Updated: {now}\n'],
['BLUE', 'YELLOW'],
sep='\t\t',
),
)
_f.write('\n'.join(dev.generate_report(header=False)))
# Dry run
if dry_run:
LOG.info('ddrescue cmd: %s', cmd)
return
# Start ddrescue and ddrescueview (if enabled)
proc = exe.popen_program(cmd)
if (
block_pair.view_map
and (not block_pair.view_proc or block_pair.view_proc.poll() is not None)
):
block_pair.view_proc = exe.popen_program(
['ddrescueview', '-r', '5s', block_pair.map_path],
pipe=True,
)
# ddrescue loop
_i = 0
while True:
if _i % 30 == 0:
# Update SMART pane
_update_smart_panes()
# Check destination
warning_message = check_destination_health(state.destination)
if warning_message:
# Error detected on destination, stop recovery
proc.terminate()
cli.print_error(warning_message)
break
_i += 1
# Update progress
block_pair.update_progress(pass_name)
state.update_progress_pane('Active')
# Check if complete
try:
proc.wait(timeout=1)
break
except KeyboardInterrupt:
# Wait a bit to let ddrescue exit safely
LOG.warning('ddrescue stopped by user')
warning_message = 'Aborted'
std.sleep(2)
proc.terminate()
break
except subprocess.TimeoutExpired:
# Continue to next loop to update panes
pass
else:
# Done
std.sleep(1)
break
# Update progress
# NOTE: Using 'Active' here to avoid flickering between block pairs
block_pair.update_progress(pass_name)
state.update_progress_pane('Active')
state.ui.clear_on_resize = False
# Check result
if proc.poll():
# True if return code is non-zero (poll() returns None if still running)
poweroff_thread = exe.start_thread(
_poweroff_source_drive,
[cfg.ddrescue.DRIVE_POWEROFF_TIMEOUT],
)
warning_message = 'Error(s) encountered, see message above'
state.update_top_panes()
if warning_message:
cli.print_standard(' ')
cli.print_standard(' ')
cli.print_error('DDRESCUE PROCESS HALTED')
cli.print_standard(' ')
cli.print_warning(warning_message)
# Needs attention?
if str(proc.poll()) != '0':
state.update_progress_pane('NEEDS ATTENTION')
cli.pause('Press Enter to return to main menu...')
# Stop source poweroff countdown
cli.print_standard('Stopping device poweroff countdown...', flush=True)
poweroff_source_after_idle = False
poweroff_thread.join() # type: ignore[reportUnboundVariable]
# Done
raise std.GenericAbort()
def run_recovery(state: State, main_menu, settings_menu, dry_run=True) -> None:
"""Run recovery passes."""
atexit.register(state.save_debug_reports)
attempted_recovery = False
auto_continue = False
# Bail early
if is_missing_source_or_destination(state):
cli.print_standard('')
cli.pause('Press Enter to return to main menu...')
return
if source_or_destination_changed(state):
cli.print_standard('')
cli.abort()
# Get settings
for name, details in main_menu.toggles.items():
if 'Auto continue' in name and details['Selected']:
auto_continue = True
if 'Retry' in name and details['Selected']:
details['Selected'] = False
state.retry_all_passes()
# Start SMART/Journal
state.ui.add_info_pane(
percent=50,
update_layout=False,
watch_file=f'{state.log_dir}/smart_source.out',
)
if hasattr(state.destination, 'attributes'):
state.ui.add_info_pane(
percent=50,
update_layout=False,
watch_file=f'{state.log_dir}/smart_destination.out',
)
if PLATFORM == 'Linux':
state.ui.add_worker_pane(lines=4, cmd='journal-datarec-monitor')
state.ui.set_current_pane_height(DDRESCUE_OUTPUT_HEIGHT)
# Run pass(es)
for pass_name in ('read-skip', 'read-full', 'trim', 'scrape'):
abort = False
# Skip to next pass
if state.pass_complete(pass_name):
# NOTE: This bypasses auto_continue
state.skip_pass(pass_name)
continue
# Run ddrescue
for pair in state.block_pairs:
if not pair.pass_complete(pass_name):
attempted_recovery = True
state.mark_started()
try:
run_ddrescue(state, pair, pass_name, settings_menu, dry_run=dry_run)
except (FileNotFoundError, KeyboardInterrupt, std.GenericAbort):
is_missing_source_or_destination(state)
abort = True
break
# Continue or return to menu
all_complete = state.pass_complete(pass_name)
all_above_threshold = state.pass_above_threshold(pass_name)
if abort or not (all_complete and all_above_threshold and auto_continue):
LOG.warning('Recovery halted')
break
# Stop SMART/Journal
state.ui.remove_all_info_panes()
state.ui.remove_all_worker_panes()
state.ui.clear_current_pane_height()
# Show warning if nothing was done
if not attempted_recovery:
cli.print_warning('No actions performed')
cli.print_standard(' ')
cli.pause('Press Enter to return to main menu...')
# Done
state.save_debug_reports()
atexit.unregister(state.save_debug_reports)
state.update_progress_pane('Idle')
def source_or_destination_changed(state) -> bool:
"""Verify the source and destination objects are still valid."""
changed = False
# Compare objects
for obj in (state.source, state.destination):
if not obj:
changed = True
elif hasattr(obj, 'exists'):
# Assuming dest path
changed = changed or not obj.exists()
elif isinstance(obj, hw_disk.Disk):
compare_dev = hw_disk.Disk(obj.path)
for key in ('model', 'serial'):
changed = changed or getattr(obj, key) != getattr(compare_dev, key)
# Update top panes
state.update_top_panes()
# Done
if changed:
cli.print_error('Source and/or Destination changed')
return changed
def zero_fill_gaps(
state: State,
dest_size: int,
dry_run: bool = True,
extend_to_end: bool = False,
) -> None:
"""Zero-fill any gaps on the destination."""
#fake_settings_menu = menus.settings(state.mode)
full_disk_clone = bool(
state.mode == 'Clone'
and len(state.block_pairs) == 1
and state.source.path == state.block_pairs[0].source
)
larger_destination = state.source.size < dest_size
percent_recovered = state.get_percent_recovered()
# Bail early
if percent_recovered == 100 and not (larger_destination and extend_to_end):
return
for block_pair in state.block_pairs:
domain_size = block_pair.size
if (full_disk_clone and state.source.size < state.destination.size):
domain_size = dest_size
larger_destination = True
# Prep zero-fill map file
zero_map_path = block_pair.map_path.with_stem(
f'{block_pair.map_path.stem}_zero-fill',
)
io.copy_file(block_pair.map_path, zero_map_path, overwrite=True)
mark_non_recovered_as_non_tried(zero_map_path)
if full_disk_clone and larger_destination and extend_to_end:
# Extend domain size
with open(zero_map_path, 'a', encoding='utf-8') as f:
f.write(
f'\n{hex(block_pair.size)} '
f'{hex(domain_size - block_pair.size)} ?'
)
# Build cmd
cmd = [
'sudo',
'ddrescue',
'--force',
f'--size={domain_size}',
'--binary-prefixes',
'--complete-only',
'--data-preview=5',
'--odirect',
'--retry-passes=0',
f'--sector-size={block_pair.sector_size}',
'-vvvv',
'/dev/zero',
block_pair.destination,
zero_map_path,
]
# Dry run
if dry_run:
cli.print_standard(f'Zero-fill with command: {cmd}')
return
# Re-run ddrescue to zero-fill gaps
proc = exe.run_program(cmd, check=False, pipe=False)
if proc.returncode:
cli.print_error('ERROR: Failed to zero-fill: {block_pair.destination}')
LOG.error('zero-fill error: %s, %s', proc.stdout, proc.stderr)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -1,109 +0,0 @@
"""WizardKit: ddrescue TUI - State"""
# vim: sts=2 sw=2 ts=2
import atexit
import logging
import pathlib
import plistlib
import re
from wk import exe
from wk.std import PLATFORM
from wk.ui import cli
# STATIC VARIABLES
LOG = logging.getLogger(__name__)
# Functions
def mount_raw_image(path) -> pathlib.Path:
"""Mount raw image using OS specific methods, returns pathlib.Path."""
loopback_path = None
if PLATFORM == 'Darwin':
loopback_path = mount_raw_image_macos(path)
elif PLATFORM == 'Linux':
loopback_path = mount_raw_image_linux(path)
# Check
if not loopback_path:
cli.print_error(f'Failed to mount image: {path}')
# Register unmount atexit
atexit.register(unmount_loopback_device, loopback_path)
# Done
return loopback_path
def mount_raw_image_linux(path) -> pathlib.Path:
"""Mount raw image using losetup, returns pathlib.Path."""
loopback_path = None
# Mount using losetup
cmd = [
'sudo',
'losetup',
'--find',
'--partscan',
'--show',
path,
]
proc = exe.run_program(cmd, check=False)
# Check result
if proc.returncode == 0:
loopback_path = proc.stdout.strip()
# Done
return loopback_path
def mount_raw_image_macos(path) -> pathlib.Path:
"""Mount raw image using hdiutil, returns pathlib.Path."""
loopback_path = None
plist_data = {}
# Mount using hdiutil
# plistdata['system-entities'][{}...]
cmd = [
'hdiutil', 'attach',
'-imagekey', 'diskimage-class=CRawDiskImage',
'-nomount',
'-plist',
'-readonly',
path,
]
proc = exe.run_program(cmd, check=False, encoding=None, errors=None)
# Check result
try:
plist_data = plistlib.loads(proc.stdout)
except plistlib.InvalidFileException:
return None
for dev in plist_data.get('system-entities', []):
dev_path = dev.get('dev-entry', '')
if re.match(r'^/dev/disk\d+$', dev_path):
loopback_path = dev_path
# Done
return loopback_path
def unmount_loopback_device(path) -> None:
"""Unmount loopback device using OS specific methods."""
cmd = []
# Build OS specific cmd
if PLATFORM == 'Darwin':
cmd = ['hdiutil', 'detach', path]
elif PLATFORM == 'Linux':
cmd = ['sudo', 'losetup', '--detach', path]
# Unmount loopback device
exe.run_program(cmd, check=False)
if __name__ == '__main__':
print("This file is not meant to be called directly.")

Some files were not shown because too many files have changed in this diff Show more