Skip to content

Adding Additional Commands - Extracted Unattend Schema XSD #2

@dmidlo

Description

@dmidlo

Hey I've just begun working on some automation, and I'll be working with UnattendXmlBuilder during the course of the project. I imagine and hope I'll run into some opportunities to contribute. One thing I've found so far is that it is incredibly hard to find an XSD for unattend to perform validation against. Scouring the web, I was able to find this article by @cschneegans who has built an extensive online unattend generator.

I thought I'd try to write something native to PS to retrieve the XSD in a repeatable fashion, here's the two functions I've come up with. Hope it helps someday!

function Get-ComponentPlatformSchemaString {
    # Specify the path to the target DLL
    $dllPath = "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\WSIM\amd64\microsoft.componentstudio.componentplatforminterface.dll"

    # Load the assembly
    try {
        $assembly = [Reflection.Assembly]::LoadFrom($dllPath)
        Write-Host "Loaded assembly: $($assembly.FullName)"
    } catch {
        Write-Host "Failed to load assembly: $dllPath `n`n`n"
        return
    }

    # Get the names of embedded resources
    $resourceNames = $assembly.GetManifestResourceNames()

    if (-not $resourceNames.Count -eq 0) {

        $resourceNames | ForEach-Object {

            # Extract and display the contents of XML resources
            if ($_.EndsWith(".resources")) {
                try {
                    $stream = $assembly.GetManifestResourceStream($_)
                    if ($stream) {
                        $reader = New-Object System.IO.StreamReader($stream)
                        $content = $reader.ReadToEnd()
                        $reader.Close()
                        $stream.Close()

                        # Check for XML content within the resource
                        if ($content -match "<\?xml version=""1.0"" encoding=""ASCII""\?>") {
                            Write-Host "XML content found in resource $($_)"
                            return $content
                        }
                    }
                } catch {}
            }
        }
    }
}
function Get-UnattendSchema {
    $schemaResouceDump = Get-ComponentPlatformSchemaString

    $lines = $schemaResouceDump -split "`r?`n"

    $schemaStartIndex = $null
    $schemaEndIndex = $null

    for ($index = 0; $index -lt $lines.Count; $index++) {
        $line = $lines[$index]
    
        if ($line -like "*<xsd:schema*") {
            $schemaStartIndex = $index
        }
    
        if ($line -like "*</xsd:schema>*") {
            $schemaEndIndex = $index
            break
        }
    }

    if ($schemaStartIndex -eq $null -or $schemaEndIndex -eq $null) {
        Write-Warning "Schema start or end tag not found."
    }
    
    $unattendSchema = ($lines[$schemaStartIndex..$schemaEndIndex] -join "`n")
    $unattendSchema | Out-File -FilePath "$($PWD.Path)\unattend.xsd"

    return $unattendSchema
}

And the returned schema:

