Compare commits
4 commits
8a65313039
...
3b975af2ba
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b975af2ba | |||
| b8fe43fd8f | |||
| 8495d62a06 | |||
| 4a306b56d9 |
5 changed files with 145 additions and 10 deletions
83
config/unattend.xml
Executable file
83
config/unattend.xml
Executable file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||||
|
<settings pass="disabled">
|
||||||
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<UserData>
|
||||||
|
<ProductKey>
|
||||||
|
<Key />
|
||||||
|
</ProductKey>
|
||||||
|
</UserData>
|
||||||
|
<RunSynchronous>
|
||||||
|
<RunSynchronousCommand wcm:action="add">
|
||||||
|
<Order>1</Order>
|
||||||
|
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassTPMCheck /t REG_DWORD /d 1 /f</Path>
|
||||||
|
</RunSynchronousCommand>
|
||||||
|
<RunSynchronousCommand wcm:action="add">
|
||||||
|
<Order>2</Order>
|
||||||
|
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassSecureBootCheck /t REG_DWORD /d 1 /f</Path>
|
||||||
|
</RunSynchronousCommand>
|
||||||
|
<RunSynchronousCommand wcm:action="add">
|
||||||
|
<Order>3</Order>
|
||||||
|
<Path>reg add HKLM\SYSTEM\Setup\LabConfig /v BypassRAMCheck /t REG_DWORD /d 1 /f</Path>
|
||||||
|
</RunSynchronousCommand>
|
||||||
|
</RunSynchronous>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
<settings pass="specialize">
|
||||||
|
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<RunSynchronous>
|
||||||
|
<RunSynchronousCommand wcm:action="add">
|
||||||
|
<Order>1</Order>
|
||||||
|
<Path>reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE /v BypassNRO /t REG_DWORD /d 1 /f</Path>
|
||||||
|
</RunSynchronousCommand>
|
||||||
|
</RunSynchronous>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
<settings pass="oobeSystem">
|
||||||
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<OOBE>
|
||||||
|
<ProtectYourPC>3</ProtectYourPC>
|
||||||
|
</OOBE>
|
||||||
|
<UserAccounts>
|
||||||
|
<LocalAccounts>
|
||||||
|
<LocalAccount wcm:action="add">
|
||||||
|
<Name>NEWUSERNAME</Name>
|
||||||
|
<DisplayName>NEWUSERNAME</DisplayName>
|
||||||
|
<Group>Administrators;Power Users</Group>
|
||||||
|
<Password>
|
||||||
|
<Value>UABhAHMAcwB3AG8AcgBkAA==</Value>
|
||||||
|
<PlainText>false</PlainText>
|
||||||
|
</Password>
|
||||||
|
</LocalAccount>
|
||||||
|
</LocalAccounts>
|
||||||
|
</UserAccounts>
|
||||||
|
<FirstLogonCommands>
|
||||||
|
<SynchronousCommand wcm:action="add">
|
||||||
|
<Order>1</Order>
|
||||||
|
<CommandLine>net user "NEWUSERNAME" /expires:never</CommandLine>
|
||||||
|
</SynchronousCommand>
|
||||||
|
<SynchronousCommand wcm:action="add">
|
||||||
|
<Order>2</Order>
|
||||||
|
<CommandLine>net user "NEWUSERNAME" /passwordchg:yes</CommandLine>
|
||||||
|
</SynchronousCommand>
|
||||||
|
<SynchronousCommand wcm:action="add">
|
||||||
|
<Order>3</Order>
|
||||||
|
<CommandLine>net user "NEWUSERNAME" /passwordreq:no</CommandLine>
|
||||||
|
</SynchronousCommand>
|
||||||
|
</FirstLogonCommands>
|
||||||
|
</component>
|
||||||
|
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<InputLocale>00000409</InputLocale>
|
||||||
|
<SystemLocale>en-US</SystemLocale>
|
||||||
|
<UserLocale>en-US</UserLocale>
|
||||||
|
<UILanguage>en-US</UILanguage>
|
||||||
|
<UILanguageFallback></UILanguageFallback>
|
||||||
|
</component>
|
||||||
|
<component name="Microsoft-Windows-SecureStartup-FilterDriver" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<PreventDeviceEncryption>true</PreventDeviceEncryption>
|
||||||
|
</component>
|
||||||
|
<component name="Microsoft-Windows-EnhancedStorage-Adm" processorArchitecture="amd64" language="neutral" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS">
|
||||||
|
<TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
</unattend>
|
||||||
|
|
@ -38,6 +38,8 @@ use core::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
fs::{File, create_dir_all},
|
||||||
|
io::Write,
|
||||||
iter::zip,
|
iter::zip,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
|
@ -51,11 +53,12 @@ use ratatui::{
|
||||||
style::Color,
|
style::Color,
|
||||||
};
|
};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{set_username::InputUsername, wim_scan::WimScan},
|
components::{set_username::InputUsername, wim_scan::WimScan},
|
||||||
state::{ScanType, State},
|
state::{ScanType, State},
|
||||||
|
wim::gen_unattend_xml,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
|
@ -195,7 +198,7 @@ impl App {
|
||||||
// Get image info
|
// Get image info
|
||||||
let wim_sources = self.state.wim_sources.lock().unwrap();
|
let wim_sources = self.state.wim_sources.lock().unwrap();
|
||||||
let wim_file = wim_sources.get_file(self.state.wim_file_index.unwrap());
|
let wim_file = wim_sources.get_file(self.state.wim_file_index.unwrap());
|
||||||
let wim_index = format!("{}", self.state.wim_image_index.unwrap());
|
let wim_index = self.state.wim_image_index.unwrap() + 1; // wimapply uses 1-based index
|
||||||
|
|
||||||
// Add actions
|
// Add actions
|
||||||
let disk_list = self.state.disk_list.lock().unwrap();
|
let disk_list = self.state.disk_list.lock().unwrap();
|
||||||
|
|
@ -206,7 +209,12 @@ impl App {
|
||||||
let dest_path = format!("{}:\\", disk.get_part_letter(num_parts - 1));
|
let dest_path = format!("{}:\\", disk.get_part_letter(num_parts - 1));
|
||||||
self.tasks.add(TaskType::CommandWait(
|
self.tasks.add(TaskType::CommandWait(
|
||||||
wimlib_imagex,
|
wimlib_imagex,
|
||||||
vec![String::from("apply"), wim_file.path, wim_index, dest_path],
|
vec![
|
||||||
|
String::from("apply"),
|
||||||
|
wim_file.path,
|
||||||
|
format!("{wim_index}"),
|
||||||
|
dest_path,
|
||||||
|
],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -215,6 +223,8 @@ impl App {
|
||||||
popup::Type::Info,
|
popup::Type::Info,
|
||||||
String::from("Updating boot configuration"),
|
String::from("Updating boot configuration"),
|
||||||
))?;
|
))?;
|
||||||
|
let wim_sources = self.state.wim_sources.lock().unwrap();
|
||||||
|
let wim_file = wim_sources.get_file(self.state.wim_file_index.unwrap());
|
||||||
|
|
||||||
// Get System32 path
|
// Get System32 path
|
||||||
let system32 = get_system32_path(&self.action_tx);
|
let system32 = get_system32_path(&self.action_tx);
|
||||||
|
|
@ -244,10 +254,15 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create boot files
|
// Create boot files
|
||||||
|
let safe_mode = if wim_file.is_backup {
|
||||||
|
boot::SafeMode::Enable
|
||||||
|
} else {
|
||||||
|
boot::SafeMode::Disable
|
||||||
|
};
|
||||||
for task in boot::configure_disk(
|
for task in boot::configure_disk(
|
||||||
&letter_boot,
|
&letter_boot,
|
||||||
&letter_os,
|
&letter_os,
|
||||||
boot::SafeMode::Enable,
|
safe_mode,
|
||||||
&system32,
|
&system32,
|
||||||
&table_type,
|
&table_type,
|
||||||
) {
|
) {
|
||||||
|
|
@ -265,6 +280,29 @@ impl App {
|
||||||
)))?;
|
)))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add unattend.xml (if applicable)
|
||||||
|
if let Some(username) = &self.state.username
|
||||||
|
&& !wim_file.is_backup
|
||||||
|
{
|
||||||
|
let unattend_xml_str = gen_unattend_xml(username);
|
||||||
|
let panther_path = format!("{letter_os}:\\Windows\\Panther");
|
||||||
|
if create_dir_all(PathBuf::from(&panther_path)).is_ok() {
|
||||||
|
if let Ok(mut unattend_xml) =
|
||||||
|
File::create(format!("{panther_path}\\unattend.xml"))
|
||||||
|
{
|
||||||
|
if unattend_xml.write_all(unattend_xml_str.as_bytes()).is_ok() {
|
||||||
|
info!("Created unattend.xml with username set to: {username}");
|
||||||
|
} else {
|
||||||
|
error!("Failed to write to unattend.xml");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Failed to create unattend.xml");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Failed to create Panther dir");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::ScanDisks => {
|
Mode::ScanDisks => {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ pub fn connect_network_share(
|
||||||
lpRemoteName: remote_name.as_c_str().as_ptr() as *mut u8,
|
lpRemoteName: remote_name.as_c_str().as_ptr() as *mut u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
let username = to_cstr(username);
|
let username = format!("{server}\\{username}");
|
||||||
|
let username = to_cstr(&username);
|
||||||
let password = to_cstr(password);
|
let password = to_cstr(password);
|
||||||
|
|
||||||
// mount
|
// mount
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ pub fn scan_network_share(config: Config, wim_sources_arc: Arc<Mutex<WimSources>
|
||||||
if let Ok(item) = item
|
if let Ok(item) = item
|
||||||
&& item.file_name().to_string_lossy().ends_with(".wim")
|
&& item.file_name().to_string_lossy().ends_with(".wim")
|
||||||
&& let Some(path_str) = item.path().to_str()
|
&& let Some(path_str) = item.path().to_str()
|
||||||
&& let Ok(new_source) = parse_wim_file(path_str, true)
|
&& let Ok(new_source) = parse_wim_file(path_str, false)
|
||||||
// Assuming all network sources are installers
|
// Assuming all network sources are installers
|
||||||
{
|
{
|
||||||
wim_files.push(new_source);
|
wim_files.push(new_source);
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ use xml::reader::{EventReader, XmlEvent};
|
||||||
|
|
||||||
use core::system::disk::bytes_to_string;
|
use core::system::disk::bytes_to_string;
|
||||||
|
|
||||||
|
const UNATTEND_XML: &str = include_str!("../../config/unattend.xml");
|
||||||
|
|
||||||
static WIMINFO_EXE: LazyLock<String> = LazyLock::new(|| {
|
static WIMINFO_EXE: LazyLock<String> = LazyLock::new(|| {
|
||||||
let program_files =
|
let program_files =
|
||||||
PathBuf::from(env::var("PROGRAMFILES").expect("Failed to resolve %PROGRAMFILES%"));
|
PathBuf::from(env::var("PROGRAMFILES").expect("Failed to resolve %PROGRAMFILES%"));
|
||||||
|
|
@ -176,13 +178,20 @@ impl WimSources {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file(&self, index: usize) -> WimFile {
|
pub fn get_file(&self, index: usize) -> WimFile {
|
||||||
|
let rel_index: usize;
|
||||||
let num_local = self.local.len();
|
let num_local = self.local.len();
|
||||||
let index = if index < num_local {
|
let mut use_local = true;
|
||||||
index
|
if index < num_local {
|
||||||
|
rel_index = index;
|
||||||
} else {
|
} else {
|
||||||
index - num_local
|
rel_index = index - num_local;
|
||||||
|
use_local = false;
|
||||||
};
|
};
|
||||||
self.local.get(index).unwrap().clone()
|
if use_local {
|
||||||
|
self.local.get(rel_index).unwrap().clone()
|
||||||
|
} else {
|
||||||
|
self.network.get(rel_index).unwrap().clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_file_list(&self) -> Vec<WimFile> {
|
pub fn get_file_list(&self) -> Vec<WimFile> {
|
||||||
|
|
@ -222,6 +231,10 @@ impl WimSources {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gen_unattend_xml(username: &str) -> String {
|
||||||
|
UNATTEND_XML.replace("NEWUSERNAME", username)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_wim_xml(wim_file: &str) -> std::io::Result<File> {
|
fn get_wim_xml(wim_file: &str) -> std::io::Result<File> {
|
||||||
let tmp_file = NamedTempFile::new()?;
|
let tmp_file = NamedTempFile::new()?;
|
||||||
let _ = Command::new(&*WIMINFO_EXE)
|
let _ = Command::new(&*WIMINFO_EXE)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue