diff --git a/src/Ookii.AnswerFile.Tests/AnswerFileGeneratorTests.cs b/src/Ookii.AnswerFile.Tests/AnswerFileGeneratorTests.cs index dda8871..e276981 100644 --- a/src/Ookii.AnswerFile.Tests/AnswerFileGeneratorTests.cs +++ b/src/Ookii.AnswerFile.Tests/AnswerFileGeneratorTests.cs @@ -238,4 +238,17 @@ public void TestGenerateDomainOnly() AnswerFileGenerator.Generate(actualPath, options); CheckFilesEqual(expectedPath, actualPath); } + + [TestMethod] + public void TestGenerateAdministratorPassword() + { + var (actualPath, expectedPath) = GetPaths(); + var options = new AnswerFileOptions + { + AdministratorPassword = "Password123" + }; + + AnswerFileGenerator.Generate(actualPath, options); + CheckFilesEqual(expectedPath, actualPath); + } } diff --git a/src/Ookii.AnswerFile.Tests/Ookii.AnswerFile.Tests.csproj b/src/Ookii.AnswerFile.Tests/Ookii.AnswerFile.Tests.csproj index 7579362..c50e758 100644 --- a/src/Ookii.AnswerFile.Tests/Ookii.AnswerFile.Tests.csproj +++ b/src/Ookii.AnswerFile.Tests/Ookii.AnswerFile.Tests.csproj @@ -57,6 +57,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/Ookii.AnswerFile.Tests/expected/TestGenerateAdministratorPassword.xml b/src/Ookii.AnswerFile.Tests/expected/TestGenerateAdministratorPassword.xml new file mode 100644 index 0000000..4d097e6 --- /dev/null +++ b/src/Ookii.AnswerFile.Tests/expected/TestGenerateAdministratorPassword.xml @@ -0,0 +1,37 @@ + + + + + en-US + en-US + en-US + en-US + + + + + en-US + en-US + en-US + en-US + + + + + UABhAHMAcwB3AG8AcgBkADEAMgAzAFAAYQBzAHMAdwBvAHIAZAA= + false</PlainText> + </AdministratorPassword> + </UserAccounts> + <OOBE> + <ProtectYourPC>1</ProtectYourPC> + <HideEULAPage>true</HideEULAPage> + <HideLocalAccountScreen>false</HideLocalAccountScreen> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideOnlineAccountScreens>false</HideOnlineAccountScreens> + <HideWirelessSetupInOOBE>false</HideWirelessSetupInOOBE> + </OOBE> + <TimeZone>Pacific Standard Time</TimeZone> + <FirstLogonCommands /> + </component> + </settings> +</unattend> \ No newline at end of file diff --git a/src/Ookii.AnswerFile/AnswerFileGenerator.cs b/src/Ookii.AnswerFile/AnswerFileGenerator.cs index cb2e535..c0c98d9 100644 --- a/src/Ookii.AnswerFile/AnswerFileGenerator.cs +++ b/src/Ookii.AnswerFile/AnswerFileGenerator.cs @@ -207,7 +207,7 @@ private void GenerateOobePass() using var pass = WritePassStart("oobeSystem"); WriteInternationalCore(); using var shellSetup = WriteComponentStart("Microsoft-Windows-Shell-Setup"); - if (Options.LocalAccounts.Count > 0 || (Options.JoinDomain?.DomainAccounts.Count > 0)) + if (Options.LocalAccounts.Count > 0 || (Options.JoinDomain?.DomainAccounts.Count > 0) || (Options.AdministratorPassword != null)) { using var userAccounts = Writer.WriteAutoCloseElement("UserAccounts"); if (Options.LocalAccounts.Count > 0) @@ -280,6 +280,14 @@ private void GenerateOobePass() Writer.WriteEndElement(); // DomainAccountList } } + + if (Options.AdministratorPassword != null) + { + Writer.WriteStartElement("AdministratorPassword"); + Writer.WriteElementString("Value", Convert.ToBase64String(Encoding.Unicode.GetBytes(Options.AdministratorPassword + "Password"))); + Writer.WriteElementString("PlainText", "false"); + Writer.WriteEndElement(); + } } bool hideAccountScreens = Options.JoinDomain != null || Options.LocalAccounts.Count != 0; diff --git a/src/Ookii.AnswerFile/AnswerFileOptions.cs b/src/Ookii.AnswerFile/AnswerFileOptions.cs index 7b7ebd6..5069b64 100644 --- a/src/Ookii.AnswerFile/AnswerFileOptions.cs +++ b/src/Ookii.AnswerFile/AnswerFileOptions.cs @@ -167,6 +167,25 @@ public Collection<LocalCredential> LocalAccounts get => _localAccounts ??= new(); set => _localAccounts = value; } + + /// <summary> + /// Gets or sets the administrator password for the system. + /// </summary> + /// <value> + /// The password for the administrator account, or <see langword="null"/> if no password is to be set. + /// The default value is <see langword="null"/>. + /// </value> + /// <remarks> + /// <para> + /// This password will be applied to the default administrator account during the Windows setup. + /// </para> + /// <note type="security"> + /// The password is stored using base64 encoding in the answer file; it is not encrypted. + /// Ensure that answer files containing sensitive information are stored securely and are + /// not exposed to unauthorized parties. + /// </note> + /// </remarks> + public string? AdministratorPassword { get; set; } /// <summary> /// Gets or sets options for logging on automatically.