Skip to content

Commit d477e5b

Browse files
committed
Support adding a random number to computer names.
Addresses #33.
1 parent 3774e74 commit d477e5b

File tree

8 files changed

+87
-23
lines changed

8 files changed

+87
-23
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,21 @@ To provision a domain account for the computer, you can use the following comman
292292
djoin.exe /provision /domain domainname /machine machinename /savefile filename
293293
```
294294

295+
### Specifying a computer name
296+
297+
When you provide a computer name using the [`-ComputerName`][] argument, the Answer File Generator
298+
does not check whether that computer name is valid. Specifying an invalid computer name will cause
299+
Windows setup to fail when applying the answer file. Make sure you follow the
300+
[rules for computer names](https://learn.microsoft.com/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-computername)
301+
when choosing a name.
302+
303+
If you do not specify a computer name, Windows will automatically choose one during installation.
304+
In addition, you can also use the `#` character to generate a name containing a random number.
305+
306+
Every occurrence of `#` in the provided computer name will be replaced with a digit between 0 and 9
307+
when generating the answer file. For example `PC-###` would be replaced with `PC-123` (or some
308+
other random number).
309+
295310
## Using JSON to provide options
296311

297312
Because the large number of command line arguments may get unwieldy, the Answer File Generator
@@ -338,6 +353,7 @@ any other adverse effects caused by the use of answer files generated by this to
338353
[`-AutoLogonUser`]: doc/CommandLine.md#-autologonuser
339354
[`-AutoLogonCount`]: doc/CommandLine.md#-autologoncount
340355
[`-Feature`]: doc/CommandLine.md#-feature
356+
[`-ComputerName`]: doc/CommandLine.md#-computername
341357
[`-FirstLogonCommand`]: doc/CommandLine.md#-firstlogoncommand
342358
[`-Install`]: doc/CommandLine.md#-install
343359
[`-InstallToDisk`]: doc/CommandLine.md#-installtodisk

doc/CommandLine.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,10 +404,14 @@ Required argument: -JoinDomain
404404

405405
### `-ComputerName`
406406

407-
The network name for the computer. If not specified, Windows will generate a default name.
407+
The network name for the computer. If not specified, Windows will generate a default name. Any `#`
408+
characters in the name will be replaced with a random digit between 0 and 9. For example, `PC-###`
409+
would be replaced with `PC-123` (or some other random number).
408410

409411
Must not be blank.
410412

