0

I have a native CMD Command that output this text: each section splitted with '-----' dashes line, I want to get each portion in different array, so I can process the result of each one of them,

Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

---Processing--------------------------
---------------------------------------
SKU ID: 2b88c4f2-ea8f-43cd-805e-4d41346e18a7
LICENSE NAME: Office 15, OfficeProPlusVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: HT7T7
---------------------------------------
SKU ID: 3e4294dd-a765-49bc-8dbd-cf8b62a4bd3d
LICENSE NAME: Office 15, OfficeVisioProVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: WTWRR
---------------------------------------
SKU ID: ed34dc89-1c27-4ecd-8b2f-63d0f4cedc32
LICENSE NAME: Office 15, OfficeProjectProVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: TVGWY
---------------------------------------
---------------------------------------
---Exiting-----------------------------

EDIT: This Is my Code, I think it's complex, but just for you to know I don't want you to do my work so:

Function Parse-OSPPResult
{
Param(
[Parameter(Mandatory = $true)]
$Result
)

$c = $Result | ? {$_ -notmatch '^Microsoft|^Copyright|Processing|Exiting|^LICENSE STATUS'}
$c = $c[0..($c.Length -3)]
$LineNumbers = $c | Select-String '^--' |select -ExpandProperty linenumber

if ($LineNumbers.Count -gt 1)
{
    $array = @{}

    for ($i=0; $i -lt ($LineNumbers.Count -1); $i++)
    {
    $array[$i] = $c[$LineNumbers[$i]..($LineNumbers[($i + 1)]-2)]
    }
    $array[$i] = $c[$LineNumbers[$i]..($c.Length -1)]
}
    else
    {
    $array[0] = $c[$LineNumbers..($c.Length)]
    }

$arr = @()

    foreach ($item in ($array.GetEnumerator() | % {$_.Name}))
    {
    $Name = (($array[$item] | ? {$_ -match '^LICENSE NAME:'}) -split ': ')[-1]
    $Desc = (($array[$item] | ? {$_ -match '^LICENSE DESCRIPTION:'}) -split ': ')[-1]
    $Key = (($array[$item] | ? {$_ -match '^Last 5'}) -split ': ')[-1]
    $row = "" | Select Name,Description,Key
    $row.Name = $Name
    $row.Description = $Desc
    $row.Key = $Key
    $arr += $row
    }

    return $arr
}

Result:

Name                                      Description                    Key  
----                                      -----------                    ---  
Office 15, OfficeProjectProVL_MAK edition Office 15, RETAIL(MAK) channel HT7T7
Office 15, OfficeVisioProVL_MAK edition   Office 15, RETAIL(MAK) channel WTWRR
Office 15, OfficeProPlusVL_MAK edition    Office 15, RETAIL(MAK) channel TVGWY

will be happy to see other approaches, if possible.

*Note: Sometimes the result has only one portion...

Thanks.

0

3 Answers 3

4

I'd do it this way:

function Split-CommandOutput
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string[]]$InputObject
    )

    End
    {
        # Collect all pipeline input and make sure it's an array of strings
        $InputObject = @($input) | ForEach-Object {$_ -split [System.Environment]::NewLine}

        # Separator to split records
        $Separator = '^-+$'

        # Find start and end indexes of each record
        $RecordBounds = 0..($InputObject.Length-1) | Where-Object {$InputObject[$_] -match $Separator}

        # Split records into multidimensional array
        $Records = @()
        for ($i=0 ; $i -lt ($RecordBounds.Length-1) ; $i++)
        {
            $Records += ,($InputObject[($RecordBounds[$i]+1)..($RecordBounds[$i+1]-1)])
        }

        # Process each record
        foreach($record in $Records)
        {
            # For each item in record
            $Properties = @{}
            foreach($item in $record)    
            {
                # Extract data using regex
                if($item -match '\s*(.+)\s*:\s*(.+)\s*')
                {
                    $Properties.Add($Matches[1], $Matches[2])
                }
            }

            # Create new object
            New-Object -TypeName PSCustomObject -Property $Properties
        }
    }
}

You can pipe strings, arrays of strings and tool output directly to this function:

