2

Environment Info:

PS C:\> Get-WmiObject Win32_OperatingSystem


SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 9600
RegisteredUser  : xxxxxxxxxxxxxxxxxxxxxxx
SerialNumber    : xxxxx-xxxxx-xxxxx-xxxxx
Version         : 6.3.9600 # Windows 8.1, Update 1



PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.14409.1018
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.14409.1018
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

Background:

why I made this:

  • my USB HDD is a little bit unstable. and I need to find files and store paths progressively.
  • if some error will occur, store the error information instead of the path.
  • I intend to use [TreeElement] objects for storing and searching.

I made a simple tree class:

# need Powershell v5.0 higher
class TreeElement
{
    $Value = $null
    [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
    [TreeElement] $Parent = $null

    TreeElement($Value)
    {
        $this.Value = $Value
    }

    [TreeElement] AddChild([TreeElement] $Child)
    {
        $this.Children.Add($Child)
        return $Child
    }

    [TreeElement] AddChildValue($ChildValue)
    {
        $Child = [TreeElement]::new($ChildValue)
        $this.Children.Add($Child)
        return $Child
    }
}

I finished coding, and tested like this:

$root = [TreeElement]::new(1)
$root.AddChildValue(2)
$root.AddChildValue(3)
$root.AddChildValue(4)
$root.AddChildValue(5)

$root

The last line will show this in the console.

Value Children                                             Parent
----- --------                                             ------
    1 {TreeElement, TreeElement, TreeElement, TreeElement}

nop.

I wanted to store $root to a file.

so I decided to use *-Clixml, and coded:

Function Store-Tree
{
    [OutputType([void])]
    Param
    (
        [string]$Path,
        [TreeElement]$RootElement
    )

    Export-Clixml -Path $Path -InputObject $RootElement
}

Function Restore-Tree
{
    Param
    (
        [string]$Path
    )

    # restore from xml
    $obj = Import-Clixml -Path $Path

    # Reconstruct instances...
    $result = Reconstruct-Tree -RootObject $obj
    return $result
}

Function Reconstruct-Tree
{
    [OutputType([TreeElement])]
    Param
    (
        [PSObject] $RootObject
    )

    $root = [TreeElement]::new($RootObject.Value)

    foreach($ChildObject in $RootObject.Children)
    {
        [TreeElement] $branch = Reconstruct-Tree $ChildObject
        [void] $root.AddChild($branch)
    }

    return $root
}

Then I tested it:

PS> mkdir C:\temp
PS> $path = "C:\temp\root-tree.xml"
PS> $root # original instance

Value Children                                             Parent
----- --------                                             ------
    1 {TreeElement, TreeElement, TreeElement, TreeElement}


PS> Store-Tree -Path $path -RootElement $root # store in xml. instances are converted to [PsObject] internally.
PS> $root_r = Restore-Tree -Path $path # restore instances with type of [TreeElement].

Value       Children Parent
-----       -------- ------
TreeElement {}                      # what?

Problem:

I expected $root_r has an instance almost the same as $root.

but $root_r has an expected object in the Children member.

I wanted to return just the object.

debugging showed that the [TreeElement] constructor was running when the function Reconstruct-Tree returned the object.

Question:

Is there a way to return just the object? Did I do something wrong?

I googled some site, but no information was gained.

Any help is appreciated.

Thank you for your help in advance.

1 Answer 1

1

self resolved.


Debug Step1:

  • Paste code [A] and [S] at first.
  • Then test with [T].
  • Nothing strange.

Debug Step2:

  • Paste code [A] and [S] at first.
  • Then I modified the class [TreeElement] like [A modified].
  • Paste code [A modified].
  • And, test with [T].
  • Something strange happened.

Why?

  • (1) When I run the '[A modified]', it will fix the definition of [TreeElement] itself.
  • (2) But the definiton of '[TreeElement]' in the function Reconstruct-Tree is not fixed.
  • (3) So [TreeElement] of (1) is a different type from '[TreeElement]' of (2).
  • (4) Then Reconstruct-Tree try to return an instance of [TreeElment] with the old [TreeElement] type ('[TreeElement]').
  • (5) And powershell decide the instance is an argument of the constructor of '[TreeElement]'.

Sorry for bothering you. Thanks.


Sample Code:

[A] : a definition of [TreeElement] class.

# need Powershell v5.0 higher
class TreeElement
{
    $Value = $null
    [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
    [TreeElement] $Parent = $null

    TreeElement($Value)
    {
        $this.Value = $Value
    }

    [TreeElement] AddChild([TreeElement] $Child)
    {
        $this.Children.Add($Child)
        return $Child
    }

    [TreeElement] AddChildValue($ChildValue)
    {
        $Child = [TreeElement]::new($ChildValue)
        $this.Children.Add($Child)
        return $Child
    }
}

[A modified] : a new definition of [TreeElement] class.

class TreeElement
{
    $Value = $null
    [System.Collections.Generic.List[TreeElement]] $Children = [System.Collections.Generic.List[TreeElement]]::new()
    [TreeElement] $Parent = $null
    [string] $Dummy = "editted class type!"

    TreeElement($Value)
    {
        $this.Value = $Value
    }

    [TreeElement] AddChild([TreeElement] $Child)
    {
        $this.Children.Add($Child)
        return $Child
    }

    [TreeElement] AddChildValue($ChildValue)
    {
        $Child = [TreeElement]::new($ChildValue)
        $this.Children.Add($Child)
        return $Child
    }
}

[S] : storing an instance of the class ([TreeElement]).

Function Store-Tree
{
    [OutputType([void])]
    Param
    (
        [string]$Path,
        [TreeElement]$RootElement
    )

    Export-Clixml -Path $Path -InputObject $RootElement
}

Function Restore-Tree
{
    Param
    (
        [string]$Path
    )

    # restore from xml
    $obj = Import-Clixml -Path $Path

    # Reconstruct instances...
    $result = Reconstruct-Tree -RootObject $obj
    return $result
}

Function Reconstruct-Tree
{
    [OutputType([TreeElement])]
    Param
    (
        [PSObject] $RootObject
    )

    $root = [TreeElement]::new($RootObject.Value)

    foreach($ChildObject in $RootObject.Children)
    {
        [TreeElement] $branch = Reconstruct-Tree $ChildObject
        [void] $root.AddChild($branch)
    }

    return $root
}

[T] : Test Code.

$path = "C:\temp\root-tree.xml"

$root = [TreeElement]::new(1)
$root.AddChildValue(2)
$root.AddChildValue(3)
$root.AddChildValue(4)
$root.AddChildValue(5)

$root # original instance

Store-Tree -Path $path -RootElement $root # store in xml. instances are converted to [PsObject] internally.

$root_r = Restore-Tree -Path $path # restore instances with type of [TreeElement].
$root_r
Sign up to request clarification or add additional context in comments.

Comments

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.