Reorganize project: move answer file to unattend/, drop unused scripts
- Move unattend-vms-WIPE.xml to unattend/vms-WIPE-DISK.xml; it now runs oobe-ltsc.ps1 as its final first-logon command - Remove MeshAgent.ps1 (folded into oobe-ltsc.ps1) and WinRE.ps1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>master
parent
59cb60ffb1
commit
b9a8ded252
|
|
@ -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
|
||||
735
WinRE.ps1
735
WinRE.ps1
|
|
@ -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
|
||||
|
|
@ -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 @@
|
|||
=============================================================== -->
|
||||
<FirstLogonCommands>
|
||||
|
||||
<!-- Installs balloon, vioserial, qxldod video, and the QEMU guest
|
||||
agent. Scans every drive for the installer rather than assuming
|
||||
a letter, since the VirtIO disc moves around post-install. -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Description>Install VirtIO guest tools</Description>
|
||||
<CommandLine>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 } }"</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Description>Open Remote Desktop firewall rules</Description>
|
||||
<CommandLine>cmd /c netsh advfirewall firewall set rule group="remote desktop" new enable=Yes</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<Description>Disable hibernation and reclaim hiberfil.sys</Description>
|
||||
<CommandLine>cmd /c powercfg /hibernate off</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>4</Order>
|
||||
<Description>Never sleep or blank the display</Description>
|
||||
<CommandLine>cmd /c powercfg -change -standby-timeout-ac 0 & powercfg -change -monitor-timeout-ac 0</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>5</Order>
|
||||
<Description>Show file extensions</Description>
|
||||
<CommandLine>reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v HideFileExt /t REG_DWORD /d 0 /f</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>6</Order>
|
||||
<Order>2</Order>
|
||||
<Description>Allow signed PowerShell scripts</Description>
|
||||
<CommandLine>powershell -NoProfile -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force"</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
<!--
|
||||
EDIT: your provisioning hook. Drop setup.ps1 into the merged ISO
|
||||
alongside this file and it'll be found the same way.
|
||||
|
||||
<!-- Provisioning: oobe-ltsc.ps1 sits at the root of the merged ISO
|
||||
next to this file. Scans every drive for it rather than assuming
|
||||
a letter, since the VirtIO disc moves around post-install.
|
||||
The script installs the VirtIO guest tools, MeshCentral agent,
|
||||
power/RDP/SSH settings, then restarts the VM itself, so this
|
||||
must stay the LAST command. Log: C:\ProgramData\OOBE\oobe-ltsc.log -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<Description>Run post-install provisioning script</Description>
|
||||
<CommandLine>powershell -NoProfile -ExecutionPolicy Bypass -Command "Get-Volume | Where-Object DriveLetter | ForEach-Object { $s = $_.DriveLetter + ':\setup.ps1'; if (Test-Path $s) { & $s } }"</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
-->
|
||||
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>8</Order>
|
||||
<Description>Restart to finalize VirtIO driver installation</Description>
|
||||
<CommandLine>cmd /c shutdown /r /t 15 /c "Finalizing VirtIO driver install"</CommandLine>
|
||||
<Order>3</Order>
|
||||
<Description>Run oobe-ltsc.ps1 provisioning script</Description>
|
||||
<CommandLine>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 }"</CommandLine>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
|
||||
Loading…
Reference in New Issue