Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding .NETs ToString() method can cause unexpected behaviour when using Transcripts #23804

Open
5 tasks done
dhermanconsulting opened this issue May 15, 2024 · 1 comment
Labels
Needs-Triage The issue is new and needs to be triaged by a work group.

Comments

@dhermanconsulting
Copy link

Prerequisites

Steps to reproduce

When PowerShell Transcripting is enabled, this code is invoked, which calls ToString() against any parameter passed to a cmdlet, regardless of type.

If the ToString() method which is called also calls a cmdlet with $this, this creates infinite recursion as the linked code keeps calling ToString(), which calls a cmdlet, which calls ToString() etc.

The issue is not observed when transcription is disabled.

This recursion causes the script to slow dramatically - I assume it is exhausting the stack, throwing a handled exception, which then allows everything to unwind and continue execution.

The below is a contrived/minimal example to demonstrate the issue:

Start-Transcript

$global:CountCalls = 0

function Get-Name {

    param(
        [TestClassA] $Arg
    )

    return $testClassA.NameProperty

}

function Random-CmdLet {

    param(
        [TestClassA] $Arg
    )

    return $true

}

class TestClassA {

    [string] $NameProperty = "MyName"

     [string] ToString() {

        $global:CountCalls++

        return Get-Name -Arg $this
    }

}

[System.Diagnostics.Stopwatch] $stopWatchA = [System.Diagnostics.Stopwatch]::StartNew()

$testClassA = [TestClassA]::New()

Random-CmdLet -Arg $testClassA

$stopWatchA.Stop()

$stopWatchA.Elapsed.TotalMilliseconds | Write-Host

"Calls to ToString(): {0}" -f $CountCalls | Write-Host 

Expected behavior

Transcript started, output file is xyz.txt
True
4
Calls to ToString(): 0

Actual behavior

Transcript started, output file is xyz.txt
True
82.7247
Calls to ToString(): 418

Error details

No response

Environment data

PSVersion                      7.4.2
PSEdition                      Core
GitCommitId                    7.4.2
OS                             Microsoft Windows 10.0.22631
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

@dhermanconsulting dhermanconsulting added the Needs-Triage The issue is new and needs to be triaged by a work group. label May 15, 2024
@dhermanconsulting
Copy link
Author

dhermanconsulting commented May 15, 2024

Further to note, overriding ToString() is recommended in .NET development and I've never seen any guidelines by Microsoft that it shouldn't perform any processing, or call other functions/methods. Ultimately it should be for the developer to decide what meaningful output is expected.

In my use case, I wanted to use ConvertTo-Json to output serialised JSON data.

The issues comes about specifically because of the trace debugging within the linked file:

https://github.com/PowerShell/PowerShell/blob/master/src/System.Management.Automation/engine/ParameterBinderBase.cs

Though I appreciate it's a niche issue, and a bit of mix and match PowerShell classes and PowerShell cmdlets I think the functionality should be supported and not choke when transcripting is enabled

GitHub
PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Triage The issue is new and needs to be triaged by a work group.
Projects
None yet
Development

No branches or pull requests

1 participant