413+
See [specifying a computer name](../README.md/#specifying-a-computer-name).
414+
411415
```yaml
412416
Value: <String>
413417
Alias: -n

src/GenerateAnswerFile/Properties/Resources.Designer.cs

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/GenerateAnswerFile/Properties/Resources.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
<value>User account options:</value>
143143
</data>
144144
<data name="ComputerNameDescription" xml:space="preserve">
145-
<value>The network name for the computer. If not specified, Windows will generate a default name.</value>
145+
<value>The network name for the computer. If not specified, Windows will generate a default name. Any '#' characters in the name will be replaced with a random digit between 0 and 9. For example, 'PC-###' would be replaced with 'PC-123' (or some other random number).</value>
146146
</data>
147147
<data name="DisableCloudDescription" xml:space="preserve">
148148
<value>Disable Windows cloud consumer features. This prevents auto-installation of recommended store apps.</value>

src/GenerateAnswerFile/Properties/launchSettings.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/GenerateAnswerFile/mdhelp.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"Override": true,
44
"Text": "Displays a help message."
55
},
6+
"ComputerName": "See [specifying a computer name](../README.md/#specifying-a-computer-name).",
67
"Feature": "See [optional features](../README.md#optional-features).",
78
"ImageIndex": "See [selecting the edition to install](../README.md#selecting-the-edition-to-install).",
89
"Install": "See [installation method](../README.md#installation-method).",

src/Ookii.AnswerFile.Tests/AnswerFileOptionsTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Drawing;
22
using System.Text.Json;
3+
using System.Text.RegularExpressions;
34

45
namespace Ookii.AnswerFile.Tests;
56

@@ -193,4 +194,25 @@ public void TestJsonSerializationManual()
193194
Assert.AreEqual(new Version(10, 0, 22000, 1), install.OptionalFeatures.WindowsVersion);
194195
CollectionAssert.AreEqual(new[] { "Microsoft-Windows-Subsystem-Linux", "VirtualMachinePlatform" }, install.OptionalFeatures.Features);
195196
}
197+
198+
[TestMethod]
199+
public void TestRandomComputerName()
200+
{
201+
var options = new AnswerFileOptions()
202+
{
203+
ComputerName = "test-####",
204+
};
205+
206+
Assert.IsTrue(Regex.IsMatch(options.ComputerName, @"^test-\d{4}$"));
207+
options.ComputerName = "foo#bar";
208+
Assert.IsTrue(Regex.IsMatch(options.ComputerName, @"^foo\dbar$"));
209+
options.ComputerName = "####################";
210+
Assert.IsTrue(Regex.IsMatch(options.ComputerName, @"^\d{20}$"));
211+
options.ComputerName = "test-###-#####";
212+
Assert.IsTrue(Regex.IsMatch(options.ComputerName, @"^test-\d{3}-\d{5}$"));
213+
214+
var json = "{\"ComputerName\": \"test-####\"}";
215+
options = AnswerFileOptions.FromJson(json);
216+
Assert.IsTrue(Regex.IsMatch(options!.ComputerName!, @"^test-\d{4}$"));
217+
}
196218
}

src/Ookii.AnswerFile/AnswerFileOptions.cs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System.Collections.ObjectModel;
22
using System.Drawing;
3+
using System.Text;
34
using System.Text.Json;
45
using System.Text.Json.Serialization;
6+
using System.Text.RegularExpressions;
57

68
namespace Ookii.AnswerFile;
79

@@ -10,14 +12,13 @@ namespace Ookii.AnswerFile;
1012
/// <see cref="AnswerFileGenerator"/> class.
1113
/// </summary>
1214
/// <threadsafety instance="false" static="true"/>
13-
public class AnswerFileOptions
15+
public partial class AnswerFileOptions
1416
{
17+
private string? _computerName;
1518
private Collection<LocalCredential>? _localAccounts;
1619
private Collection<string>? _firstLogonCommands;
1720
private Collection<string>? _firstLogonScripts;
1821

19-
#pragma warning disable CA1822 // Mark members as static
20-
2122
/// <summary>
2223
/// Gets the schema that can be used for validation of the JSON representation of this object.
2324
/// </summary>
@@ -29,8 +30,6 @@ public class AnswerFileOptions
2930
[JsonPropertyName("$schema")]
3031
public string JsonSchema => "https://www.ookii.org/Link/AnswerFileJsonSchema-2.0";
3132

32-
#pragma warning restore CA1822 // Mark members as static
33-
3433
/// <summary>
3534
/// Gets or sets the installation method to use, along with the options for that method.
3635
/// </summary>
@@ -66,7 +65,31 @@ public class AnswerFileOptions
6665
/// The computer name, or <see langword="null"/> to let Windows pick a computer name. The
6766
/// default value is <see langword="null"/>.
6867
/// </value>
69-
public string? ComputerName { get; set; }
68+
/// <remarks>
69+
/// <para>
70+
/// If this property is set to a value containing the # character, each # will be replaced
71+
/// with a random digit between 0 and 9. For example, the value "PC-###" will be replaced with
72+
/// "PC-123" (or any other random number).
73+
/// </para>
74+
/// <note type="note">
75+
/// While random numbers can be used to generate a distinct computer name, it is not
76+
/// necessarily guaranteed to be a unique name on the network.
77+
/// </note>
78+
/// </remarks>
79+
public string? ComputerName
80+
{
81+
get => _computerName;
82+
set
83+
{
84+
if (value != null)
85+
{
86+
// Replace # with random digits.
87+
value = RandomNumberRegex().Replace(value, m => Random.Shared.Next().ToString(m.Value).Substring(0, m.Length));
88+
}
89+
90+
_computerName = value;
91+
}
92+
}
7093

7194
/// <summary>
7295
/// Gets or sets a value which indicates whether Windows Defender is enabled after installation.
@@ -286,4 +309,10 @@ public Collection<string> FirstLogonScripts
286309
/// <returns>A JSON representation of the current instance.</returns>
287310
public string ToJson()
288311
=> JsonSerializer.Serialize(this, typeof(AnswerFileOptions), SourceGenerationContext.Default);
312+
313+
// This regex is used to replace the # characters in the computer name with random digits.
314+
// It processes groups of # in batches of 9, to avoid exceeding the maximum value of an int
315+
// for a single random number.
316+
[GeneratedRegex("#{1,9}")]
317+
private static partial Regex RandomNumberRegex();
289318
}

0 commit comments

Comments
 (0)