2 votes

Comment créer un élément de fichier XML avec bouclage en utilisant powershell ?

Je vais créer un fichier xml. Les éléments du fichier xml sont choisis dans le fichier .ini. J'ai plus d'un fichier .ini. J'ai essayé, mais je ne peux toujours créer qu'un seul élément.

Il y a deux types de fichiers de contenu dans mon fichier .ini. Le premier.

[Product]
Name = NB A
String = Defaults and Exit

[Controller1]
Desc = Embedded Intel RAID

[Controller2]
Desc = Intel Optane Device

2ème.

[Product]
Name = NB A
String = Defaults and Exit

[Controller1]
Desc = Embedded SATA 

Je m'attends à ce que la sortie du XML soit de deux types. Le premier.

<Product Name=NB A>
      <Controller controllertype="raid">
      <Controller controllertype="optane">
</Product>

2ème.

<Product Name=NB A>
      <Controller controllertype="raid">
</Product>

Le code que j'ai écrit jusqu'à présent :

$ProductListXML = "D:\TST.XML"
$driver = "D:\ver.xml" 

# get an XMLTextWriter to create the XML
$XmlWriter = New-Object System.XMl.XmlTextWriter($ProductListXML,$Null)

# choose a pretty formatting:
$xmlWriter.Formatting = 'Indented'
$xmlWriter.Indentation = 1
$XmlWriter.IndentChar = "`t"

# write the header
$xmlWriter.WriteStartDocument()

$xmlWriter.WriteStartElement('ProductList')
$xmlWriter.WriteAttributeString('Version', '200422a')

# load it into an XML object:
$xml = New-Object -TypeName XML
$xml.Load($driver)
$FamilyCode = $Xml.drivergroup.family | Select-Object -ExpandProperty Code

foreach ($fc in $FamilyCode)
{
    $FCDesc = $Xml.drivergroup.family | Where-Object { $_.code -eq "$fc" }| Select-Object -ExpandProperty description
    $SystemID = $Xml.drivergroup.family |  Where-Object { $_.code -eq "$fc" } | Select-Object -ExpandProperty Product | Select-Object -ExpandProperty systemid
    $IDSplit = $SystemID -split "/"

    $XmlWriter.WriteStartElement('Family')   
    $XmlWriter.WriteAttributeString('code', "$fc")
    $XmlWriter.WriteAttributeString('decription', "$FCDesc")

    foreach($sid in $IDSplit)
    {

        $ID = Get-ChildItem -path "D:\product\*$sid*" | Select-Object -ExpandProperty BaseName

        foreach ($id in $ID)
        {
            $File = Get-ChildItem -path "D:\product\*$id*"
            $ReadINI = @{} 
            Get-Content "$File" | ForEach-Object {
            $_.Trim()
            } | Where-Object {

            $_ -notmatch '^(;|$)'
            } | ForEach-Object {
            if ($_ -match '^\[.*\]$') {
            $section = $_ -replace '\[|\]'
            $ReadINI[$section] = @{}
            } else {
            $key, $value = $_ -split '\s*=\s*', 2
            $ReadINI[$section][$key] = $value    
            }
            }

            $ProductName = $ReadINI["Product"]["Name"]
            $TechType = $ReadINI["Controller1"]["Node"]
            if($TechType -eq "Intel")
            {
                $TechType = "Intel"
            }
            else{

                $TechType = "AMD"
            }
            $FactoryDefaultsString = $ReadINI["Product"]["String"]

            $YearPath = "D:\*.txt"
            $YearMapping = Select-String -Path $YearPath -Pattern "$id" 
            if($YearMapping -like "*2017*")
            {
                $Year = "2017"
            }
            elseif($YearMapping -like "*2018*")
            {
                $Year = "2018"
            }
            elseif($YearMapping -like "*2019*")
            {
                $Year = "2019"
            }
            elseif($YearMapping -like "*2020*")
            {
                $Year = "2020"
            }
            elseif($YearMapping -like "*2021*")
            {
                $Year = "2021"
            }

            $XmlWriter.WriteStartElement('Product')
            $XmlWriter.WriteAttributeString('Name', "$ProductName")
            $XmlWriter.WriteAttributeString('SSID', "$id")
            $XmlWriter.WriteAttributeString('TechType', "$TechType")
            $XmlWriter.WriteAttributeString('Year', "$Year")
            $XmlWriter.WriteAttributeString('FactoryDefaultsString', "$FactoryDefaultsString")

            $Controller2 = Select-String -Path $File -Pattern "Controller2" | Select-Object -ExpandProperty Filename
            foreach ($cont2 in $Controller2)
            {
                $file = Get-ChildItem "D:\product\$cont2"
                $ReadTechTp = @{} 
                Get-Content "$file" | ForEach-Object {
                $_.Trim()
                } | Where-Object {

                $_ -notmatch '^(;|$)'
                } | ForEach-Object {
                if ($_ -match '^\[.*\]$') {
                $section = $_ -replace '\[|\]'
                $ReadTechTp[$section] = @{}
                } else {
                $key, $value = $_ -split '\s*=\s*', 2
                $ReadTechTp[$section][$key] = $value    
                }
                }

                $Desc = $ReadTechTp["Controller2"]["Desc"]

                if($Desc -like "*RAID*" -or $Controller1 -like "*SATA*")
                {
                    $ControllerType = "RAID"
                }
                else{
                    $ControllerType = "OPTANE"
                }

                $XmlWriter.WriteStartElement('Controller')
                $XmlWriter.WriteAttributeString('ControllerType', "$ControllerType")

            }

            $xmlWriter.WriteEndElement()

        }

    }

    $xmlWriter.WriteEndElement()
}

    $xmlWriter.WriteEndElement()

# finalize the document:
$xmlWriter.WriteEndDocument()
$xmlWriter.Flush()
$xmlWriter.Close()

Toute personne peut aider, s'il vous plaît. Les conseils et les solutions sont les bienvenus. Merci de votre aide.

1voto

RoadRunner Points 8021

Voici comment vous pourriez le faire :

  • Créer une Regex pour faire correspondre les en-têtes. Cela pourrait être quelque chose comme ^\[(.+)\]$ .

    • Faire correspondre le début de la ligne avec ^ ,
    • Trouve le premier [ support avec \[ ,
    • Fait correspondre tout caractère une fois ou plus dans un groupe avec (.+) ,
    • Correspond à la dernière parenthèse ] avec \] et termine la ligne par $ .
  • Créez une Regex pour faire correspondre les clés et les valeurs. Cela pourrait être quelque chose comme ^(.+?)\s*=\s*(.*)$ .

    • Faites correspondre le début de la ligne avec ^ ,
    • Trouve les touches avec n'importe quel caractère une ou un nombre illimité de fois avec (.+?) ,
    • Correspond à zéro ou plus d'espace entre un nom de domaine et un mot de passe. = signe avec \s*=\s*
    • Fait correspondre zéro ou plusieurs caractères dans un groupe avec (.*) et termine la ligne par $ .

En gardant à l'esprit ce qui précède, nous pouvons créer une fonction qui renvoie l'information suivante .ini la structure du fichier comme des tables de hachage imbriquées. J'utilise le -File y -Regex passe de switch pour lire le fichier et rechercher des motifs regex. Vous pouvez jeter un coup d'oeil à about_Switch pour plus d'informations.

Toutefois, il faudra probablement prévoir davantage de contrôles d'erreurs, notamment pour gérer les commentaires et les entrées non valides. Je viens de créer quelque chose qui fonctionnera pour le système ci-dessus. .ini des fichiers.

function Get-IniFile {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$FilePath
    )

    $ini = [ordered]@{}

    switch -Regex -File $FilePath {

        # Match headers
        "^\[(.+)\]$" {
            $section = $Matches[1]
            $ini[$section] = [ordered]@{}
            continue
        }

        # Match key-value pairs
        "^(.+?)\s*=\s*(.*)$" {
            $name, $value = $matches[1..2]
            $ini[$section][$name] = $value
            continue
        }
    }

    return $ini
}

Ensuite, vous pourriez itérer vos deux .ini fichiers, disons first.ini y second.ini . et créez les fichiers XML pour les deux en utilisant les tables de hachage retournées par Get-IniFile .

$iniFiles = "first.ini", "second.ini"

# Go through each .ini file
foreach ($file in $iniFiles) {

    # Create XML object to write to
    $xml = New-Object -TypeName System.Xml.XmlDocument

    # Get .ini file data into a hashtable
    $iniFileData = Get-IniFile -FilePath $file

    # Iterate first set of keys from hashtable
    foreach ($kvp in $iniFileData.GetEnumerator()) {

        # Create a product root key for the header
        $product = $xml.CreateElement($kvp.Key)

        # Iterate through key-value pairs
        foreach ($value in $kvp.Value.GetEnumerator()) {
            switch ($value.Name)
            {

                # If we found a name, this attribute belongs to the header
                "Name" {
                    $product.SetAttribute($value.Name, $value.Value)
                    $xml.AppendChild($product)
                    break
                }

                # Otherwise we found a descendent node
                "Desc" {

                    # Create descendent controller node
                    $controller = $xml.CreateElement("Controller")

                    # Determine how to set the attributes depending on the value
                    if ($value.Value -like "*RAID*" -or $value.Value -like "*SATA*") {
                        $controller.SetAttribute("controllertype", "raid");
                    } else {
                        $controller.SetAttribute("controllertype", "optane");
                    }

                    # Append controller node to product root node
                    $xml.Product.AppendChild($controller)
                    break
                }
            }
        }
    }

    # Save to XML file, using the name from the original file
    $filename = [System.IO.Path]::GetFileNameWithoutExtension($file)
    $xml.Save("{0}.xml" -f $filename)
}

premier.xml

<Product Name="NB A">
  <Controller controllertype="raid" />
  <Controller controllertype="optane" />
</Product>

deuxième.xml

<Product Name="NB A">
  <Controller controllertype="raid" />
</Product>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X