AutomatedLabUnattended.psm1
function Add-UnattendedCloudInitNetworkAdapter { param ( [string]$InterfaceName, [AutomatedLab.IPNetwork[]]$IpAddresses, [AutomatedLab.IPAddress[]]$Gateways, [AutomatedLab.IPAddress[]]$DnsServers ) $macAddress = ($Interfacename -replace '-', ':').ToLower() if (-not $script:un.network.network.ContainsKey('ethernets`')) { $script:un.network.network.ethernets = @{ } } if ($script:un.network.network.ethernets.Keys.Count -eq 0) { $ifName = 'en0' } else { [int]$lastIfIndex = ($script:un.network.network.ethernets.Keys.GetEnumerator() | Sort-Object | Select-Object -Last 1) -replace 'en' $lastIfIndex++ $ifName = 'en{0}' -f $lastIfIndex } $script:un.network.network.ethernets[$ifName] = @{ match = @{ macAddress = $macAddress } 'set-name' = $ifName } $adapterAddress = $IpAddresses | Select-Object -First 1 if (-not $adapterAddress) { $script:un.network.network.ethernets[$ifName].dhcp4 = 'yes' $script:un.network.network.ethernets[$ifName].dhcp6 = 'yes' } else { $script:un.network.network.ethernets[$ifName].addresses = @() foreach ($ip in $IpAddresses) { $script:un.network.network.ethernets[$ifName].addresses += '{0}/{1}' -f $ip.IPAddress.AddressAsString, $ip.Netmask } } if ($Gateways -and -not $script:un.network.network.ethernets[$ifName].ContainsKey('routes')) { $script:un.network.network.ethernets[$ifName].routes = @() } foreach ($gw in $Gateways) { $script:un.network.network.ethernets[$ifName].routes += @{ to = 'default' via = $gw.AddressAsString } } if ($DnsServers) { $script:un.network.network.ethernets[$ifName].nameservers = @{ addresses = $DnsServers.AddressAsString } } } function Add-UnattendedCloudInitRenameNetworkAdapters { [CmdletBinding()] param ( ) Write-PSFMessage -Message 'Method not required on Ubuntu/Cloudinit' } function Add-UnattendedCloudInitSynchronousCommand { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Command, [Parameter(Mandatory)] [string]$Description ) $script:un['late-commands'] += $Command } function Export-UnattendedCloudInitFile { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Path ) $script:un | ConvertTo-Yaml | Set-Content -Path $Path -Force } function Import-UnattendedCloudInitContent { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]] $Content ) $script:un = $Content -join "`r`n" | ConvertFrom-Yaml } function Set-UnattendedCloudInitAdministratorName { param ( [Parameter(Mandatory = $true)] [string] $Name ) $Script:un.identity.username = $Name } function Set-UnattendedCloudInitAdministratorPassword { param ( [Parameter(Mandatory = $true)] [string] $Password ) $pw = [System.Text.Encoding]::UTF8.GetBytes($Password) $sha = [System.Security.Cryptography.SHA512Managed]::new() $hsh = $sha.ComputeHash($pw) $Script:un.identity.password = [Convert]::ToBase64String($hsh) } function Set-UnattendedCloudInitAntiMalware { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [bool]$Enabled ) Write-PSFMessage -Message "No anti-malware settings for CloudInit/Ubuntu" } function Set-UnattendedCloudInitAutoLogon { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password ) Write-PSFMessage -Message "Auto-logon not implemented yet for CloudInit/Ubuntu" } function Set-UnattendedCloudInitComputerName { param ( [Parameter(Mandatory = $true)] [string] $ComputerName ) $Script:un.identity.hostname = $ComputerName } function Set-UnattendedCloudInitDomain { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password, [Parameter()] [string]$OrganizationalUnit ) if ($OrganizationalUnit) { $script:un['late-commands'] += "realm join --computer-ou='{2}' --one-time-password='{0}' {1}" -f $Password, $DomainName, $OrganizationalUnit } else { $script:un['late-commands'] += "realm join --one-time-password='{0}' {1}" -f $Password, $DomainName } } function Set-UnattendedCloudInitFirewallState { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [boolean]$State ) $script:un['late-commands'] += 'ufw enable' $script:un['late-commands'] += 'ufw allow 22' } function Set-UnattendedCloudInitIpSettings { [CmdletBinding()] param ( [string]$IpAddress, [string]$Gateway, [String[]]$DnsServers, [string]$DnsDomain ) $ifName = 'en0' $script:un.network.network.ethernets[$ifName] = @{ match = @{ macAddress = $macAddress } 'set-name' = $ifName } $adapterAddress = $IpAddress if (-not $adapterAddress) { $script:un.network.network.ethernets[$ifName].dhcp4 = 'yes' $script:un.network.network.ethernets[$ifName].dhcp6 = 'yes' } else { $script:un.network.network.ethernets[$ifName].addresses = @( $IpAddress ) } if ($Gateway -and -not $script:un.network.network.ethernets[$ifName].ContainsKey('routes')) { $script:un.network.network.ethernets[$ifName].routes = @( @{ to = 'default' via = $Gateway }) } if ($DnsServers) { $script:un.network.network.ethernets[$ifName].nameservers = @{ addresses = $DnsServers } } } function Set-UnattendedCloudInitLocalIntranetSites { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]]$Values ) Write-PSFMessage -Message 'No local intranet sites for CloudInit/Ubuntu' } function Set-UnattendedCloudInitPackage { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]]$Package ) foreach ($pack in $Package) { if ($pack -in $script:un.packages) { continue } $script:un.packages += $pack } } function Set-UnattendedProductKey { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$ProductKey ) Write-PSFMessage "No product key required on CloudInit/Ubuntu" } function Set-UnattendedCloudInitTimeZone { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$TimeZone ) $tzInfo = Get-TimeZone -Id $TimeZone -ErrorAction SilentlyContinue if (-not $tzInfo) { Get-TimeZone } Write-PSFMessage -Message ('Since non-standard timezone names are used, we revert to Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours) $tzname = if ($tzInfo.BaseUtcOffset.TotalHours -gt 0) { 'timezone Etc/GMT+{0}' -f $tzInfo.BaseUtcOffset.TotalHours } elseif ($tzInfo.BaseUtcOffset.TotalHours -eq 0) { 'timezone Etc/GMT' } else { 'timezone Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours } $script:un['late-commands'] += 'sudo timedatectl set-timezone {0}' -f $tzname } function Set-UnattendedCloudInitUserLocale { param ( [Parameter(Mandatory = $true)] [string]$UserLocale ) try { $ci = [cultureinfo]::new($UserLocale) } catch { Write-PSFMessage -Message "Could not determine culture from $UserLocale. Assuming en_us" $script:un.locale = 'en_US.UTF-8' return } $script:un.locale = "$($ci.IetfLanguageTag -replace '-','_').UTF-8" } function Set-UnattendedCloudInitWorkgroup { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$WorkgroupName ) $script:un['late-commands'] += "sed -i 's|[#]*workgroup = WORKGROUP|workgroup = {0}|g' /etc/samba/smb.conf" -f $WorkgroupName } function Add-UnattendedKickstartNetworkAdapter { param ( [string]$Interfacename, [AutomatedLab.IPNetwork[]]$IpAddresses, [AutomatedLab.IPAddress[]]$Gateways, [AutomatedLab.IPAddress[]]$DnsServers ) $linuxInterfaceName = ($Interfacename -replace '-',':').ToLower() $adapterAddress = $IpAddresses | Select-Object -First 1 if (-not $adapterAddress) { $configurationItem = "network --bootproto=dhcp --device={0}" -f $linuxInterfaceName } else { $configurationItem = "network --bootproto=static --device={0} --ip={1} --netmask={2}" -f $linuxInterfaceName,$adapterAddress.IPAddress.AddressAsString,$adapterAddress.Netmask } if ($Gateways) { $configurationItem += ' --gateway={0}' -f ($Gateways.AddressAsString -join ',') } $configurationItem += if ($DnsServers | Where-Object AddressAsString -ne '0.0.0.0') { ' --nameserver={0}' -f ($DnsServers.AddressAsString -join ',') } else { ' --nodns' } $script:un.Add($configurationItem) } function Add-UnattendedKickstartRenameNetworkAdapters { [CmdletBinding()] param ( ) Write-PSFMessage -Message 'Method not yet implemented for RHEL/CentOS/Fedora' } function Add-UnattendedKickstartSynchronousCommand { param ( [Parameter(Mandatory)] [string]$Command, [Parameter(Mandatory)] [string]$Description ) Write-PSFMessage -Message "Adding command to %post section to $Description" $idx = $script:un.IndexOf('%post') if ($idx -eq -1) { $script:un.Add('%post') $idx = $script:un.IndexOf('%post') } $script:un.Insert($idx + 1, $Command) } function Export-UnattendedKickstartFile { param ( [Parameter(Mandatory = $true)] [string]$Path ) $idx = $script:un.IndexOf('%post') if ($idx -eq -1) { $script:un.Add('%post') $idx = $script:un.IndexOf('%post') } $repoIp = try { ([System.Net.Dns]::GetHostByName('packages.microsoft.com').AddressList | Where-Object AddressFamily -eq InterNetwork).IPAddressToString } catch { '104.214.230.139' } try { $repoContent = (Invoke-RestMethod -Method Get -Uri 'https://packages.microsoft.com/config/rhel/7/prod.repo' -ErrorAction Stop) -split "`n" } catch { } if ($script:un[$idx + 1] -ne '#start') { @( '#start' '. /etc/os-release' foreach ($line in $repoContent) { if (-not $line) { continue } if ($line -like '*gpgcheck*') {$line = 'gpgcheck=0'} 'echo "{0}" >> /etc/yum.repos.d/microsoft.repo' -f $line } 'echo "{0} packages.microsoft.com" >> /etc/hosts' -f $repoIp 'yum install -y openssl' 'yum install -y omi' 'yum install -y powershell' 'yum install -y omi-psrp-server' 'yum list installed "powershell" > /ksPowerShell' 'yum list installed "omi-psrp-server" > /ksOmi' 'rm /etc/yum.repos.d/microsoft.repo' foreach ($line in $repoContent) { if (-not $line) { continue } 'echo "{0}" >> /etc/yum.repos.d/microsoft.repo' -f $line } 'authselect select sssd with-mkhomedir -f' 'systemctl restart sssd' 'echo "Subsystem powershell /usr/bin/pwsh -sshs -NoLogo" >> /etc/ssh/sshd_config' 'systemctl restart sshd' ) | ForEach-Object -Process { $idx++ $script:un.Insert($idx, $_) } # When index of end is greater then index of package end: add %end to EOF # else add %end before %packages $idxPackage = $script:un.IndexOf('%packages --ignoremissing') $idxPost = $script:un.IndexOf('%post') $idxEnd = if (-1 -ne $idxPackage -and $idxPost -lt $idxPackage) { $idxPackage } else { $script:un.Count } $script:un.Insert($idxEnd, '%end') } ($script:un | Out-String) -replace "`r`n", "`n" | Set-Content -Path $Path -Force } function Import-UnattendedKickstartContent { param ( [Parameter(Mandatory = $true)] [System.Collections.Generic.List[string]] $Content ) $script:un = $Content } function Set-UnattendedKickstartAdministratorName { param ( $Name ) $script:un.Add("user --name=$Name --groups=wheel --password='%PASSWORD%'") } function Set-UnattendedKickstartAdministratorPassword { param ( [Parameter(Mandatory = $true)] [string]$Password ) $Script:un.Add("rootpw '$Password'") $Script:un = [System.Collections.Generic.List[string]]($Script:un.Replace('%PASSWORD%', $Password)) } function Set-UnattendedKickstartAntiMalware { param ( [Parameter(Mandatory = $true)] [bool]$Enabled ) if ($Enabled) { $Script:un.Add("selinux --enforcing") } else { $Script:un.Add("selinux --permissive") # Not a great idea to disable selinux alltogether } } function Set-UnattendedKickstartAutoLogon { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password ) Write-PSFMessage -Message "Auto-logon not implemented yet for RHEL/CentOS/Fedora" } function Set-UnattendedKickstartComputerName { param ( [Parameter(Mandatory = $true)] [string]$ComputerName ) $script:un.Add("network --hostname=$ComputerName") } function Set-UnattendedKickstartDomain { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password, [Parameter()] [string]$OrganizationalUnit ) if ($OrganizationalUnit) { $script:un.Add(("realm join --computer-ou='{2}' --one-time-password='{0}' {1}" -f $Password, $DomainName, $OrganizationalUnit)) } else { $script:un.Add(("realm join --one-time-password='{0}' {1}" -f $Password, $DomainName)) } } function Set-UnattendedKickstartFirewallState { param ( [Parameter(Mandatory = $true)] [boolean]$State ) if ($State) { $script:un.Add('firewall --enabled') } else { $script:un.Add('firewall --disabled') } } function Set-UnattendedKickstartIpSettings { param ( [string]$IpAddress, [string]$Gateway, [String[]]$DnsServers, [string]$DnsDomain ) if (-not $IpAddress) { $configurationItem = "network --bootproto=dhcp" } else { $configurationItem = "network --bootproto=static --ip={0}" -f $IpAddress } if ($Gateway) { $configurationItem += ' --gateway={0}' -f $Gateway } $configurationItem += if ($DnsServers) { ' --nameserver={0}' -f ($DnsServers.AddressAsString -join ',') } else { ' --nodns' } $script:un.Add($configurationItem) } function Set-UnattendedKickstartLocalIntranetSites { param ( [Parameter(Mandatory = $true)] [string[]]$Values ) Write-PSFMessage -Message 'No local intranet sites for RHEL/CentOS/Fedora' } function Set-UnattendedKickstartPackage { param ( [string[]]$Package ) if ($Package -like '*Gnome*') { $script:un.Add('xconfig --startxonboot --defaultdesktop=GNOME') } elseif ($Package -like '*KDE*') { Write-PSFMessage -Level Warning -Message 'Adding KDE UI to RHEL/CentOS via kickstart file is not supported. Please configure your UI manually.' } $script:un.Add('%packages --ignoremissing') $script:un.Add('@^server-product-environment') $required = @( 'oddjob' 'oddjob-mkhomedir' 'sssd' 'adcli' 'krb5-workstation' 'realmd' 'samba-common' 'samba-common-tools' 'authselect-compat' 'sshd' ) foreach ($p in $Package) { if ($p -eq '@^server-product-environment' -or $p -in $required) { continue } $null = $script:un.Add($p) if ($p -like '*gnome*' -and $script:un -notcontains '@^graphical-server-environment') { $script:un.Add('@^graphical-server-environment')} } foreach ($p in $required) { $script:un.Add($p) } $script:un.Add('%end') } function Set-UnattendedKickstartProductKey { param ( [Parameter(Mandatory = $true)] [string]$ProductKey ) Write-PSFMessage -Message 'No product key necessary for RHEL/CentOS/Fedora' } function Set-UnattendedKickstartTimeZone { param ( [Parameter(Mandatory = $true)] [string]$TimeZone ) $tzInfo = Get-TimeZone -Id $TimeZone -ErrorAction SilentlyContinue if (-not $tzInfo) { Get-TimeZone } Write-PSFMessage -Message ('Since non-standard timezone names are used, we revert to Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours) if ($tzInfo.BaseUtcOffset.TotalHours -gt 0) { $script:un.Add(('timezone Etc/GMT+{0}' -f $tzInfo.BaseUtcOffset.TotalHours)) } elseif ($tzInfo.BaseUtcOffset.TotalHours -eq 0) { $script:un.Add('timezone Etc/GMT') } else { $script:un.Add(('timezone Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours)) } } function Set-UnattendedKickstartUserLocale { param ( [Parameter(Mandatory = $true)] [string]$UserLocale ) try { $ci = [cultureinfo]::new($UserLocale) } catch { Write-PSFMessage -Message "Could not determine culture from $UserLocale. Assuming en_us" $script:un.Add("keyboard 'us'") $script:un.Add('lang en_us') return } $weirdLinuxCultureName = if ($ci.IsNeutralCulture) { $ci.TwoLetterISOLanguageName } else {$ci.Name -split '-' | Select-Object -Last 1} $script:un.Add("keyboard '$($weirdLinuxCultureName.ToLower())'") $script:un.Add("lang $($ci.IetfLanguageTag -replace '-','_')") } function Set-UnattendedKickstartWorkgroup { param ( [Parameter(Mandatory = $true)] [string] $WorkgroupName ) $script:un.Add(('auth --smbworkgroup={0}' -f $WorkgroupName)) } function Add-UnattendedYastNetworkAdapter { param ( [string]$Interfacename, [AutomatedLab.IPNetwork[]]$IpAddresses, [AutomatedLab.IPAddress[]]$Gateways, [AutomatedLab.IPAddress[]]$DnsServers, [string]$ConnectionSpecificDNSSuffix, [string]$DnsDomain, [string]$DNSSuffixSearchOrder ) $networking = $script:un.SelectSingleNode('/un:profile/un:networking', $script:nsm) $interfaceList = $script:un.SelectSingleNode('/un:profile/un:networking/un:interfaces', $script:nsm) $udevList = $script:un.SelectSingleNode('/un:profile/un:networking/un:net-udev', $script:nsm) $dns = $script:un.SelectSingleNode('/un:profile/un:networking/un:dns', $script:nsm) $nameServers = $script:un.SelectSingleNode('/un:profile/un:networking/un:dns/un:nameservers', $script:nsm) $routes = $script:un.SelectSingleNode('/un:profile/un:networking/un:routing/un:routes', $script:nsm) $hostName = $script:un.CreateElement('hostname', $script:nsm.LookupNamespace('un')) $null = $dns.AppendChild($hostName) if ($DnsDomain) { $domain = $script:un.CreateElement('domain', $script:nsm.LookupNamespace('un')) $domain.InnerText = $DnsDomain $null = $dns.AppendChild($domain) } if ($DnsServers) { foreach ($ns in $DnsServers) { $nameserver = $script:un.CreateElement('nameserver', $script:nsm.LookupNamespace('un')) $nameserver.InnerText = $ns $null = $nameservers.AppendChild($nameserver) } if ($DNSSuffixSearchOrder) { $searchlist = $script:un.CreateElement('searchlist', $script:nsm.LookupNamespace('un')) $nsAttr = $script:un.CreateAttribute('config', 'type', $script:nsm.LookupNamespace('config')) $nsAttr.InnerText = 'list' $null = $searchlist.Attributes.Append($nsAttr) foreach ($suffix in ($DNSSuffixSearchOrder -split ',')) { $suffixEntry = $script:un.CreateElement('search', $script:nsm.LookupNamespace('un')) $suffixEntry.InnerText = $suffix $null = $searchlist.AppendChild($suffixEntry) } $null = $dns.AppendChild($searchlist) } } $null = $networking.AppendChild($dns) $interface = 'eth0' $lastInterface = $script:un.SelectNodes('/un:profile/un:networking/un:interfaces/un:interface/un:device', $script:nsm).InnerText | Sort-Object | Select-Object -Last 1 if ($lastInterface) { $interface = 'eth{0}' -f ([int]$lastInterface.Substring($lastInterface.Length - 1, 1) + 1) } $interfaceNode = $script:un.CreateElement('interface', $script:nsm.LookupNamespace('un')) $bootproto = $script:un.CreateElement('bootproto', $script:nsm.LookupNamespace('un')) $bootproto.InnerText = if ($IpAddresses.Count -eq 0) { 'dhcp' } else { 'static' } $deviceNode = $script:un.CreateElement('device', $script:nsm.LookupNamespace('un')) $deviceNode.InnerText = $interface $firewallnode = $script:un.CreateElement('firewall', $script:nsm.LookupNamespace('un')) $firewallnode.InnerText = 'no' if ($IpAddresses.Count -gt 0) { $ipaddr = $script:un.CreateElement('ipaddr', $script:nsm.LookupNamespace('un')) $netmask = $script:un.CreateElement('netmask', $script:nsm.LookupNamespace('un')) $network = $script:un.CreateElement('network', $script:nsm.LookupNamespace('un')) $ipaddr.InnerText = $IpAddresses[0].IpAddress.AddressAsString $netmask.InnerText = $IpAddresses[0].Netmask.AddressAsString $network.InnerText = $IpAddresses[0].Network.AddressAsString $null = $interfaceNode.AppendChild($ipaddr) $null = $interfaceNode.AppendChild($netmask) $null = $interfaceNode.AppendChild($network) } $startmode = $script:un.CreateElement('startmode', $script:nsm.LookupNamespace('un')) $startmode.InnerText = 'auto' $null = $interfaceNode.AppendChild($bootproto) $null = $interfaceNode.AppendChild($deviceNode) $null = $interfaceNode.AppendChild($firewallnode) $null = $interfaceNode.AppendChild($startmode) if ($IpAddresses.Count -gt 1) { $aliases = $script:un.CreateElement('aliases', $script:nsm.LookupNamespace('un')) $count = 0 foreach ($additionalAdapter in ($IpAddresses | Select-Object -Skip 1)) { $alias = $script:un.CreateElement("alias$count", $script:nsm.LookupNamespace('un')) $ipaddr = $script:un.CreateElement('IPADDR', $script:nsm.LookupNamespace('un')) $label = $script:un.CreateElement('LABEL', $script:nsm.LookupNamespace('un')) $netmask = $script:un.CreateElement('NETMASK', $script:nsm.LookupNamespace('un')) $ipaddr.InnerText = $additionalAdapter.IpAddress.AddressAsString $netmask.InnerText = $additionalAdapter.Netmask.AddressAsString $label.InnerText = "ip$count" $null = $alias.AppendChild($ipaddr) $null = $alias.AppendChild($label) $null = $alias.AppendChild($netmask) $null = $aliases.AppendChild($alias) $count++ } $null = $interfaceNode.AppendChild($aliases) } $null = $interfaceList.AppendChild($interfaceNode) $udevRuleNode = $script:un.CreateElement('rule', $script:nsm.LookupNamespace('un')) $udevRuleNameNode = $script:un.CreateElement('name', $script:nsm.LookupNamespace('un')) $udevRuleNameNode.InnerText = $interface $udevRuleRuleNode = $script:un.CreateElement('rule', $script:nsm.LookupNamespace('un')) $udevRuleRuleNode.InnerText = 'ATTR{address}' # No joke. They really mean it to be written this way $udevRuleValueNode = $script:un.CreateElement('value', $script:nsm.LookupNamespace('un')) $udevRuleValueNode.InnerText = ($Interfacename -replace '-', ':').ToUpper() $null = $udevRuleNode.AppendChild($udevRuleNameNode) $null = $udevRuleNode.AppendChild($udevRuleRuleNode) $null = $udevRuleNode.AppendChild($udevRuleValueNode) $null = $udevList.AppendChild($udevRuleNode) if ($Gateways) { foreach ($gateway in $Gateways) { $routeNode = $script:un.CreateElement('route', $script:nsm.LookupNamespace('un')) $destinationNode = $script:un.CreateElement('destination', $script:nsm.LookupNamespace('un')) $deviceNode = $script:un.CreateElement('device', $script:nsm.LookupNamespace('un')) $gatewayNode = $script:un.CreateElement('gateway', $script:nsm.LookupNamespace('un')) $netmask = $script:un.CreateElement('netmask', $script:nsm.LookupNamespace('un')) $destinationNode.InnerText = 'default' # should work for both IPV4 and IPV6 routes $devicenode.InnerText = $interface $gatewayNode.InnerText = $gateway.AddressAsString $netmask.InnerText = '-' $null = $routeNode.AppendChild($destinationNode) $null = $routeNode.AppendChild($devicenode) $null = $routeNode.AppendChild($gatewayNode) $null = $routeNode.AppendChild($netmask) $null = $routes.AppendChild($routeNode) } } } function Add-UnattendedYastRenameNetworkAdapters { } function Add-UnattendedYastSynchronousCommand { param ( [Parameter(Mandatory)] [string]$Command, [Parameter(Mandatory)] [string]$Description ) } function Export-UnattendedYastFile { param ( [Parameter(Mandatory = $true)] [string]$Path ) $script:un.Save($Path) } function Import-UnattendedYastContent { param ( [Parameter(Mandatory = $true)] [xml] $Content ) $script:un = $Content $script:ns = @{ un = "http://www.suse.com/1.0/yast2ns" 'un:config' = "http://www.suse.com/1.0/configns" } $script:nsm = [System.Xml.XmlNamespaceManager]::new($script:un.NameTable) $script:nsm.AddNamespace('un',"http://www.suse.com/1.0/yast2ns") $script:nsm.AddNamespace('un:config',"http://www.suse.com/1.0/configns" ) } function Set-UnattendedYastAdministratorName { param ( $Name ) $userNode = $script:un.SelectSingleNode('/un:profile/un:users', $script:nsm) $user = $script:un.CreateElement('user', $script:nsm.LookupNamespace('un')) $username = $script:un.CreateElement('username', $script:nsm.LookupNamespace('un')) $pw = $script:un.CreateElement('user_password', $script:nsm.LookupNamespace('un')) $encrypted = $script:un.CreateElement('encrypted', $script:nsm.LookupNamespace('un')) $listAttr = $script:un.CreateAttribute('config','type', $script:nsm.LookupNamespace('config')) $listAttr.InnerText = 'boolean' $null = $encrypted.Attributes.Append($listAttr) $encrypted.InnerText = 'false' $pw.InnerText = 'none' $username.InnerText = $Name $null = $user.AppendChild($pw) $null = $user.AppendChild($encrypted) $null = $user.AppendChild($username) $null = $userNode.AppendChild($user) } function Set-UnattendedYastAdministratorPassword { param ( [Parameter(Mandatory = $true)] [string]$Password ) $passwordNodes = $script:un.SelectNodes('/un:profile/un:users/un:user/un:user_password', $script:nsm) foreach ($node in $passwordNodes) { $node.InnerText = $Password } } function Set-UnattendedYastAntiMalware { param ( [Parameter(Mandatory = $true)] [bool]$Enabled ) } function Set-UnattendedYastAutoLogon { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password ) $logonNode = $script:un.CreateElement('login_settings', $script:nsm.LookupNamespace('un')) $autoLogon = $script:un.CreateElement('autologin_user', $script:nsm.LookupNamespace('un')) $autologon.InnerText = '{0}\{1}' -f $DomainName, $Username $null = $logonNode.AppendChild($autoLogon) $null = $script:un.DocumentElement.AppendChild($logonNode) } function Set-UnattendedYastComputerName { param ( [Parameter(Mandatory = $true)] [string]$ComputerName ) $component = $script:un.SelectSingleNode('/un:profile/un:networking/un:dns/un:hostname', $script:nsm) $component.InnerText = $ComputerName } function Set-UnattendedYastDomain { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password, [Parameter()] [string]$OrganizationalUnit ) $smbClientNode = $script:un.CreateElement('samba-client', $script:nsm.LookupNamespace('un')) $boolAttrib = $script:un.CreateAttribute('config','type', $script:nsm.LookupNamespace('config')) $boolAttrib.InnerText = 'boolean' $adNode = $script:un.CreateElement('active_directory', $script:nsm.LookupNamespace('un')) $kdc = $script:un.CreateElement('kdc', $script:nsm.LookupNamespace('un')) $disableDhcp = $script:un.CreateElement('disable_dhcp_hostname', $script:nsm.LookupNamespace('un')) $globalNode = $script:un.CreateElement('global', $script:nsm.LookupNamespace('un')) $securityNode = $script:un.CreateElement('security', $script:nsm.LookupNamespace('un')) $shellNode = $script:un.CreateElement('template_shell', $script:nsm.LookupNamespace('un')) $guestNode = $script:un.CreateElement('usershare_allow_guests', $script:nsm.LookupNamespace('un')) $domainNode = $script:un.CreateElement('workgroup', $script:nsm.LookupNamespace('un')) $joinNode = $script:un.CreateElement('join', $script:nsm.LookupNamespace('un')) $joinUserNode = $script:un.CreateElement('user', $script:nsm.LookupNamespace('un')) $joinPasswordNode = $script:un.CreateElement('password', $script:nsm.LookupNamespace('un')) $homedirNode = $script:un.CreateElement('mkhomedir', $script:nsm.LookupNamespace('un')) $winbindNode = $script:un.CreateElement('winbind', $script:nsm.LookupNamespace('un')) $null = $disableDhcp.Attributes.Append($boolAttrib) $null = $homedirNode.Attributes.Append($boolAttrib) $null = $winbindNode.Attributes.Append($boolAttrib) $kdc.InnerText = $DomainName $disableDhcp.InnerText = 'true' $securityNode.InnerText = 'ADS' $shellNode.InnerText = '/bin/bash' $guestNode.InnerText = 'no' $domainNode.InnerText = $DomainName $joinUserNode.InnerText = $Username $joinPasswordNode.InnerText = $Password $homedirNode.InnerText = 'true' $winbindNode.InnerText = 'false' $null = $adNode.AppendChild($kdc) $null = $globalNode.AppendChild($securityNode) $null = $globalNode.AppendChild($shellNode) $null = $globalNode.AppendChild($guestNode) $null = $globalNode.AppendChild($domainNode) $null = $joinNode.AppendChild($joinUserNode) $null = $joinNode.AppendChild($joinPasswordNode) $null = $smbClientNode.AppendChild($disableDhcp) $null = $smbClientNode.AppendChild($globalNode) $null = $smbClientNode.AppendChild($adNode) $null = $smbClientNode.AppendChild($joinNode) $null = $smbClientNode.AppendChild($homedirNode) $null = $smbClientNode.AppendChild($winbindNode) $null = $script:un.DocumentElement.AppendChild($smbClientNode) # SSSD configuration $authClientNode = $script:un.CreateElement('auth-client', $script:nsm.LookupNamespace('un')) $authClientSssd = $script:un.CreateElement('sssd', $script:nsm.LookupNamespace('un')) $authClientLdaps = $script:un.CreateElement('nssldap', $script:nsm.LookupNamespace('un')) $sssdConf = $script:un.CreateElement('sssd_conf', $script:nsm.LookupNamespace('un')) $sssdConfFile = $script:un.CreateElement('config_file_version', $script:nsm.LookupNamespace('un')) $sssdConfServices = $script:un.CreateElement('services', $script:nsm.LookupNamespace('un')) $sssdConfNode = $script:un.CreateElement('sssd', $script:nsm.LookupNamespace('un')) $sssdConfDomains = $script:un.CreateElement('domains', $script:nsm.LookupNamespace('un')) $authDomains = $script:un.CreateElement('auth_domains', $script:nsm.LookupNamespace('un')) $authDomain = $script:un.CreateElement('domain', $script:nsm.LookupNamespace('un')) $authDomainName = $script:un.CreateElement('domain_name', $script:nsm.LookupNamespace('un')) $authDomainIdp = $script:un.CreateElement('id_provider', $script:nsm.LookupNamespace('un')) $authDomainUri = $script:un.CreateElement('ldap_uri', $script:nsm.LookupNamespace('un')) $authClientSssd.InnerText = 'yes' $authClientLdaps.InnerText = 'no' $sssdConfFile.InnerText = 2 $sssdConfServices.InnerText = 'nss, pam' $sssdConfDomains.InnerText = $DomainName $authDomainName.InnerText = $DomainName $authDomainIdp.InnerText = 'ldap' $authDomainUri.InnerText = "ldap://$DomainName" $authDomain.AppendChild($authDomainName) $authDomain.AppendChild($authDomainIdp) $authDomain.AppendChild($authDomainUri) $authDomains.AppendChild($authDomain) $sssdConf.AppendChild($authDomains) $sssdConfNode.AppendChild($sssdConfFile) $sssdConfNode.AppendChild($sssdConfServices) $sssdConfNode.AppendChild($sssdConfDomains) $sssdConf.AppendChild($sssdConfNode) $authClientNode.AppendChild($authClientSssd) $authClientNode.AppendChild($authClientLdaps) $authClientNode.AppendChild($sssdConf) $script:un.DocumentElement.AppendChild($authClientNode) } function Set-UnattendedYastFirewallState { param ( [Parameter(Mandatory = $true)] [boolean]$State ) $fwState = $script:un.SelectSingleNode('/un:profile/un:firewall/un:enable_firewall', $script:nsm) $fwState.InnerText = $State.ToString().ToLower() } function Set-UnattendedYastIpSettings { param ( [string]$IpAddress, [string]$Gateway, [String[]]$DnsServers, [string]$DnsDomain ) } function Set-UnattendedYastLocalIntranetSites { param ( [Parameter(Mandatory = $true)] [string[]]$Values ) } function Set-UnattendedYastPackage { param ( [string[]]$Package ) $packagesNode = $script:un.SelectSingleNode('/un:profile/un:software/un:patterns', $script:nsm) foreach ($p in $Package) { $packageNode = $script:un.CreateElement('pattern', $script:nsm.LookupNamespace('un')) $packageNode.InnerText = $p $null = $packagesNode.AppendChild($packageNode) } } function Set-UnattendedYastProductKey { param ( [Parameter(Mandatory = $true)] [string]$ProductKey ) } function Set-UnattendedYastTimeZone { param ( [Parameter(Mandatory = $true)] [string]$TimeZone ) $tzInfo = Get-TimeZone -Id $TimeZone Write-PSFMessage -Message ('Since non-standard timezone names are used, we revert to Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours) $timeNode = $script:un.SelectSingleNode('/un:profile/un:timezone/un:timezone', $script:nsm) $timeNode.InnerText = if ($tzInfo.BaseUtcOffset.TotalHours -gt 0) { 'Etc/GMT+{0}' -f $tzInfo.BaseUtcOffset.TotalHours } elseif ($tzInfo.BaseUtcOffset.TotalHours -eq 0) { 'Etc/GMT' } else { 'Etc/GMT{0}' -f $tzInfo.BaseUtcOffset.TotalHours } } function Set-UnattendedYastUserLocale { param ( [Parameter(Mandatory = $true)] [string]$UserLocale ) $language = $script:un.SelectSingleNode('/un:profile/un:language', $script:nsm) $languageNode = $script:un.SelectSingleNode('/un:profile/un:language/un:language', $script:nsm) $keyboard = $script:un.SelectSingleNode('/un:profile/un:keyboard/un:keymap', $script:nsm) try { $ci = [cultureinfo]::new($UserLocale) } catch { $ci = [cultureinfo]::new('en-us') } # Primary language $languageNode.InnerText = $ci.IetfLanguageTag -replace '-', '_' # Secondary language if ($ci.Name -ne 'en-US') { $languagesNode = $script:un.CreateElement('languages', $script:nsm.LookupNamespace('un')) $languagesNode.InnerText = 'en-us' $null = $language.AppendChild($languagesNode) } $keyMapName = '{0}-{1}' -f ($ci.EnglishName -split " ")[0].Trim().ToLower(), ($ci.Name -split '-')[-1].ToLower() $keyboard.InnerText = $keyMapName } function Set-UnattendedYastWorkgroup { param ( [Parameter(Mandatory = $true)] [string] $WorkgroupName ) $smbClientNode = $script:un.CreateElement('samba-client', $script:nsm.LookupNamespace('un')) $boolAttrib = $script:un.CreateAttribute('config','type', $script:nsm.LookupNamespace('config')) $boolAttrib.InnerText = 'boolean' $disableDhcp = $script:un.CreateElement('disable_dhcp_hostname', $script:nsm.LookupNamespace('un')) $globalNode = $script:un.CreateElement('global', $script:nsm.LookupNamespace('un')) $securityNode = $script:un.CreateElement('security', $script:nsm.LookupNamespace('un')) $shellNode = $script:un.CreateElement('template_shell', $script:nsm.LookupNamespace('un')) $guestNode = $script:un.CreateElement('usershare_allow_guests', $script:nsm.LookupNamespace('un')) $domainNode = $script:un.CreateElement('workgroup', $script:nsm.LookupNamespace('un')) $homedirNode = $script:un.CreateElement('mkhomedir', $script:nsm.LookupNamespace('un')) $winbindNode = $script:un.CreateElement('winbind', $script:nsm.LookupNamespace('un')) $null = $disableDhcp.Attributes.Append($boolAttrib) $null = $homedirNode.Attributes.Append($boolAttrib) $null = $winbindNode.Attributes.Append($boolAttrib) $disableDhcp.InnerText = 'true' $securityNode.InnerText = 'domain' $shellNode.InnerText = '/bin/bash' $guestNode.InnerText = 'no' $domainNode.InnerText = $DomainName $homedirNode.InnerText = 'true' $winbindNode.InnerText = 'true' $null = $globalNode.AppendChild($securityNode) $null = $globalNode.AppendChild($shellNode) $null = $globalNode.AppendChild($guestNode) $null = $globalNode.AppendChild($domainNode) $null = $smbClientNode.AppendChild($disableDhcp) $null = $smbClientNode.AppendChild($globalNode) $null = $smbClientNode.AppendChild($homedirNode) $null = $smbClientNode.AppendChild($winbindNode) $null = $script:un.DocumentElement.AppendChild($smbClientNode) } function Add-UnattendedWindowsNetworkAdapter { param ( [string]$Interfacename, [AutomatedLab.IPNetwork[]]$IpAddresses, [AutomatedLab.IPAddress[]]$Gateways, [AutomatedLab.IPAddress[]]$DnsServers, [string]$ConnectionSpecificDNSSuffix, [string]$DnsDomain, [string]$UseDomainNameDevolution, [string]$DNSSuffixSearchOrder, [string]$EnableAdapterDomainNameRegistration, [string]$DisableDynamicUpdate, [string]$NetbiosOptions ) function Add-XmlGroup { param ( [string]$XPath, [string]$ElementName, [string]$Action, [string]$KeyValue ) Write-Debug -Message "XPath=$XPath" Write-Debug -Message "ElementName=$ElementName" #$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } #$wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' $rootElement = $script:un | Select-Xml -XPath $XPath -Namespace $script:ns | Select-Object -ExpandProperty Node $element = $script:un.CreateElement($ElementName, $script:un.DocumentElement.NamespaceURI) [Void]$rootElement.AppendChild($element) #[Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, 'add') if ($Action) { [Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, $Action) } if ($KeyValue) { [Void]$element.SetAttribute('keyValue', $script:wcmNamespaceUrl, $KeyValue) } } function Add-XmlElement { param ( [string]$XPath, [string]$ElementName, [string]$Text, [string]$Action, [string]$KeyValue ) Write-Debug -Message "XPath=$XPath" Write-Debug -Message "ElementName=$ElementName" Write-Debug -Message "Text=$Text" #$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } #$wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' $rootElement = $script:un | Select-Xml -XPath $xPath -Namespace $script:ns | Select-Object -ExpandProperty Node $element = $script:un.CreateElement($elementName, $script:un.DocumentElement.NamespaceURI) [Void]$rootElement.AppendChild($element) if ($Action) { [Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, $Action) } if ($KeyValue) { [Void]$element.SetAttribute('keyValue', $script:wcmNamespaceUrl, $KeyValue) } $element.InnerText = $Text } $TCPIPInterfacesNode = '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-TCPIP"]' if (-not ($script:un | Select-Xml -XPath "$TCPIPInterfacesNode/un:Interfaces" -Namespace $script:ns | Select-Object -ExpandProperty Node)) { Add-XmlGroup -XPath "$TCPIPInterfacesNode" -ElementName 'Interfaces' $order = 1 } Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces" -ElementName 'Interface' -Action 'add' Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface" -ElementName 'Ipv4Settings' Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv4Settings" -ElementName 'DhcpEnabled' -Text "$(([string](-not ([boolean]($ipAddresses -match '\.')))).ToLower())" #Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv4Settings" -ElementName 'Metric' -Text '10' #Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv4Settings" -ElementName 'RouterDiscoveryEnabled' -Text 'false' Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface" -ElementName 'Ipv6Settings' Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv6Settings" -ElementName 'DhcpEnabled' -Text "$(([string](-not ([boolean]($ipAddresses -match ':')))).ToLower())" #Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv6Settings" -ElementName 'Metric' -Text '10' #Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Ipv6Settings" -ElementName 'RouterDiscoveryEnabled' -Text 'false' Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface" -ElementName 'Identifier' -Text "$Interfacename" if ($IpAddresses) { Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface" -ElementName 'UnicastIpAddresses' $ipCount = 1 foreach ($ipAddress in $IpAddresses) { Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:UnicastIpAddresses" -ElementName 'IpAddress' -Text "$($ipAddress.IpAddress.AddressAsString)/$($ipAddress.Cidr)" -Action 'add' -KeyValue "$(($ipCount++))" } } if ($gateways) { Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface" -ElementName 'Routes' $gatewayCount = 0 foreach ($gateway in $gateways) { Add-XmlGroup -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Routes" -ElementName 'Route' -Action 'add' Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Routes/un:Route" -ElementName 'Identifier' -Text "$(($gatewayCount++))" #Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Routes/un:Route" -ElementName 'Metric' -Text '0' Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Routes/un:Route" -ElementName 'NextHopAddress' -Text $gateway if ($gateway -match ':') { $prefix = '::/0' } else { $prefix = '0.0.0.0/0' } Add-XmlElement -XPath "$TCPIPInterfacesNode/un:Interfaces/un:Interface/un:Routes/un:Route" -ElementName 'Prefix' -Text $prefix } } $DNSClientNode = '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-DNS-Client"]' #if ($UseDomainNameDevolution) #{ # Add-XmlElement -XPath "$DNSClientNode" -ElementName 'UseDomainNameDevolution' -Text "$UseDomainNameDevolution" #} if ($DNSSuffixSearchOrder) { if (-not ($script:un | Select-Xml -XPath "$DNSClientNode/un:DNSSuffixSearchOrder" -Namespace $script:ns | Select-Object -ExpandProperty Node)) { Add-XmlGroup -XPath "$DNSClientNode" -ElementName 'DNSSuffixSearchOrder' -Action 'add' $order = 1 } else { $nodes = ($script:un | Select-Xml -XPath "$DNSClientNode/un:DNSSuffixSearchOrder" -Namespace $script:ns | Select-Object -ExpandProperty Node).childnodes $order = ($nodes | Measure-Object).count+1 } foreach ($DNSSuffix in $DNSSuffixSearchOrder) { Add-XmlElement -XPath "$DNSClientNode/un:DNSSuffixSearchOrder" -ElementName 'DomainName' -Text $DNSSuffix -Action 'add' -KeyValue "$(($order++))" } } if (-not ($script:un | Select-Xml -XPath "$DNSClientNode/un:Interfaces" -Namespace $script:ns | Select-Object -ExpandProperty Node)) { Add-XmlGroup -XPath "$DNSClientNode" -ElementName 'Interfaces' $order = 1 } Add-XmlGroup -XPath "$DNSClientNode/un:Interfaces" -ElementName 'Interface' -Action 'add' Add-XmlElement -XPath "$DNSClientNode/un:Interfaces/un:Interface" -ElementName 'Identifier' -Text "$Interfacename" if ($DnsDomain) { Add-XmlElement -XPath "$DNSClientNode/un:Interfaces/un:Interface" -ElementName 'DNSDomain' -Text "$DnsDomain" } if ($dnsServers) { Add-XmlGroup -XPath "$DNSClientNode/un:Interfaces/un:Interface" -ElementName 'DNSServerSearchOrder' $dnsServersCount = 1 foreach ($dnsServer in $dnsServers) { Add-XmlElement -XPath "$DNSClientNode/un:Interfaces/un:Interface/un:DNSServerSearchOrder" -ElementName 'IpAddress' -Text $dnsServer -Action 'add' -KeyValue "$(($dnsServersCount++))" } } Add-XmlElement -XPath "$DNSClientNode/un:Interfaces/un:Interface" -ElementName 'EnableAdapterDomainNameRegistration' -Text $EnableAdapterDomainNameRegistration Add-XmlElement -XPath "$DNSClientNode/un:Interfaces/un:Interface" -ElementName 'DisableDynamicUpdate' -Text $DisableDynamicUpdate $NetBTNode = '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-NetBT"]' if (-not ($script:un | Select-Xml -XPath "$NetBTNode/un:Interfaces" -Namespace $script:ns | Select-Object -ExpandProperty Node)) { Add-XmlGroup -XPath "$NetBTNode" -ElementName 'Interfaces' } Add-XmlGroup -XPath "$NetBTNode/un:Interfaces" -ElementName 'Interface' -Action 'add' Add-XmlElement -XPath "$NetBTNode/un:Interfaces/un:Interface" -ElementName 'NetbiosOptions' -Text $NetbiosOptions Add-XmlElement -XPath "$NetBTNode/un:Interfaces/un:Interface" -ElementName 'Identifier' -Text "$Interfacename" } function Add-UnattendedWindowsRenameNetworkAdapters { function Add-XmlGroup { param ( $XPath, $ElementName, $Action, $KeyValue ) Write-Debug -Message "XPath=$XPath" Write-Debug -Message "ElementName=$ElementName" #$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } #$wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' $rootElement = $script:un | Select-Xml -XPath $xPath -Namespace $script:ns | Select-Object -ExpandProperty Node $element = $script:un.CreateElement($elementName) [Void]$rootElement.AppendChild($element) #[Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, 'add') if ($Action) { [Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, $Action) } if ($KeyValue) { [Void]$element.SetAttribute('keyValue', $script:wcmNamespaceUrl, $KeyValue) } } function Add-XmlElement { param ( $rootElement, $ElementName, $Text, $Action, $KeyValue ) Write-Debug -Message "XPath=$XPath" Write-Debug -Message "ElementName=$ElementName" Write-Debug -Message "Text=$Text" #$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } #$wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' #$rootElement = $script:un | Select-Xml -XPath $xPath -Namespace $script:ns | Select-Object -ExpandProperty Node $element = $script:un.CreateElement($elementName) [Void]$rootElement.AppendChild($element) if ($Action) { [Void]$element.SetAttribute('action', $script:wcmNamespaceUrl, $Action) } if ($KeyValue) { [Void]$element.SetAttribute('keyValue', $script:wcmNamespaceUrl, $KeyValue) } $element.InnerText = $Text } $order = (($script:un | Select-Xml -XPath "$WinPENode/un:RunSynchronousCommand" -Namespace $script:ns).node.childnodes.order | Measure-Object -Maximum).maximum $order++ Add-XmlGroup -XPath '//un:settings[@pass = "oobeSystem"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]/un:FirstLogonCommands' -ElementName 'SynchronousCommand' -Action 'add' $nodes = ($script:un | Select-Xml -XPath '//un:settings[@pass = "oobeSystem"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]/un:FirstLogonCommands' -Namespace $script:ns | Select-Object -ExpandProperty Node).childnodes $order = ($nodes | Measure-Object).count $rootElement = $nodes[$order-1] Add-XmlElement -RootElement $rootElement -ElementName 'Description' -Text 'Rename network adapters' Add-XmlElement -RootElement $rootElement -ElementName 'Order' -Text "$order" Add-XmlElement -RootElement $rootElement -ElementName 'CommandLine' -Text 'powershell.exe -executionpolicy bypass -file "c:\RenameNetworkAdapters.ps1"' } function Add-UnattendedWindowsSynchronousCommand { param ( [Parameter(Mandatory)] [string]$Command, [Parameter(Mandatory)] [string]$Description ) $highestOrder = ($un | Select-Xml -Namespace $ns -XPath //un:RunSynchronous).Node.RunSynchronousCommand.Order | Sort-Object -Property { [int]$_ } -Descending | Select-Object -First 1 $runSynchronousNode = ($un | Select-Xml -Namespace $ns -XPath //un:RunSynchronous).Node $runSynchronousCommandNode = $un.CreateElement('RunSynchronousCommand') [Void]$runSynchronousCommandNode.SetAttribute('action', $wcmNamespaceUrl, 'add') $runSynchronousCommandDescriptionNode = $un.CreateElement('Description') $runSynchronousCommandDescriptionNode.InnerText = $Description $runSynchronousCommandOrderNode = $un.CreateElement('Order') $runSynchronousCommandOrderNode.InnerText = ([int]$highestOrder + 1) $runSynchronousCommandPathNode = $un.CreateElement('Path') $runSynchronousCommandPathNode.InnerText = $Command [void]$runSynchronousCommandNode.AppendChild($runSynchronousCommandDescriptionNode) [void]$runSynchronousCommandNode.AppendChild($runSynchronousCommandOrderNode) [void]$runSynchronousCommandNode.AppendChild($runSynchronousCommandPathNode) [void]$runSynchronousNode.AppendChild($runSynchronousCommandNode) } function Export-UnattendedWindowsFile { param ( [Parameter(Mandatory = $true)] [string]$Path ) $script:un.Save($Path) } function Import-UnattendedWindowsContent { param ( [Parameter(Mandatory = $true)] [xml] $Content ) $script:un = $Content $script:ns = @{ un = 'urn:schemas-microsoft-com:unattend' } $Script:wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' } function Set-UnattendedWindowsDomain { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password, [Parameter()] [string]$OrganizationalUnit ) $idNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-UnattendedJoin"]/un:Identification' -Namespace $ns | Select-Object -ExpandProperty Node $idNode.RemoveAll() $joinDomainNode = $script:un.CreateElement('JoinDomain') $joinDomainNode.InnerText = $DomainName $credentialsNode = $script:un.CreateElement('Credentials') $domainNode = $script:un.CreateElement('Domain') $domainNode.InnerText = $DomainName $userNameNode = $script:un.CreateElement('Username') $userNameNode.InnerText = $Username $passwordNode = $script:un.CreateElement('Password') $passwordNode.InnerText = $Password if ($OrganizationalUnit) { $ouNode = $script:un.CreateElement('MachineObjectOU') $ouNode.InnerText = $OrganizationalUnit $null = $idNode.AppendChild($ouNode) } [Void]$credentialsNode.AppendChild($domainNode) [Void]$credentialsNode.AppendChild($userNameNode) [Void]$credentialsNode.AppendChild($passwordNode) [Void]$idNode.AppendChild($credentialsNode) [Void]$idNode.AppendChild($joinDomainNode) } function Set-UnattendedWindowsAdministratorName { param ( [Parameter(Mandatory = $true)] [string]$Name ) $shellNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "oobeSystem"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $shellNode.UserAccounts.LocalAccounts.LocalAccount.Name = $Name $shellNode.UserAccounts.LocalAccounts.LocalAccount.DisplayName = $Name } function Set-UnattendedWindowsAdministratorPassword { param ( [Parameter(Mandatory = $true)] [string]$Password ) $shellNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "oobeSystem"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $shellNode.UserAccounts.AdministratorPassword.Value = $Password $shellNode.UserAccounts.AdministratorPassword.PlainText = 'true' $shellNode.UserAccounts.LocalAccounts.LocalAccount.Password.Value = $Password } function Set-UnattendedWindowsAntiMalware { param ( [Parameter(Mandatory = $true)] [bool]$Enabled ) $node = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Security-Malware-Windows-Defender"]' -Namespace $ns | Select-Object -ExpandProperty Node if ($Enabled) { $node.DisableAntiSpyware = 'true' } else { $node.DisableAntiSpyware = 'false' } } function Set-UnattendedWindowsAutoLogon { param ( [Parameter(Mandatory = $true)] [string]$DomainName, [Parameter(Mandatory = $true)] [string]$Username, [Parameter(Mandatory = $true)] [string]$Password ) $shellNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $autoLogonNode = $script:un.CreateElement('AutoLogon') $passwordNode = $script:un.CreateElement('Password') $passwordValueNode = $script:un.CreateElement('Value') $passwordValueNode.InnerText = $Password $domainNode = $script:un.CreateElement('Domain') $domainNode.InnerText = $DomainName $enabledNode = $script:un.CreateElement('Enabled') $enabledNode.InnerText = 'true' $logonCount = $script:un.CreateElement('LogonCount') $logonCount.InnerText = '9999' $userNameNode = $script:un.CreateElement('Username') $userNameNode.InnerText = $Username [Void]$autoLogonNode.AppendChild($passwordNode) [Void]$passwordNode.AppendChild($passwordValueNode) [Void]$autoLogonNode.AppendChild($domainNode) [Void]$autoLogonNode.AppendChild($enabledNode) [Void]$autoLogonNode.AppendChild($logonCount) [Void]$autoLogonNode.AppendChild($userNameNode) [Void]$shellNode.AppendChild($autoLogonNode) } function Set-UnattendedWindowsComputerName { param ( [Parameter(Mandatory = $true)] [string]$ComputerName ) $component = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $component.ComputerName = $ComputerName } function Set-UnattendedWindowsFirewallState { param ( [Parameter(Mandatory = $true)] [boolean]$State ) $setupNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Networking-MPSSVC-Svc"]' -Namespace $ns | Select-Object -ExpandProperty Node $WindowsFirewallStateNode = $script:un.CreateElement('DomainProfile_EnableFirewall') $WindowsFirewallStateNode.InnerText = ([string]$State).ToLower() [Void]$setupNode.AppendChild($WindowsFirewallStateNode) $WindowsFirewallStateNode = $script:un.CreateElement('PrivateProfile_EnableFirewall') $WindowsFirewallStateNode.InnerText = ([string]$State).ToLower() [Void]$setupNode.AppendChild($WindowsFirewallStateNode) $WindowsFirewallStateNode = $script:un.CreateElement('PublicProfile_EnableFirewall') $WindowsFirewallStateNode.InnerText = ([string]$State).ToLower() [Void]$setupNode.AppendChild($WindowsFirewallStateNode) } function Set-UnattendedWindowsIpSettings { param ( [string]$IpAddress, [string]$Gateway, [String[]]$DnsServers, [string]$DnsDomain ) $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-TCPIP"]/un:Interfaces/un:Interface[un:Identifier = "Ethernet"]' -Namespace $ns | Select-Object -ExpandProperty Node if (-not $ethernetInterface) { $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-TCPIP"]/un:Interfaces/un:Interface[un:Identifier = "Local Area Connection"]' -Namespace $ns | Select-Object -ExpandProperty Node } if ($IpAddress) { $ethernetInterface.Ipv4Settings.DhcpEnabled = 'false' $ethernetInterface.UnicastIpAddresses.IpAddress.InnerText = $IpAddress } if ($Gateway) { $InterfaceElement = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-TCPIP"]/un:Interfaces/un:Interface' -Namespace $ns | Select-Object -ExpandProperty Node $RoutesNode = $script:un.CreateElement('Routes') [Void]$InterfaceElement.AppendChild($RoutesNode) $routes = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-TCPIP"]/un:Interfaces/un:Interface/un:Routes' -Namespace $ns | Select-Object -ExpandProperty Node $routeElement = $script:un.CreateElement('Route') $identifierElement = $script:un.CreateElement('Identifier') $prefixElement = $script:un.CreateElement('Prefix') $nextHopAddressElement = $script:un.CreateElement('NextHopAddress') [void]$routeElement.AppendChild($identifierElement) [void]$routeElement.AppendChild($prefixElement) [void]$routeElement.AppendChild($nextHopAddressElement) [Void]$routeElement.SetAttribute('action', $wcmNamespaceUrl, 'add') $identifierElement.InnerText = '0' $prefixElement.InnerText = '0.0.0.0/0' $nextHopAddressElement.InnerText = $Gateway [void]$RoutesNode.AppendChild($routeElement) } <# <Routes> <Route wcm:action="add"> <Identifier>0</Identifier> <Prefix>0.0.0.0/0</Prefix> <NextHopAddress></NextHopAddress> </Route> </Routes> #> if ($DnsServers) { $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-DNS-Client"]/un:Interfaces/un:Interface[un:Identifier = "Ethernet"]' -Namespace $ns | Select-Object -ExpandProperty Node -ErrorAction SilentlyContinue if (-not $ethernetInterface) { $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-DNS-Client"]/un:Interfaces/un:Interface[un:Identifier = "Local Area Connection"]' -Namespace $ns | Select-Object -ExpandProperty Node -ErrorAction SilentlyContinue } <# <DNSServerSearchOrder> <IpAddress wcm:action="add" wcm:keyValue="1">10.0.0.10</IpAddress> </DNSServerSearchOrder> #> $dnsServerSearchOrder = $script:un.CreateElement('DNSServerSearchOrder') $i = 1 foreach ($dnsServer in $DnsServers) { $ipAddressElement = $script:un.CreateElement('IpAddress') [Void]$ipAddressElement.SetAttribute('action', $wcmNamespaceUrl, 'add') [Void]$ipAddressElement.SetAttribute('keyValue', $wcmNamespaceUrl, "$i") $ipAddressElement.InnerText = $dnsServer [Void]$dnsServerSearchOrder.AppendChild($ipAddressElement) $i++ } [Void]$ethernetInterface.AppendChild($dnsServerSearchOrder) } <# <DNSDomain>something.com</DNSDomain> #> if ($DnsDomain) { $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-DNS-Client"]/un:Interfaces/un:Interface[un:Identifier = "Ethernet"]' -Namespace $ns | Select-Object -ExpandProperty Node -ErrorAction SilentlyContinue if (-not $ethernetInterface) { $ethernetInterface = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-DNS-Client"]/un:Interfaces/un:Interface[un:Identifier = "Local Area Connection"]' -Namespace $ns | Select-Object -ExpandProperty Node -ErrorAction SilentlyContinue } $dnsDomainElement = $script:un.CreateElement('DNSDomain') $dnsDomainElement.InnerText = $DnsDomain [Void]$ethernetInterface.AppendChild($dnsDomainElement) } } function Set-UnattendedWindowsLocalIntranetSites { param ( [Parameter(Mandatory = $true)] [string[]]$Values ) $ieNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-IE-InternetExplorer"]' -Namespace $ns | Select-Object -ExpandProperty Node $ieNode.LocalIntranetSites = $Values -join ';' } function Set-UnattendedWindowsPackage { param ( [string[]]$Package ) } function Set-UnattendedWindowsProductKey { param ( [Parameter(Mandatory = $true)] [string]$ProductKey ) $setupNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $productKeyNode = $script:un.CreateElement('ProductKey') $productKeyNode.InnerText = $ProductKey [Void]$setupNode.AppendChild($productKeyNode) } function Set-UnattendedWindowsTimeZone { param ( [Parameter(Mandatory = $true)] [string]$TimeZone ) $component = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | Select-Object -ExpandProperty Node $component.TimeZone = $TimeZone } function Set-UnattendedWindowsUserLocale { param ( [Parameter(Mandatory = $true)] [string]$UserLocale ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $component = $script:un | Select-Xml -XPath '//un:settings[@pass = "oobeSystem"]/un:component[@name = "Microsoft-Windows-International-Core"]' -Namespace $ns | Select-Object -ExpandProperty Node #this is for getting the input locale strings like '0409:00000409' $component.UserLocale = $UserLocale if ($IsLinux) { $inputLocale = '0409:00000409' } else { try { $inputLocale = @((New-WinUserLanguageList -Language $UserLocale).InputMethodTips) $inputLocale += (New-WinUserLanguageList -Language 'en-us').InputMethodTips } catch { Remove-Module -Name International -ErrorAction SilentlyContinue -Force Get-ChildItem -Directory -Path ([IO.Path]::GetTempPath()) -Filter RemoteIpMoProxy_International*_localhost_* | Remove-Item -Recurse -Force if ((Get-Command Import-Module).Parameters.ContainsKey('UseWindowsPowerShell')) { Import-Module -Name International -UseWindowsPowerShell -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -Force } else { Import-WinModule -Name International -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -Force } $inputLocale = @((New-WinUserLanguageList -Language $UserLocale).InputMethodTips) $inputLocale += (New-WinUserLanguageList -Language 'en-us').InputMethodTips } } if ($inputLocale) { $component.InputLocale = ($inputLocale -join ';') } } function Set-UnattendedWindowsWorkgroup { param ( [Parameter(Mandatory = $true)] [string] $WorkgroupName ) $idNode = $script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-UnattendedJoin"]/un:Identification' -Namespace $ns | Select-Object -ExpandProperty Node $idNode.RemoveAll() $workGroupNode = $script:un.CreateElement('JoinWorkgroup') $workGroupNode.InnerText = $WorkgroupName [Void]$idNode.AppendChild($workGroupNode) } function Add-UnattendedNetworkAdapter { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$Interfacename, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [AutomatedLab.IPNetwork[]]$IpAddresses, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [AutomatedLab.IPAddress[]]$Gateways, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [AutomatedLab.IPAddress[]]$DnsServers, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$ConnectionSpecificDNSSuffix, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$DnsDomain, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$UseDomainNameDevolution, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$DNSSuffixSearchOrder, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$EnableAdapterDomainNameRegistration, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$DisableDynamicUpdate, [Parameter(ParameterSetName='Windows')] [Parameter(ParameterSetName='Kickstart')] [Parameter(ParameterSetName='Yast')] [Parameter(ParameterSetName='CloudInit')] [string]$NetbiosOptions, [Parameter(ParameterSetName='Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName='Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName='CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Add-UnattendedRenameNetworkAdapters { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName='Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName='Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName='CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") & $command } function Add-UnattendedSynchronousCommand { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName='Windows', Mandatory = $true)] [Parameter(ParameterSetName='Kickstart', Mandatory = $true)] [Parameter(ParameterSetName='Yast', Mandatory = $true)] [Parameter(ParameterSetName='CloudInit', Mandatory = $true)] [string]$Command, [Parameter(ParameterSetName='Windows', Mandatory = $true)] [Parameter(ParameterSetName='Kickstart', Mandatory = $true)] [Parameter(ParameterSetName='Yast', Mandatory = $true)] [Parameter(ParameterSetName='CloudInit', Mandatory = $true)] [string]$Description, [Parameter(ParameterSetName='Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName='Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName='CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $commandObject = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $commandObject -Parameters $PSBoundParameters & $commandObject @parameters } function Export-UnattendedFile { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName='Windows', Mandatory = $true)] [Parameter(ParameterSetName='Kickstart', Mandatory = $true)] [Parameter(ParameterSetName='Yast', Mandatory = $true)] [Parameter(ParameterSetName='CloudInit', Mandatory = $true)] [string]$Path, [Parameter(ParameterSetName='Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName='Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName='CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Get-UnattendedContent { [CmdletBinding()] param () return $script:un } function Import-UnattendedContent { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string[]] $Content, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Import-UnattendedFile { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$Path ) $script:un = [xml](Get-Content -Path $Path) $script:ns = @{ un = 'urn:schemas-microsoft-com:unattend' } $Script:wcmNamespaceUrl = 'http://schemas.microsoft.com/WMIConfig/2002/State' } function Set-UnattendedAdministratorName { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Name, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedAdministratorPassword { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Password, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedAntiMalware { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [bool]$Enabled, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedAutoLogon { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$DomainName, [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Username, [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Password, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedComputerName { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$ComputerName, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedDomain { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$DomainName, [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Username, [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$Password, [Parameter()] [string]$OrganizationalUnit, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedFirewallState { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [boolean]$State, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedIpSettings { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows')] [Parameter(ParameterSetName = 'Kickstart')] [Parameter(ParameterSetName = 'Yast')] [Parameter(ParameterSetName = 'CloudInit')] [string]$IpAddress, [Parameter(ParameterSetName = 'Windows')] [Parameter(ParameterSetName = 'Kickstart')] [Parameter(ParameterSetName = 'Yast')] [Parameter(ParameterSetName = 'CloudInit')] [string]$Gateway, [Parameter(ParameterSetName = 'Windows')] [Parameter(ParameterSetName = 'Kickstart')] [Parameter(ParameterSetName = 'Yast')] [Parameter(ParameterSetName = 'CloudInit')] [String[]]$DnsServers, [Parameter(ParameterSetName = 'Windows')] [Parameter(ParameterSetName = 'Kickstart')] [Parameter(ParameterSetName = 'Yast')] [Parameter(ParameterSetName = 'CloudInit')] [string]$DnsDomain, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedLocalIntranetSites { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string[]]$Values, [Parameter(ParameterSetName='Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName='Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName='CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedPackage { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string[]]$Package, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedProductKey { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$ProductKey, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedTimeZone { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$TimeZone, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedUserLocale { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$UserLocale, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } function Set-UnattendedWorkgroup { [CmdletBinding(DefaultParameterSetName = 'Windows')] param ( [Parameter(ParameterSetName = 'Windows', Mandatory = $true)] [Parameter(ParameterSetName = 'Kickstart', Mandatory = $true)] [Parameter(ParameterSetName = 'Yast', Mandatory = $true)] [Parameter(ParameterSetName = 'CloudInit', Mandatory = $true)] [string]$WorkgroupName, [Parameter(ParameterSetName = 'Kickstart')] [switch] $IsKickstart, [Parameter(ParameterSetName = 'Yast')] [switch] $IsAutoYast, [Parameter(ParameterSetName = 'CloudInit')] [switch] $IsCloudInit ) if (-not $script:un) { Write-Error 'No unattended file imported. Please use Import-UnattendedFile first' return } $command = Get-Command -Name $PSCmdlet.MyInvocation.MyCommand.Name.Replace('Unattended', "Unattended$($PSCmdlet.ParameterSetName)") $parameters = Sync-Parameter $command -Parameters $PSBoundParameters & $command @parameters } Export-ModuleMember -Function Add-UnattendedNetworkAdapter,Add-UnattendedRenameNetworkAdapters,Add-UnattendedSynchronousCommand,Export-UnattendedFile,Get-UnattendedContent,Import-UnattendedContent,Import-UnattendedFile,Set-UnattendedAdministratorName,Set-UnattendedAdministratorPassword,Set-UnattendedAntiMalware,Set-UnattendedAutoLogon,Set-UnattendedComputerName,Set-UnattendedDomain,Set-UnattendedFirewallState,Set-UnattendedIpSettings,Set-UnattendedLocalIntranetSites,Set-UnattendedPackage,Set-UnattendedProductKey,Set-UnattendedTimeZone,Set-UnattendedUserLocale,Set-UnattendedWorkgroup |