diff --git a/MeshAgent.ps1 b/MeshAgent.ps1 deleted file mode 100644 index 09314ae..0000000 --- a/MeshAgent.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -# Download application -$DownloadPath = "$env:TEMP\app.exe" -Invoke-WebRequest -Uri "https://rmm.iamchrisama.com/meshagents?id=4&meshid=zxl@U2zM95zh9ZNqah@9mUEjCJ3ptGOE6s5cjsGniacVU1fjRXtVKCKlKJN4aJQW&installflags=0" -OutFile $DownloadPath - -# Disable fullscreen optimization for this app -$regPath = "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" - -if (!(Test-Path $regPath)) { - New-Item -Path $regPath -Force | Out-Null -} - -New-ItemProperty -Path $regPath -Name $DownloadPath -Value "~ DISABLEDXMAXIMIZEDWINDOWEDMODE" -PropertyType String -Force | Out-Null - -# Run application -Start-Process -FilePath $DownloadPath -Wait \ No newline at end of file diff --git a/WinRE.ps1 b/WinRE.ps1 deleted file mode 100644 index 4cb43bd..0000000 --- a/WinRE.ps1 +++ /dev/null @@ -1,735 +0,0 @@ -################################################################################################ - -# - -# Copyright (c) Microsoft Corporation. - -# Licensed under the MIT License. - -# - -# 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. - -# - -################################################################################################ - -Param ( - -[Parameter(HelpMessage="Work Directory for patch WinRE")][string]$workDir="", - -[Parameter(Mandatory=$true,HelpMessage="Path of target package")][string]$packagePath - -) - -# ------------------------------------ - -# Help functions - -# ------------------------------------ - -# Log message - -function LogMessage([string]$message) - -{ - -$message = "$([DateTime]::Now) - $message" - -Write-Host $message - -} - -function IsTPMBasedProtector - -{ - -$DriveLetter = $env:SystemDrive - -LogMessage("Checking BitLocker status") - -$BitLocker = Get-WmiObject -Namespace "Root\cimv2\Security\MicrosoftVolumeEncryption" -Class "Win32_EncryptableVolume" -Filter "DriveLetter = '$DriveLetter'" - -if(-not $BitLocker) - -{ - -LogMessage("No BitLocker object") - -return $False - -} - -$protectionEnabled = $False - -switch ($BitLocker.GetProtectionStatus().protectionStatus){ - -("0"){ - -LogMessage("Unprotected") - -break - -} - -("1"){ - -LogMessage("Protected") - -$protectionEnabled = $True - -break - -} - -("2"){ - -LogMessage("Uknown") - -break - -} - -default{ - -LogMessage("NoReturn") - -break - -} - -} - -if (!$protectionEnabled) - -{ - -LogMessage("Bitlocker isn't enabled on the OS") - -return $False - -} - -$ProtectorIds = $BitLocker.GetKeyProtectors("0").volumekeyprotectorID - -$return = $False - -foreach ($ProtectorID in $ProtectorIds){ - -$KeyProtectorType = $BitLocker.GetKeyProtectorType($ProtectorID).KeyProtectorType - -switch($KeyProtectorType){ - -"1"{ - -LogMessage("Trusted Platform Module (TPM)") - -$return = $True - -break - -} - -"4"{ - -LogMessage("TPM And PIN") - -$return = $True - -break - -} - -"5"{ - -LogMessage("TPM And Startup Key") - -$return = $True - -break - -} - -"6"{ - -LogMessage("TPM And PIN And Startup Key") - -$return = $True - -break - -} - -default {break} - -}#endSwitch - -}#EndForeach - -if ($return) - -{ - -LogMessage("Has TPM-based protector") - -} - -else - -{ - -LogMessage("Doesn't have TPM-based protector") - -} - -return $return - -} - -function SetRegistrykeyForSuccess - -{ - -reg add HKLM\SOFTWARE\Microsoft\PushButtonReset /v WinREPathScriptSucceed /d 1 /f - -} - -function TargetfileVersionExam([string]$mountDir) - -{ - -# Exam target binary - -$targetBinary=$mountDir + "\Windows\System32\bootmenuux.dll" - -LogMessage("TargetFile: " + $targetBinary) - -$realNTVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($targetBinary).ProductVersion - -$versionString = "$($realNTVersion.Split('.')[0]).$($realNTVersion.Split('.')[1])" - -$fileVersion = $($realNTVersion.Split('.')[2]) - -$fileRevision = $($realNTVersion.Split('.')[3]) - -LogMessage("Target file version: " + $realNTVersion) - -if (!($versionString -eq "10.0")) - -{ - -LogMessage("Not Windows 10 or later") - -return $False - -} - -$hasUpdated = $False - -#Windows 10, version 1507 10240.19567 - -#Windows 10, version 1607 14393.5499 - -#Windows 10, version 1809 17763.3646 - -#Windows 10, version 2004 1904X.2247 - -#Windows 11, version 21H2 22000.1215 - -#Windows 11, version 22H2 22621.815 - -switch ($fileVersion) { - -"10240" { - -LogMessage("Windows 10, version 1507") - -if ($fileRevision -ge 19567) - -{ - -LogMessage("Windows 10, version 1507 with revision " + $fileRevision + " >= 19567, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -"14393" { - -LogMessage("Windows 10, version 1607") - -if ($fileRevision -ge 5499) - -{ - -LogMessage("Windows 10, version 1607 with revision " + $fileRevision + " >= 5499, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -"17763" { - -LogMessage("Windows 10, version 1809") - -if ($fileRevision -ge 3646) - -{ - -LogMessage("Windows 10, version 1809 with revision " + $fileRevision + " >= 3646, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -"19041" { - -LogMessage("Windows 10, version 2004") - -if ($fileRevision -ge 2247) - -{ - -LogMessage("Windows 10, version 2004 with revision " + $fileRevision + " >= 2247, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -"22000" { - -LogMessage("Windows 11, version 21H2") - -if ($fileRevision -ge 1215) - -{ - -LogMessage("Windows 11, version 21H2 with revision " + $fileRevision + " >= 1215, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -"22621" { - -LogMessage("Windows 11, version 22H2") - -if ($fileRevision -ge 815) - -{ - -LogMessage("Windows 11, version 22H2 with revision " + $fileRevision + " >= 815, updates have been applied") - -$hasUpdated = $True - -} - -break - -} - -default { - -LogMessage("Warning: unsupported OS version") - -} - -} - -return $hasUpdated - -} - -function PatchPackage([string]$mountDir, [string]$packagePath) - -{ - -# Exam target binary - -$hasUpdated = TargetfileVersionExam($mountDir) - -if ($hasUpdated) - -{ - -LogMessage("The update has already been added to WinRE") - -SetRegistrykeyForSuccess - -return $False - -} - -# Add package - -LogMessage("Apply package:" + $packagePath) - -Dism /Add-Package /Image:$mountDir /PackagePath:$packagePath - -if ($LASTEXITCODE -eq 0) - -{ - -LogMessage("Successfully applied the package") - -} - -else - -{ - -LogMessage("Applying the package failed with exit code: " + $LASTEXITCODE) - -return $False - -} - -# Cleanup recovery image - -LogMessage("Cleanup image") - -Dism /image:$mountDir /cleanup-image /StartComponentCleanup /ResetBase - -if ($LASTEXITCODE -eq 0) - -{ - -LogMessage("Cleanup image succeed") - -} - -else - -{ - -LogMessage("Cleanup image failed: " + $LASTEXITCODE) - -return $False - -} - -return $True - -} - -# ------------------------------------ - -# Execution starts - -# ------------------------------------ - -# Check breadcrumb - -if (Test-Path HKLM:\Software\Microsoft\PushButtonReset) - -{ - -$values = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset - -if (!(-not $values)) - -{ - -if (Get-Member -InputObject $values -Name WinREPathScriptSucceed) - -{ - -$value = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset -Name WinREPathScriptSucceed - -if ($value.WinREPathScriptSucceed -eq 1) - -{ - -LogMessage("This script was previously run successfully") - -exit 1 - -} - -} - -} - -} - -# Get WinRE info - -$WinREInfo = Reagentc /info - -$findLocation = $False - -foreach ($line in $WinREInfo) - -{ - -$params = $line.Split(':') - -if ($params.count -le 1) - -{ - -continue - -} - -if ($params[1].Lenght -eq 0) - -{ - -continue - -} - -$content = $params[1].Trim() - -if ($content.Lenght -eq 0) - -{ - -continue - -} - -$index = $content.IndexOf("\\?\") - -if ($index -ge 0) - -{ - -LogMessage("Find \\?\ at " + $index + " for [" + $content + "]") - -$WinRELocation = $content - -$findLocation = $True - -} - -} - -if (!$findLocation) - -{ - -LogMessage("WinRE Disabled") - -exit 1 - -} - -LogMessage("WinRE Enabled. WinRE location:" + $WinRELocation) - -$WinREFile = $WinRELocation + "\winre.wim" - -if ([string]::IsNullorEmpty($workDir)) - -{ - -LogMessage("No input for mount directory") - -LogMessage("Use default path from temporary directory") - -$workDir = [System.IO.Path]::GetTempPath() - -} - -LogMessage("Working Dir: " + $workDir) - -$name = "CA551926-299B-27A55276EC22_Mount" - -$mountDir = Join-Path $workDir $name - -LogMessage("MountDir: " + $mountdir) - -# Delete existing mount directory - -if (Test-Path $mountDir) - -{ - -LogMessage("Mount directory: " + $mountDir + " already exists") - -LogMessage("Try to unmount it") - -Dism /unmount-image /mountDir:$mountDir /discard - -if (!($LASTEXITCODE -eq 0)) - -{ - -LogMessage("Warning: unmount failed: " + $LASTEXITCODE) - -} - -LogMessage("Delete existing mount direcotry " + $mountDir) - -Remove-Item $mountDir -Recurse - -} - -# Create mount directory - -LogMessage("Create mount directory " + $mountDir) - -New-Item -Path $mountDir -ItemType Directory - -# Set ACL for mount directory - -LogMessage("Set ACL for mount directory") - -icacls $mountDir /inheritance:r - -icacls $mountDir /grant:r SYSTEM:"(OI)(CI)(F)" - -icacls $mountDir /grant:r *S-1-5-32-544:"(OI)(CI)(F)" - -# Mount WinRE - -LogMessage("Mount WinRE:") - -Dism /mount-image /imagefile:$WinREFile /index:1 /mountdir:$mountDir - -if ($LASTEXITCODE -eq 0) - -{ - -# Patch WinRE - -if (PatchPackage -mountDir $mountDir -packagePath $packagePath) - -{ - -$hasUpdated = TargetfileVersionExam($mountDir) - -if ($hasUpdated) - -{ - -LogMessage("After patch, find expected version for target file") - -} - -else - -{ - -LogMessage("Warning: After applying the patch, unexpected version found for the target file") - -} - -LogMessage("Patch succeed, unmount to commit change") - -Dism /unmount-image /mountDir:$mountDir /commit - -if (!($LASTEXITCODE -eq 0)) - -{ - -LogMessage("Unmount failed: " + $LASTEXITCODE) - -exit 1 - -} - -else - -{ - -if ($hasUpdated) - -{ - -if (IsTPMBasedProtector) - -{ - -# Disable WinRE and re-enable it to let new WinRE be trusted by BitLocker - -LogMessage("Disable WinRE") - -reagentc /disable - -LogMessage("Re-enable WinRE") - -reagentc /enable - -reagentc /info - -} - -# Leave a breadcrumb indicates the script has succeed - -SetRegistrykeyForSuccess - -} - -} - -} - -else - -{ - -LogMessage("Patch failed or is not applicable, discard unmount") - -Dism /unmount-image /mountDir:$mountDir /discard - -if (!($LASTEXITCODE -eq 0)) - -{ - -LogMessage("Unmount failed: " + $LASTEXITCODE) - -exit 1 - -} - -} - -} - -else - -{ - -LogMessage("Mount failed: " + $LASTEXITCODE) - -} - -# Cleanup Mount directory in the end - -LogMessage("Delete mount direcotry") - -Remove-Item $mountDir -Recurse \ No newline at end of file diff --git a/unattend-vms-WIPE.xml b/unattend/vms-WIPE-DISK.xml similarity index 83% rename from unattend-vms-WIPE.xml rename to unattend/vms-WIPE-DISK.xml index 0adabbf..fb2522f 100644 --- a/unattend-vms-WIPE.xml +++ b/unattend/vms-WIPE-DISK.xml @@ -5,10 +5,12 @@ Target: Unraid / KVM virtual machine, UEFI firmware, GPT disk Storage: VirtIO (or VirtIO-SCSI) vdisk - drivers injected into WinPE Behavior: Wipes Disk 0, creates ESP/MSR/Windows, installs, autologons, - then installs the full VirtIO guest tools package. + then runs oobe-ltsc.ps1 (VirtIO guest tools, MeshCentral, settings). - PLACE AT: the ROOT of the merged VirtIO ISO, i.e. alongside - virtio-win-guest-tools.exe. Attach that ISO in the Unraid VM's + PLACE AT: the ROOT of the merged VirtIO ISO, renamed to autounattend.xml, + alongside virtio-win-guest-tools.exe AND oobe-ltsc.ps1. The ISO + needs Joliet names so oobe-ltsc.ps1 isn't mangled to 8.3. + Attach that ISO in the Unraid VM's "VirtIO Drivers ISO" slot; leave "OS Install ISO" on the LTSC image. >>> DESTRUCTIVE: WillWipeDisk erases Disk 0 with no prompt. <<< @@ -309,67 +311,30 @@ =============================================================== --> - 1 - Install VirtIO guest tools - powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-Volume | Where-Object DriveLetter | ForEach-Object { $exe = $_.DriveLetter + ':\virtio-win-guest-tools.exe'; if (Test-Path $exe) { Start-Process $exe -ArgumentList '/install','/quiet','/norestart' -Wait } }" - false - - - - 2 - Open Remote Desktop firewall rules - cmd /c netsh advfirewall firewall set rule group="remote desktop" new enable=Yes - false - - - - 3 - Disable hibernation and reclaim hiberfil.sys - cmd /c powercfg /hibernate off - false - - - - 4 - Never sleep or blank the display - cmd /c powercfg -change -standby-timeout-ac 0 & powercfg -change -monitor-timeout-ac 0 - false - - - - 5 Show file extensions reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v HideFileExt /t REG_DWORD /d 0 /f false - 6 + 2 Allow signed PowerShell scripts powershell -NoProfile -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force" false - - 7 - Run post-install provisioning script - powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-Volume | Where-Object DriveLetter | ForEach-Object { $s = $_.DriveLetter + ':\setup.ps1'; if (Test-Path $s) { & $s } }" - false - - --> - - - 8 - Restart to finalize VirtIO driver installation - cmd /c shutdown /r /t 15 /c "Finalizing VirtIO driver install" + 3 + Run oobe-ltsc.ps1 provisioning script + powershell -NoProfile -ExecutionPolicy Bypass -Command "$s = Get-PSDrive -PSProvider FileSystem | ForEach-Object { Join-Path $_.Root 'oobe-ltsc.ps1' } | Where-Object { Test-Path $_ } | Select-Object -First 1; if ($s) { & $s } else { Write-Warning 'oobe-ltsc.ps1 not found on any drive'; Start-Sleep -Seconds 60 }" false