xmlobjectpowershellobject-to-stringpsobject

Tostring() method of custom powershell objects and export-clixml


1. I have these XML-files which contain data from 3rd-Party cmdlets exported via export-clixml as a backup.
    They look like this (only with more objects):

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>Deserialized.System.Object</T>
    </TN>
    <ToString>OldDomain\UserName</ToString>
    <Props>
      <S N="AdministratorName">OldDomain\UserName</S>
      <Obj N="AdministratorType" RefId="1">
        <TN RefId="1">
          <T>Deserialized.System.Enum</T>
          <T>Deserialized.System.ValueType</T>
          <T>Deserialized.System.Object</T>
        </TN>
        <ToString>Full</ToString>
        <I32>1</I32>
      </Obj>
    </Props>
  </Obj>
</Objs>

2. I usally import these with import-clixml and pipe them again to these 3rd-party cmdlets to recreate the data. Works great.

3. Now i need to replace *OldDomain* with *NewDomain*, before using them.
So i import the data and then replace the values:

foreach ($prop in $subobj.psobject.properties) {         
    If ($prop.Value -match $oldval) {
        $prop.Value = ($prop.Value) -replace ($oldval,$newval) 
    }    
}

This works in theory and if i look at the objects after replacement, they look fine.
 
4. But after piping the data to the cmdlets i kept getting errors about "OldDomain" not being available. "OldDomain" should not even be in the object anymore...
It took me a while, but then i found out where "OldDomain" kept coming from. It becomes clear when i export the object again after replacing the values:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>Deserialized.System.Object</T>
    </TN>
    <ToString>OldDomain\UserName</ToString>                 <<<<<<<<<<<<
    <Props>
      <S N="AdministratorName">NewDomain\UserName</S>       <<<<<<<<<<<<
      <Obj N="AdministratorType" RefId="1">
        <TN RefId="1">
          <T>Deserialized.System.Enum</T>
          <T>Deserialized.System.ValueType</T>
          <T>Deserialized.System.Object</T>
        </TN>
        <ToString>Full</ToString>
        <I32>1</I32>
      </Obj>
    </Props>
  </Obj>
</Objs>


The value is in the tostring()-Method. But why is there a static value in the tostring()-Method? Its supposed to be a METHOD.
And for some reason the cmdlets use this value inside the tostring()-Method.

5. Apart from the reason for this, i tried replacing the value inside tostring(). But its a method, so the only way i know to override this is by adding a new method with the same name:

$subobj | Add-Member -MemberType scriptmethod -Name tostring {$replVal} -Force

This worked only half because it did not replace the value of tostring() with the content of the variable $replVal, (which is "NewDomain"), but with the variable $replVal itself.
So $subobj.tostring() is whatever you have in $replval when you do call the method tostring(), rather than a fixed value.
So what i would need is the scriptmethod work like a noteproperty and let me assign a fixed value, like tostring() = $replvalue


So i dont get it.

A) Why is tostring() in the export-clixml - file anyway?

B) Why is there a fixed value for a method (tostring()) inside the object stored?

C) and most important: How do i replace the fixed value inside tostring()?

 
Thanks and best regards, ffm


   


Solution

  • A) I am not certain, but it does make some sense for the object to have its method definition in the export.

    B) If my reason for A) is true (and it probably isn't), then this being static would be a bug in the implementation of writing the method definition out the file.Basically, I think you're right and that it shouldn't be this way.

    C)

    $subobj | Add-Member -MemberType ScriptMethod -Name ToString -Value {$this.AdministatorName} -Force
    

    Not sure if I got that property name right (AdministatorName). But $this in the definition of your script method refers to object, so you can programmatically get it that way.

    Edit after discussion:

    $replVal = 'A value'
    $block = [ScriptBlock]::Create("'{0}'" -f ($replVal -replace "'","``'"))
    $subobj | Add-Member -MemberType ScriptMethod -Name ToString -Value $block -Force
    

    This will allow you to change $replVal without changing the value of ToString().