MyTool.exe | Split-CommandOutput
$ArrayOfStrings | Split-CommandOutput
$SingleString | Split-CommandOutput

Result:

LICENSE NAME                               : Office 15, OfficeProPlusVL_MAK edition
LICENSE DESCRIPTION                        : Office 15, RETAIL(MAK) channel
BETA EXPIRATION                            : 01/01/1601
SKU ID                                     : xxxxxxx-ea8f-43cd-805e-xxxxxxxxxx
LICENSE STATUS                             : ---LICENSED--- 
Last 5 characters of installed product key : XXXXX

LICENSE NAME                               : Office 15, OfficeVisioProVL_MAK edition
LICENSE DESCRIPTION                        : Office 15, RETAIL(MAK) channel
BETA EXPIRATION                            : 01/01/1601
SKU ID                                     : xxxxxxx-a765-49bc-8dbd-xxxxxxxxxx
LICENSE STATUS                             : ---LICENSED--- 
Last 5 characters of installed product key : XXXXX

LICENSE NAME                               : Office 15, OfficeProjectProVL_MAK edition
LICENSE DESCRIPTION                        : Office 15, RETAIL(MAK) channel
BETA EXPIRATION                            : 01/01/1601
SKU ID                                     : ed34dc89-1c27-4ecd-8b2f-63d0f4cedc32
LICENSE STATUS                             : ---LICENSED--- 
Last 5 characters of installed product key : XXXXX
Sign up to request clarification or add additional context in comments.

Comments

3

this worked for me

$text = @'
---Processing--------------------------
---------------------------------------
SKU ID: xxxxxxx-ea8f-43cd-805e-xxxxxxxxxx
LICENSE NAME: Office 15, OfficeProPlusVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: XXXXX
---------------------------------------
SKU ID: xxxxxxx-a765-49bc-8dbd-xxxxxxxxxx
LICENSE NAME: Office 15, OfficeVisioProVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: XXXXX
---------------------------------------
SKU ID: ed34dc89-1c27-4ecd-8b2f-63d0f4cedc32
LICENSE NAME: Office 15, OfficeProjectProVL_MAK edition
LICENSE DESCRIPTION: Office 15, RETAIL(MAK) channel
BETA EXPIRATION: 01/01/1601
LICENSE STATUS:  ---LICENSED--- 
Last 5 characters of installed product key: XXXXX
---------------------------------------
---------------------------------------
---Exiting-----------------------------
'@ -split "`n"

$hash = @{}
$object = foreach ($line in $text) {
    if ($line.startswith('----') -and [bool]$($hash.Keys)) {
        [pscustomobject]$hash
        $hash = @{}
        continue
    } elseif ($line -match '(.*):(.*)') {
        $hash.Add($Matches[1].trim(), $Matches[2].trim())
    }
}

$object

1 Comment

nice, can you explain a bit?
3

The tidier version:

# Somewhere to hold the information for each program entry
$program = @{}

$result = foreach ($line in Get-Content d:\t.txt) {

    # Reset at the beginning of a new SKU or at the end of everything.
    # Output the program details, and initialize for the next one
    if ($line -match '^SKU' -or $line -match '---Exiting') {
        if ($program.Count) { [pscustomobject]$program }
        $program = @{}
    }


    # Lines which have colons contain data
    if ($line -match ':') {
        $name, $value = $line.Split(':', 2)

        # Replace the long names with the desired shorter names
        switch -Regex ($name) {
            'license name'        { $name = 'Name' }
            'license description' { $name = 'Description' }
            'product key'         { $name = 'Key' }   
        }

        # Save the data for each line into the program store
        $program[$name] = $value
    }

}

# Choose the desired results
$result | select Name, Description, Key

The golf version:

(gc d:\t.txt -Raw)-split'-{39}'|%{$p=@{};($_-split'\n')-match':'|%{
$k,$v=$_.Split(':',2);$p[$k]=$v.Trim()};if($p.Count){[pscustomobject]$p}}

1 Comment

@JustCurious now it's even more golfed; and the Tidy version doesn't spit out an empty object anymore, too!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.