forked from M-Labs/nix-scripts
7e82318fd1
Windows changes the naming structure of homedir directories if it encounters an already present homedir so this is not working as intended.
319 lines
12 KiB
Nix
319 lines
12 KiB
Nix
{ pkgs
|
|
, lib ? pkgs.lib
|
|
, fullName
|
|
, organization
|
|
, administratorPassword
|
|
, uiLanguage ? "en-US"
|
|
, inputLocale ? "en-US"
|
|
, userLocale ? "en-US"
|
|
, systemLocale ? "en-US"
|
|
, users ? {}
|
|
, productKey ? null
|
|
, defaultUser ? null
|
|
, setupCommands ? []
|
|
, timeZone ? "UTC"
|
|
, services ? {}
|
|
, impureShellCommands ? []
|
|
, driveLetter ? "F:"
|
|
, ...
|
|
}:
|
|
|
|
let
|
|
|
|
serviceCommands = lib.mapAttrsToList (
|
|
serviceName: attrs: "powershell Set-Service -Name ${serviceName} " + (
|
|
lib.concatStringsSep " " (
|
|
(
|
|
lib.mapAttrsToList (
|
|
n: v: if builtins.typeOf v != "bool" then "-${n} ${v}" else "-${n}"
|
|
)
|
|
) (
|
|
# Always run without interaction
|
|
{ Force = true; } // attrs
|
|
)
|
|
)
|
|
)
|
|
) services;
|
|
|
|
sshSetupCommands =
|
|
# let
|
|
# makeDirs = lib.mapAttrsToList (n: v: ''mkdir C:\Users\${n}\.ssh'') users;
|
|
# writeKeys = lib.flatten (lib.mapAttrsToList (n: v: builtins.map (key: let
|
|
# commands = [
|
|
# ''powershell.exe Set-Content -Path C:\Users\${n}\.ssh\authorized_keys -Value '${key}' ''
|
|
# ];
|
|
# in lib.concatStringsSep "\n" commands) (v.sshKeys or [])) users);
|
|
# mkDirsDesc = builtins.map (c: {Path = c; Description = "Make SSH key dir";}) makeDirs;
|
|
# writeKeysDesc = builtins.map (c: {Path = c; Description = "Add SSH key";}) writeKeys;
|
|
# in
|
|
# mkDirsDesc ++ writeKeysDesc ++
|
|
[
|
|
{
|
|
Path = ''powershell.exe Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -Source ${driveLetter}\fod -LimitAccess'';
|
|
Description = "Add OpenSSH service.";
|
|
}
|
|
{
|
|
Path = ''powershell.exe Set-Service -Name sshd -StartupType Automatic'';
|
|
Description = "Enable SSH by default.";
|
|
}
|
|
];
|
|
|
|
assertCommand = c: builtins.typeOf c == "string" || builtins.typeOf c == "set" && builtins.hasAttr "Path" c && builtins.hasAttr "Description" c;
|
|
|
|
commands = builtins.map (x: assert assertCommand x; if builtins.typeOf x == "string" then { Path = x; Description = x; } else x) (
|
|
[
|
|
{
|
|
Path = "powershell.exe Set-ExecutionPolicy -Force Unrestricted";
|
|
Description = "Allow unsigned powershell scripts.";
|
|
}
|
|
]
|
|
++ [
|
|
{
|
|
Path = ''powershell.exe ${driveLetter}\win-bundle-installer.exe'';
|
|
Description = "Install any declared packages.";
|
|
}
|
|
]
|
|
++ setupCommands
|
|
++ [
|
|
{
|
|
Path = ''powershell.exe ${driveLetter}\ssh-setup.ps1'';
|
|
Description = "Setup SSH and keys";
|
|
}
|
|
]
|
|
++ serviceCommands
|
|
++ impureShellCommands
|
|
);
|
|
|
|
mkCommand = attrs: ''
|
|
<RunSynchronousCommand wcm:action="add">
|
|
${lib.concatStringsSep "\n" (lib.attrsets.mapAttrsToList (n: v: "<${n}>${v}</${n}>") attrs)}
|
|
</RunSynchronousCommand>
|
|
'';
|
|
mkCommands = commands: (
|
|
builtins.foldl' (
|
|
acc: v: rec {
|
|
i = acc.i + 1;
|
|
values = acc.values ++ [ (mkCommand (v // { Order = builtins.toString i; })) ];
|
|
}
|
|
) {
|
|
i = 0;
|
|
values = [];
|
|
} commands
|
|
).values;
|
|
|
|
mkUser =
|
|
{ name
|
|
, password
|
|
, description ? ""
|
|
, displayName ? ""
|
|
, groups ? []
|
|
# , sshKeys ? [] # Handled in scripts
|
|
}: ''
|
|
<LocalAccount wcm:action="add">
|
|
<Password>
|
|
<Value>${password}</Value>
|
|
<PlainText>true</PlainText>
|
|
</Password>
|
|
<Description>${description}</Description>
|
|
<DisplayName>${displayName}</DisplayName>
|
|
<Group>${builtins.concatStringsSep ";" (lib.unique ([ "Users" ] ++ groups))}</Group>
|
|
<Name>${name}</Name>
|
|
</LocalAccount>
|
|
'';
|
|
|
|
# Windows expects a flat list of users while we want to manage them as a set
|
|
flatUsers = builtins.attrValues (builtins.mapAttrs (name: s: s // { inherit name; }) users);
|
|
|
|
autounattendXML = pkgs.writeText "autounattend.xml" ''
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
|
<settings pass="windowsPE">
|
|
<component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<DriverPaths>
|
|
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
|
|
<Path>D:\</Path>
|
|
</PathAndCredentials>
|
|
<PathAndCredentials wcm:action="add" wcm:keyValue="2">
|
|
<Path>E:\</Path>
|
|
</PathAndCredentials>
|
|
</DriverPaths>
|
|
</component>
|
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
|
|
<DiskConfiguration>
|
|
<Disk wcm:action="add">
|
|
<CreatePartitions>
|
|
<CreatePartition wcm:action="add">
|
|
<Order>1</Order>
|
|
<Type>EFI</Type>
|
|
<Size>100</Size>
|
|
</CreatePartition>
|
|
<CreatePartition wcm:action="add">
|
|
<Order>2</Order>
|
|
<Type>MSR</Type>
|
|
<Size>16</Size>
|
|
</CreatePartition>
|
|
<CreatePartition wcm:action="add">
|
|
<Order>3</Order>
|
|
<Type>Primary</Type>
|
|
<Extend>true</Extend>
|
|
</CreatePartition>
|
|
</CreatePartitions>
|
|
<ModifyPartitions>
|
|
<ModifyPartition wcm:action="add">
|
|
<Order>1</Order>
|
|
<Format>FAT32</Format>
|
|
<Label>System</Label>
|
|
<PartitionID>1</PartitionID>
|
|
</ModifyPartition>
|
|
<ModifyPartition wcm:action="add">
|
|
<Order>2</Order>
|
|
<PartitionID>2</PartitionID>
|
|
</ModifyPartition>
|
|
<ModifyPartition wcm:action="add">
|
|
<Order>3</Order>
|
|
<Format>NTFS</Format>
|
|
<Label>Windows</Label>
|
|
<Letter>C</Letter>
|
|
<PartitionID>3</PartitionID>
|
|
</ModifyPartition>
|
|
</ModifyPartitions>
|
|
<DiskID>0</DiskID>
|
|
<WillWipeDisk>true</WillWipeDisk>
|
|
</Disk>
|
|
</DiskConfiguration>
|
|
|
|
<ImageInstall>
|
|
<OSImage>
|
|
<InstallTo>
|
|
<DiskID>0</DiskID>
|
|
<PartitionID>3</PartitionID>
|
|
</InstallTo>
|
|
<InstallFrom>
|
|
<MetaData wcm:action="add">
|
|
<Key>/IMAGE/INDEX</Key>
|
|
<Value>1</Value>
|
|
</MetaData>
|
|
</InstallFrom>
|
|
</OSImage>
|
|
</ImageInstall>
|
|
|
|
<UserData>
|
|
<ProductKey>
|
|
${if productKey != null then "<Key>${productKey}</Key>" else ""}
|
|
<WillShowUI>OnError</WillShowUI>
|
|
</ProductKey>
|
|
<AcceptEula>true</AcceptEula>
|
|
<FullName>${fullName}</FullName>
|
|
<Organization>${organization}</Organization>
|
|
</UserData>
|
|
|
|
</component>
|
|
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<SetupUILanguage>
|
|
<UILanguage>${uiLanguage}</UILanguage>
|
|
</SetupUILanguage>
|
|
<InputLocale>${inputLocale}</InputLocale>
|
|
<SystemLocale>${systemLocale}</SystemLocale>
|
|
<UILanguage>${uiLanguage}</UILanguage>
|
|
<UILanguageFallback>en-US</UILanguageFallback>
|
|
<UserLocale>${userLocale}</UserLocale>
|
|
</component>
|
|
</settings>
|
|
|
|
<settings pass="oobeSystem">
|
|
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<InputLocale>${inputLocale}</InputLocale>
|
|
<SystemLocale>${systemLocale}</SystemLocale>
|
|
<UILanguage>${uiLanguage}</UILanguage>
|
|
<UILanguageFallback>en-US</UILanguageFallback>
|
|
<UserLocale>${userLocale}</UserLocale>
|
|
</component>
|
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<OOBE>
|
|
<HideEULAPage>true</HideEULAPage>
|
|
<HideLocalAccountScreen>true</HideLocalAccountScreen>
|
|
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
|
|
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
|
|
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
|
<ProtectYourPC>1</ProtectYourPC>
|
|
</OOBE>
|
|
<TimeZone>${timeZone}</TimeZone>
|
|
|
|
<UserAccounts>
|
|
${if administratorPassword != null then ''
|
|
<AdministratorPassword>
|
|
<Value>${administratorPassword}</Value>
|
|
<PlainText>true</PlainText>
|
|
</AdministratorPassword>
|
|
'' else ""}
|
|
<LocalAccounts>
|
|
${builtins.concatStringsSep "\n" (builtins.map mkUser flatUsers)}
|
|
</LocalAccounts>
|
|
</UserAccounts>
|
|
|
|
${if defaultUser == null then "" else ''
|
|
<AutoLogon>
|
|
<Password>
|
|
<Value>${(builtins.getAttr defaultUser users).password}</Value>
|
|
<PlainText>true</PlainText>
|
|
</Password>
|
|
<Enabled>true</Enabled>
|
|
<Username>${defaultUser}</Username>
|
|
</AutoLogon>
|
|
''}
|
|
|
|
<FirstLogonCommands>
|
|
<SynchronousCommand wcm:action="add">
|
|
<Order>1</Order>
|
|
<CommandLine>cmd /C shutdown /s /f /t 00</CommandLine>
|
|
<Description>ChangeHideFiles</Description>
|
|
</SynchronousCommand>
|
|
</FirstLogonCommands>
|
|
|
|
</component>
|
|
</settings>
|
|
|
|
<settings pass="specialize">
|
|
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<RunSynchronous>
|
|
${lib.concatStringsSep "\n" (mkCommands commands)}
|
|
</RunSynchronous>
|
|
</component>
|
|
<component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="NonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<CEIPEnabled>0</CEIPEnabled>
|
|
</component>
|
|
</settings>
|
|
|
|
<!-- Disable Windows UAC -->
|
|
<settings pass="offlineServicing">
|
|
<component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
<EnableLUA>false</EnableLUA>
|
|
</component>
|
|
</settings>
|
|
|
|
<cpi:offlineImage cpi:source="wim:c:/wim/windows-10/install.wim#Windows 10 Enterprise LTSC 2019 Evaluation" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
|
|
</unattend>
|
|
'';
|
|
|
|
in {
|
|
# Lint and format as a sanity check
|
|
autounattendXML = pkgs.runCommandNoCC "autounattend.xml" {} ''
|
|
${pkgs.libxml2}/bin/xmllint --format ${autounattendXML} > $out
|
|
'';
|
|
|
|
# autounattend.xml is _super_ picky about quotes and other things
|
|
setupScript = pkgs.writeText "ssh-setup.ps1" (
|
|
''
|
|
# Setup SSH and keys
|
|
'' +
|
|
lib.concatStrings (
|
|
builtins.map (c: ''
|
|
# ${c.Description}
|
|
${c.Path}
|
|
'') sshSetupCommands
|
|
)
|
|
);
|
|
|
|
}
|