DSC Resource: Create an unattend.xml file
Today, it’s a quick post to give you a custom dsc Resource of mine..
Bellow, here is a script that you have to reg in a *.psm1 file to enable you creating very basic unattend.xml file for your installations, it’s very helpfull when building your home lab, or other infras 🙂
Like always with DSC, here is how create it and use it 🙂
The unattend template file credit goes to @energizedtech from his technet hyper-v script 🙂
Using in a configuration
configuration Unattend { Import-DscResource -module cUnattend Node localhost { cUnattend Basic { Name = "srv01" Organization = "This is a test" Owner = "Fabien Dibot" Timezone = "Greenwich Standard Time" AdminPassword = "P4ssw0rd!" ProductKey = "Some-product_key" TargetPath = "G:\Scripts\unattend.XML" Ensure = "Present" TemplatePath = "C:\Program Files\WindowsPowerShell\Modules\cUnattend\DSCResources\cUnattend\unattend-template.xml" } } } Push-Location G:\Scripts Unattend
 Building the resource
To build the skeleton, please use New-xDscResource cmdlet 😉
$TemplatePath = New-xDscResourceProperty -Name TemplatePath -Type String -Attribute Write $Name = New-xDscResourceProperty -Name Name -Type String -Attribute Key $Organization = New-xDscResourceProperty -Name Organization -Type String -Attribute Write $Owner = New-xDscResourceProperty -Name Owner -Type String -Attribute Write $TimeZone = New-xDscResourceProperty -Name TimeZone -Type String -Attribute Write $AdminPassword = New-xDscResourceProperty -Name AdminPassword -Type String -Attribute Write $ProductKey = New-xDscResourceProperty -Name ProductKey -Type String -Attribute Write $Ensure = New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -ValidateSet "Present", "Absent" $TargetPath = New-xDscResourceProperty -Name TargetPath -Type String -Attribute Write #Now create the resource New-xDscResource -Name cUnattend -Property $Name,$TemplatePath,$Organization,$Owner,$TimeZone,$AdminPassword,$ProductKey,$Ensure,$TargetPath -Path 'C:\Program Files\WindowsPowerShell\Modules\cUnattend'
Once the modules directory created pleas put a psd1 file in the module root directory ->Â C:\Program Files\WindowsPowerShell\Modules\cUnattend
@{ # Version number of this module. ModuleVersion = '1.0' # ID used to uniquely identify this module GUID = '5106df04-d187-462a-9baf-89bea7babc05' # Author of this module Author = 'Fabien Dibot' # Description of the functionality provided by this module Description = 'Module with DSC Resources for creating unattended files' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '5.0' # Functions to export from this module FunctionsToExport = '*' # Cmdlets to export from this module CmdletsToExport = '*' }
Overwrite the psm1 file by this code:
function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $Name, [System.String] $TargetPath ) Write-Verbose "Collecting datas from the unattend file" if (Test-Path $TargetPath) { [XML]$Unattend = Get-Content -LiteralPath $TargetPath $returnValue = @{ TargetPath = $TargetPath Name = $Unattend.unattend.settings.component[0].ComputerName Organization = $Unattend.unattend.settings.component[0].RegisteredOrganization Owner = $Unattend.unattend.settings.component[0].RegisteredOwner TimeZone = $Unattend.unattend.settings.component[0].TimeZone AdminPassword = $Unattend.unattend.settings.component[1].AutoLogon.Password.Value ProductKey = $Unattend.unattend.settings.component[0].ProductKey Ensure = "Present" } $returnValue } else { Write-Verbose "$TargetPath not present on system." } } function Set-TargetResource { [CmdletBinding()] param ( [System.String] $TemplatePath = "C:\Program Files\WindowsPowerShell\Modules\cUnattend\DSCResources\cUnattend\Unattend-template.xml", [parameter(Mandatory = $true)] [System.String] $Name, [System.String] $Organization, [System.String] $Owner, [ValidateSet("Yakutsk Standard Time", "West Pacific Standard Time", "West Asia Standard Time", "W. Europe Standard Time", "W. Central Africa Standard Time", "W. Australia Standard Time", "Vladivostok Standard Time", "US Mountain Standard Time", "US Eastern Standard Time", "Tonga Standard Time", "Tokyo Standard Time", "Tasmania Standard Time", "Taipei Standard Time", "Sri Lanka Standard Time", "South Africa Standard Time", "Singapore Standard Time", "SE Asia Standard Time", "Samoa Standard Time", "SA Western Standard Time", "SA Pacific Standard Time", "SA Eastern Standard Time", "Russian Standard Time", "Romance Standard Time", "Pacific Standard Time", "Pacific SA Standard Time", "North Asia Standard Time", "North Asia East Standard Time", "Newfoundland Standard Time", "New Zealand Standard Time", "Nepal Standard Time", "Namibia Standard Time", "N. Central Asia Standard Time", "Myanmar Standard Time", "Mountain Standard Time (Mexico)", "Mountain Standard Time", "Mid-Atlantic Standard Time", "Korea Standard Time", "Israel Standard Time", "Iran Standard Time", "India Standard Time", "Hawaiian Standard Time", "GTB Standard Time", "Greenwich Standard Time", "Greenland Standard Time", "GMT Standard Time", "Georgian Standard Time", "FLE Standard Time", "Fiji Standard Time", "Ekaterinburg Standard Time", "Egypt Standard Time", "Eastern Standard Time", "E. South America Standard Time", "E. Europe Standard Time", "E. Australia Standard Time", "E. Africa Standard Time", "Dateline Standard Time", "China Standard Time", "Central Standard Time (Mexico)", "Central Standard Time", "Central Pacific Standard Time", "Central European Standard Time", "Central Europe Standard Time", "Central Brazilian Standard Time", "Central Asia Standard Time", "Central America Standard Time", "Cen. Australia Standard Time", "Caucasus Standard Time", "Cape Verde Standard Time", "Canada Central Standard Time", "Azores Standard Time", "Azerbaijan Standard Time", "AUS Eastern Standard Time", "AUS Central Standard Time", "Atlantic Standard Time", "Arabic Standard Time", "Arabian Standard Time", "Arab Standard Time", "Alaskan Standard Time", "Afghanistan Standard Time", "Yakutsk Standard Time")] [System.String] $TimeZone, [System.String] $AdminPassword, [System.String] $ProductKey, [System.String] $TargetPath, [ValidateSet("Present","Absent")] [System.String] $Ensure ) Write-Verbose "Creating/removing unattend.XML file" switch ($ensure) { "Present" { Try { $Unattend = New-Object XML $Unattend.Load($TemplatePath) $Unattend.unattend.settings.component[0].ComputerName = $Name $Unattend.unattend.settings.component[0].ProductKey = $ProductKey $Unattend.unattend.settings.component[0].RegisteredOrganization = $Organization $Unattend.unattend.settings.component[0].RegisteredOwner = $Owner $Unattend.unattend.settings.component[0].TimeZone = $TimeZone $Unattend.unattend.settings.Component[1].RegisteredOrganization = $Organization $Unattend.unattend.settings.Component[1].RegisteredOwner = $Owner $Unattend.unattend.settings.component[1].UserAccounts.AdministratorPassword.Value = $AdminPassword $Unattend.unattend.settings.component[1].autologon.password.value = $AdminPassword $Unattend.save($TargetPath) Write-Verbose "$TargetPath Created." } Catch { throw $_.Exception.Message } } "Absent" { if (Test-Path $TargetPath) { Remove-Item $TargetPath -force Write-Verbose "$TargetPath removed." } else { Write-Verbose "$TargetPath already removed." } } } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $Name, [System.String] $Organization, [System.String] $Owner, [System.String] $TimeZone, [System.String] $AdminPassword, [System.String] $ProductKey, [ValidateSet("Present","Absent")] [System.String] $Ensure, [System.String] $TargetPath, [System.String] $TemplatePath = "" ) Write-Verbose "Testing values in" switch ($ensure) { "Present" { if (Test-Path $TargetPath) { [XML]$Unattend = Get-Content -LiteralPath $TargetPath $return = $false if ($Name -eq $Unattend.unattend.settings.component[0].ComputerName) { if ($Organization -eq $Unattend.unattend.settings.component[0].RegisteredOrganization) { if ($Owner -eq $Unattend.unattend.settings.component[0].RegisteredOwner) { if ($TimeZone -eq $Unattend.unattend.settings.component[0].TimeZone) { if ($AdminPassword -eq $Unattend.unattend.settings.component[1].AutoLogon.Password.Value) { if ($ProductKey -eq $Unattend.unattend.settings.component[0].ProductKey) { $return = $true } } } } } } } else { $return = $false } } "Absent" { if (Test-Path $TargetPath) { $return = $false } else { $return = $true } } } $return } Export-ModuleMember -Function *-TargetResource
<?xml version="1.0" encoding="utf-8"?> <unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="specialize"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ComputerName>**ComputerName***</ComputerName> <ProductKey>***ProductKey***</ProductKey> <RegisteredOrganization>***RegOrg***</RegisteredOrganization> <RegisteredOwner>***RegOwner***</RegisteredOwner> <TimeZone>***TimeZone***</TimeZone> </component> </settings> <settings pass="oobeSystem"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <UserAccounts> <AdministratorPassword> <Value>***Password***</Value> <PlainText>true</PlainText> </AdministratorPassword> </UserAccounts> <AutoLogon> <Password> <Value>***Password***</Value> <PlainText>true</PlainText> </Password> <Username>administrator</Username> <LogonCount>2</LogonCount> <Enabled>true</Enabled> </AutoLogon> <RegisteredOrganization>***RegOrg***</RegisteredOrganization> <RegisteredOwner>***RegOwner***</RegisteredOwner> <OOBE> <HideEULAPage>true</HideEULAPage> <SkipMachineOOBE>true</SkipMachineOOBE> </OOBE> </component> </settings> <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> </unattend>
This XML must be located somewhere accesible by your node, it can also stored in the module file, but you know, i’m lazy…
You can find all informations here to recreate the module if you need more details about how create your resource.
How can we edit a tag of existing xml.