<xsd:schema targetNamespace="urn:schemas-microsoft-com:unattend" xmlns="urn:schemas-microsoft-com:unattend"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            elementFormDefault="qualified" attributeFormDefault="unqualified">

    <!--Root Elements-->
    <xsd:element name="unattend">
        <xsd:annotation>
            <xsd:documentation>Unattend</xsd:documentation>
        </xsd:annotation>
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="unattendType" />
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:complexType name="unattendType">
       <xsd:sequence>
          <xsd:element name="servicing" type="servicingType" minOccurs="0" maxOccurs="1"/>
          <xsd:element name="settings" type="settingType" minOccurs="0" maxOccurs="unbounded"/>
          <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
       </xsd:sequence>
       <xsd:attribute name="author" type="xsd:string" use="optional"/>
       <xsd:attribute name="description" type="xsd:string" use="optional"/>
       <xsd:attribute name="creationTimeStamp" type="xsd:dateTime" use="optional"/>
       <xsd:attribute name="lastUpdateTimeStamp" type="xsd:dateTime" use="optional"/>
       <xsd:attribute name="ConfigurationSetTimeStamp" type="xsd:dateTime" use="optional"/>
       <xsd:anyAttribute namespace="##other" processContents="lax"/>
    </xsd:complexType>

      <xsd:complexType name="servicingType">
         <xsd:sequence>
            <xsd:element name="package" type="packageType" minOccurs="0" maxOccurs="unbounded"/>
         </xsd:sequence>
      </xsd:complexType>

   <xsd:complexType name="settingType">
       <xsd:sequence>
        <xsd:element name="component" type="componentSettingType" minOccurs="0" maxOccurs="unbounded"/>
       </xsd:sequence>
       <xsd:attribute name="pass" type="passType" use="required"/>
   </xsd:complexType>

   <xsd:complexType name="componentSettingType">
       <xsd:sequence>
          <xsd:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
       </xsd:sequence>
      <xsd:attribute name="name" type="xsd:string" use="required"/>
      <xsd:attribute name="version" type="fourPartVersionType" use="optional"/>
      <xsd:attribute name="processorArchitecture" type="processorArchitectureType" use="required"/>
      <xsd:attribute name="publicKeyToken" type="publicKeyTokenType" use="required"/>
      <xsd:attribute name="language" type="xsd:string" use="required"/>
      <xsd:attribute name="versionScope" type="versionScopeType" use="optional" default="nonSxS"/>
   </xsd:complexType>

   <xsd:simpleType name="passType">
      <xsd:annotation>
         <xsd:documentation>Installation phase to perform setting</xsd:documentation>
      </xsd:annotation>
         <xsd:restriction base="xsd:string">
         <xsd:enumeration value="offlineServicing"/>
         <xsd:enumeration value="windowsPE"/>
         <xsd:enumeration value="generalize"/>
         <xsd:enumeration value="specialize"/>
         <xsd:enumeration value="auditSystem"/>
         <xsd:enumeration value="auditUser"/>
         <xsd:enumeration value="oobeSystem"/>
         <xsd:enumeration value="oobeUser"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:complexType name="packageType">
      <xsd:sequence>
         <xsd:element name="assemblyIdentity" type="identityType" />
         <xsd:choice minOccurs="0" maxOccurs="unbounded">
           <xsd:element name="source" type="sourceType"/>
           <xsd:element name="selection" type="selectionType"/>
         </xsd:choice>
      </xsd:sequence>
      <xsd:attribute name="action" type="actionType" use="required"/>
      <xsd:attribute name="permanence" type="permanenceType" use="optional" default="removable"/>
      <xsd:anyAttribute namespace="##other" processContents="lax"/>
   </xsd:complexType>

   <xsd:complexType name="sourceType">
      <xsd:annotation>
         <xsd:documentation>Package source specification.</xsd:documentation>
      </xsd:annotation>
      <xsd:attribute name="location" type="xsd:string" use="required">
         <xsd:annotation>
            <xsd:documentation>Path to source location for package to install.</xsd:documentation>
         </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="permanence" type="permanenceType" use="optional" default="permanent"/>
   </xsd:complexType>

   <xsd:complexType name="selectionType">
      <xsd:annotation>
         <xsd:documentation>Selection state override for nested child packages.</xsd:documentation>
      </xsd:annotation>
      <xsd:attribute name="name" type="xsd:string" use="required">
         <xsd:annotation>
            <xsd:documentation>Name of selectable update within child package.</xsd:documentation>
         </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="state" type="xsd:boolean" use="required">
         <xsd:annotation>
            <xsd:documentation>Boolean initial state for selection.</xsd:documentation>
         </xsd:annotation>
      </xsd:attribute>
   </xsd:complexType>

   <xsd:simpleType name="actionType">
      <xsd:annotation>
         <xsd:documentation>Installation action to perform on package.</xsd:documentation>
      </xsd:annotation>
         <xsd:restriction base="xsd:string">
         <xsd:enumeration value="remove"/>      <!-- remove package from system -->
         <xsd:enumeration value="stage"/>       <!-- fully stage package, ready for installation -->
         <xsd:enumeration value="install"/>     <!-- install package on system, then configure -->
         <xsd:enumeration value="configure"/>   <!-- configure currently installed package -->
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:simpleType name="permanenceType">
      <xsd:annotation>
         <xsd:documentation>Uninstall options.</xsd:documentation>
      </xsd:annotation>
      <xsd:restriction base="xsd:string">
         <xsd:enumeration value="removable"/>   <!-- normal uninstall behavior -->
         <xsd:enumeration value="permanent"/>   <!-- cannot be removed -->
         <xsd:enumeration value="temporary"/>   <!-- removed when any component updated -->
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:complexType name="identityType">
      <xsd:attribute name="name" type="xsd:string" use="required"/>
      <xsd:attribute name="version" type="fourPartVersionType" use="required"/>
      <xsd:attribute name="processorArchitecture" type="processorArchitectureType" use="required"/>
      <xsd:attribute name="publicKeyToken" type="publicKeyTokenType" use="required"/>
      <xsd:attribute name="language" type="xsd:string" use="required"/>
      <xsd:attribute name="versionScope" type="xsd:string" use="optional" fixed="nonSxS"/>
   </xsd:complexType>

   <xsd:simpleType name="versionScopeType">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="((N|n)(E|e)(U|u)(T|t)(R|r)(A|a)(L|l))|((N|n)(O|o)(N|n)(S|s)(X|x)(S|s))"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:simpleType name="fourPartVersionType">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="(0*[0-9]{0,4}|0*[1-5][0-9]{4}|0*6[0-4][0-9]{3}|0*65[0-4][0-9]{2}|0*655[0-2][0-9]|0*6553[0-5])\.(0*[0-9]{0,4}|0*[1-5][0-9]{4}|0*6[0-4][0-9]{3}|0*65[0-4][0-9]{2}|0*655[0-2][0-9]|0*6553[0-5])\.(0*[0-9]{0,4}|0*[1-5][0-9]{4}|0*6[0-4][0-9]{3}|0*65[0-4][0-9]{2}|0*655[0-2][0-9]|0*6553[0-5])\.(0*[0-9]{0,4}|0*[1-5][0-9]{4}|0*6[0-4][0-9]{3}|0*65[0-4][0-9]{2}|0*655[0-2][0-9]|0*6553[0-5])$"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:simpleType name="publicKeyTokenType">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="([0-9]|[a-f]|[A-F]){16}"/>
      </xsd:restriction>
   </xsd:simpleType>

   <xsd:simpleType name="processorArchitectureType">
      <xsd:restriction base="xsd:string">
         <xsd:pattern value="^(((X|x)86)|((I|i)(A|a)64)|((A|a)(M|m)(D|d)64)|((W|w)(O|o)(W|w)64)|((M|m)(S|s)(I|i)(L|l))|((S|s)(H|h)(X|x))|((A|a)(R|r)(M|m)(64)?)|((D|d)(A|a)(T|t)(A|a))|((N|n)(E|e)(U|u)(T|t)(R|r)(A|a)(L|l)))$"/>
      </xsd:restriction>
   </xsd:simpleType>

</xsd:schema>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions