Home > Blockchain >  Powershell Array Output to html
Powershell Array Output to html

Time:10-07

Apologies if this is irrelevant but I'm new to powershell and I've been scratching my head on this for a few days on and off now. I'm trying to write a script that will output two columns of data to a html document. I've achieved most of it by learning through forums and testing different combinations.

The problem is although it gives me the result I need within powershell itself; it will not properly display the second column results for Net Log Level.

So the script looks at some folders and pulls the * value which is always three digits (this is the Site array). It then looks within each of these folders to the Output folder and grabs a Net Log Level node from a file inside there. The script is correctly listing the Sites but is only showing the last value for Net Log Level which is 2. You can see this in the screenshot above. I need this to take every value for each Site and display as appropriate. The image of the incorrect result is below. I need the result to be 1,4,2,2,2. Any help would be greatly appreciated!

function getSite {

    Get-ChildItem C:\Scripts\ServiceInstalls\*\Output\'Config.exe.config' | foreach {
    
    $Site = $_.fullname.substring(27, 3)    

    [xml]$xmlRead = Get-Content $_
    $NetLogLevel = $xmlRead.SelectSingleNode("//add[@key='Net Log Level']") 
    $NetLogLevel = $NetLogLevel.value
        
    New-Object -TypeName System.Collections.ArrayList
    $List1  = @([System.Collections.ArrayList]@($Site))

    New-Object -TypeName System.Collections.ArrayList
    $List2  = @([System.Collections.ArrayList]@($NetLogLevel))
    
    }
    
    $Results = @()
    ForEach($Site in $List1){

        $Results  = [pscustomobject]@{
        "Site ID" = $Site
        "Net Log Level" = $NetLogLevel
        }
    }

    $Results | ConvertTo-HTML -Property 'Site','Net Log Level' | Set-Content Output.html
    
    Invoke-Item "Output.html"
    
    }

    getSite

screenshot

CodePudding user response:

Restructure your code as follows:

Get-ChildItem 'C:\Scripts\ServiceInstalls\*\Output\Config.exe.config' |
  ForEach-Object {

    $site = $_.fullname.substring(27, 3)    

    [xml]$xmlRead = Get-Content -Raw $_.FullName
    $netLogLevel = $xmlRead.SelectSingleNode("//add[@key='Net Log Level']").InnerText

    # Construct *and output* a custom object for the file at hand.
    [pscustomobject] @{
      'Site ID' = $site
      'Net Log Level' = $netLogLevel
    }

  } | # Pipe the stream of custom objects directly to ConvertTo-Html
  ConvertTo-Html | # No need to specify -Property if you want to use all properties.
  Set-Content Output.html

As for what you tried:

  • New-Object -TypeName System.Collections.ArrayList in effect does nothing: it creates an array-list instance but doesn't save it in a variable, causing it to be enumerated to the pipeline, and since there is nothing to enumerate, nothing happens.

  • There is no point in wrapping a [System.Collections.ArrayList] instance in @(...): its elements are enumerated and then collected in a regular [object[]] array - just use @(...) by itself.

  • Using = to "grow" an array is quite inefficient, because a new array must be allocated behind the scenes every time; often there is no need to explicitly create an array - e.g. if you can simply stream objects to another command via the pipeline, as shown above, or you can let PowerShell itself implicitly create an array for you by assigning the result of a pipeline or foreach loop as a whole to a variable - see this answer.

    • Also note that when you use =, the result is invariably a regular [object[] array, even if the RHS is a different collection type such as ArrayList.

    • There are still cases where iteratively creating an array-like collection is necessary, but you then need to use the .Add() method of such a collection type in order to grow the collection efficiently - see this answer.

CodePudding user response:

Instead of populating two separate lists, simply create the resulting objects in the first loop:

function getSite {

    $Results = Get-ChildItem C:\Scripts\ServiceInstalls\*\Output\'Config.exe.config' | ForEach-Object {
        $Site = $_.fullname.substring(27, 3)    

        [xml]$xmlRead = Get-Content $_
        $NetLogLevel = $xmlRead.SelectSingleNode("//add[@key='Net Log Level']") 
        $NetLogLevel = $NetLogLevel.value

        [pscustomobject]@{
            "Site ID"       = $Site
            "Net Log Level" = $NetLogLevel
        }
    }

    $Results | ConvertTo-HTML -Property 'Site', 'Net Log Level' | Set-Content Output.html
    
    Invoke-Item "Output.html"
}

getSite
  • Related