AutomatedLabUnattended.psm1

#region Import-UnattendedFile
function Import-UnattendedFile
{
    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'
}
#endregion Import-UnattendedFile

#region Import-UnattendedContent
function Import-UnattendedContent
{
    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'
}
#endregion Import-UnattendedContent

#region Get-UnattendedContent
function Get-UnattendedContent
{
    param ()
    
    return $script:un
}
#endregion Get-UnattendedContent

#region Export-UnattendedFile
function Export-UnattendedFile
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )
    
    $script:un.Save($Path)
}
#endregion Export-UnattendedFile

#region Set-UnattendedComputerName
function Set-UnattendedComputerName
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$ComputerName
    )
    
    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 = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns |
    Select-Object -ExpandProperty Node
    
    $component.ComputerName = $ComputerName
}
#endregion

#region Set-UnattendedUserLocale
function Set-UnattendedUserLocale
{
    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
    $inputLocale = @((New-WinUserLanguageList -Language $UserLocale).InputMethodTips)
    $inputLocale += (New-WinUserLanguageList -Language 'en-us').InputMethodTips
    
    if ($inputLocale)
    {
        $component.InputLocale = ($inputLocale -join ';')
    }
}
#endregion Set-UnattendedUserLocale

#region Set-UnattendedTimeZone
function Set-UnattendedTimeZone
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$TimeZone
    )
    
    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 = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns |
    Select-Object -ExpandProperty Node
    
    $component.TimeZone = $TimeZone
}
#endregion Set-UnattendedTimeZone

#region Set-UnattendedWorkgroup
function Set-UnattendedWorkgroup
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$WorkgroupName
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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)
}
#endregion Set-UnattendedWorkgroup

#region Set-UnattendedDomain
function Set-UnattendedDomain
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$DomainName,
        
        [Parameter(Mandatory = $true)]
        [string]$Username,
        
        [Parameter(Mandatory = $true)]
        [string]$Password
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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
    
    [Void]$credentialsNode.AppendChild($domainNode)
    [Void]$credentialsNode.AppendChild($userNameNode)
    [Void]$credentialsNode.AppendChild($passwordNode)
    
    [Void]$idNode.AppendChild($credentialsNode)
    [Void]$idNode.AppendChild($joinDomainNode)
}
#endregion Set-UnattendedDomain

#region Set-UnattendedAutoLogon
function Set-UnattendedAutoLogon
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$DomainName,
        
        [Parameter(Mandatory = $true)]
        [string]$Username,
        
        [Parameter(Mandatory = $true)]
        [string]$Password
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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)
}
#endregion Set-UnattendedAutoLogon

#region Set-UnattendedAdministratorPassword
function Set-UnattendedAdministratorPassword
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$Password
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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
}
#endregion Set-UnattendedAdministratorPassword

#region Set-UnattendedAdministratorName
function Set-UnattendedAdministratorName
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$Name
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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
}
#endregion Set-UnattendedAdministratorName

#region Set-UnattendedComputerName
function Set-UnattendedIpSettings
{
    param (
        [string]$IpAddress,
        
        [string]$Gateway,
        
        [String[]]$DnsServers,

        [string]$DnsDomain
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    
    $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)
    }
}
#endregion

#region Add-UnattendedNetworkAdapter
function Add-UnattendedNetworkAdapter
{
    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
    }
    
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    <#
    if (-not ($script:un | Select-Xml -XPath '//un:settings[@pass = "specialize"]' -Namespace $script:ns | Select-Object -ExpandProperty Node))
    {
        Add-XmlGroup -XPath "$TCPIPInterfacesNode" -ElementName 'Microsoft-Windows-TCPIP'
        <component name="Microsoft-Windows-TCPIP" 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">
        </component>
    }
    #>


    $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"

}
#endregion Add-UnattendedNetworkAdapter

#region Add-UnattendedRenameNetworkAdapters
function Add-UnattendedRenameNetworkAdapters
{
    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
    }
    
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    
    $order = (($script:un | Select-Xml -XPath "$WinPENode/un:RunSynchronousCommand" -Namespace $script:ns).node.childnodes.order | measure -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"'
    
}
#endregion Add-UnattendedRenameNetworkAdapters

#OBSOLETE
#region Add-UnattendedRenameNetworkAdapter
function Add-UnattendedRenameNetworkAdapter
{
    param (
        [string]$OldInterfaceName,

        [string]$NewInterfaceName
    )
    
    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
    }
    
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $order = (($script:un | Select-Xml -XPath "$TCPIPInterfacesNode/un:RunSynchronous" -Namespace $script:ns).node.childnodes.order | measure -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 adapter ""$OldInterfaceName"" newname=""$NewInterfaceName"""
    Add-XmlElement -RootElement $rootElement -ElementName 'Order' -Text "$order"
    Add-XmlElement -RootElement $rootElement -ElementName 'CommandLine' -Text "cmd /c netsh interface set interface name=""$OldInterfaceName"" newname=""$NewInterfaceName"""
}
#endregion Add-UnattendedRenameNetworkAdapter

#region Set-UnattendedProductKey
function Set-UnattendedProductKey
{
    param (
        [Parameter(Mandatory = $true)]
        [string]$ProductKey
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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)
}
#endregion Set-UnattendedProductKey

#region Add-UnattendedSynchronousCommand
function Add-UnattendedSynchronousCommand
{
    param (
        [Parameter(Mandatory)]
        [string]$Command,
        
        [Parameter(Mandatory)]
        [string]$Description
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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)
}
#endregion Add-UnattendedSynchronousCommand

#region Set-WindowsFirewallState
function Set-WindowsFirewallState
{
    param (
        [Parameter(Mandatory = $true)]
        [boolean]$State
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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
    [Void]$setupNode.AppendChild($WindowsFirewallStateNode)

    $WindowsFirewallStateNode = $script:un.CreateElement('PrivateProfile_EnableFirewall')
    $WindowsFirewallStateNode.InnerText = [string]$State
    [Void]$setupNode.AppendChild($WindowsFirewallStateNode)

    $WindowsFirewallStateNode = $script:un.CreateElement('PublicProfile_EnableFirewall')
    $WindowsFirewallStateNode.InnerText = [string]$State
    [Void]$setupNode.AppendChild($WindowsFirewallStateNode)
}
#endregion Set-WindowsFirewallState

#region Set-LocalIntranetSites
function Set-LocalIntranetSites
{
    param (
        [Parameter(Mandatory = $true)]
        [string[]]$Values
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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 ';'
}
#endregion Set-LocalIntranetSites

#region Set-UnattendedWindowsDefender
function Set-UnattendedWindowsDefender
{
    param (
        [Parameter(Mandatory = $true)]
        [bool]$Enabled
    )
    
    if (-not $script:un)
    {
        Write-Error 'No unattended file imported. Please use Import-UnattendedFile first'
        return
    }
    
    $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'
    }
}
#endregion Set-UnattendedWindowsDefender