You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Is there an alternative to PowerShell.AddScript() that preserves file position information? #7530
The parameter to .AddScript() is a string, not a scriptblock, so any file position information that might have been present in the ScriptBlock object never makes it into that method. Is there some other way to get a PowerShell object to invoke a ScriptBlock without losing file position information?
at <ScriptBlock>, <C:\Users\UserName\Desktop\test.ps1>: line 3
Actual behavior
at <ScriptBlock>, <No file>: line 2
Environment data
>$PSVersionTable
Name Value
---------
PSVersion 6.1.0-preview.4
PSEdition Core
GitCommitId 6.1.0-preview.4
OS Microsoft Windows 6.3.9600
Platform Win32NT
PSCompatibleVersions {1.0,2.0,3.0,4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
input1
input2
Key Value
--- -----
Named2 named 2
Named1 named 1
arg1
arg2
at f, C:\Users\un1\Desktop\test.ps1: line 10
at <ScriptBlock><Process>, C:\Users\un1\Desktop\test.ps1: line 17
at <ScriptBlock><Process>, <No file>: line 5
Jason Shirk (@lzybkr) I'm seeing crashes and "InvalidOperationException: Stack Empty" using this technique combined with concurrent calls to .BeginInvoke().
This is the most verbose output I have witnessed. The run ended in a "PowerShell Core 6 has stopped working" message box.
complete
% : Stack empty.
At C:\users\un1\Desktop\test.ps1:26 char:5
+ %{ $_.PowerShell.EndInvoke($_.Invocation)}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ForEach-Object], InvalidOperationEx
ception
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.
Commands.ForEachObjectCommand
An error has occurred that was not properly handled. Additional information is s
hown below. The PowerShell process will exit.
Unhandled Exception: System.InvalidOperationException: Stack empty.
at System.Collections.Generic.Stack`1.ThrowForEmptyStack()
at System.Collections.Generic.Stack`1.Pop()
at System.Management.Automation.DlrScriptCommandProcessor.OnRestorePreviousSc
ope()
at System.Management.Automation.CommandProcessorBase.DoComplete()
at System.Management.Automation.Internal.PipelineProcessor.DoCompleteCore(Com
mandProcessorBase commandRequestingUpstreamCommandsToStop)
at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecute
Enumerate(Object input)
at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()
at System.Management.Automation.Runspaces.PipelineThread.WorkerProc()
at System.Threading.Thread.ThreadMain_ThreadStart()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionCo
ntext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
That looks like a potentially serious bug, maybe open a new issue?
This looks like the stack to save and restore variables like $_ when dot sourcing. If the stack was empty, then the wrong stack may have been used, probably from another runspace.
Patrick Meinecke (@SeeminglyScience) - $scriptBlock.Clone() should work as well and should be faster - it would avoid recompiling the script block.
Also - if that workaround works, I still think this issue should not be ignored - if my assumption is correct, it might also manifest silently and do something unexpected.
I don't see any immediate downsides to making it public.
Maybe try calling it via reflection in some experiments where you were using $scriptBlock.Ast.GetScriptBlock() to see if there are any problems or if I'm mistaken about the performance impact.
staticclassScriptBlockExtensions{internalstaticScriptBlockClone(thisScriptBlockscriptBlock){// see also PowerShell/PowerShell#7530return((ScriptBlockAst)scriptBlock.Ast).GetScriptBlock();}}
Activity
lzybkr commentedon Aug 14, 2018
How about:
Your stack will be 1 deeper than you want, but that should be easy to clean up.
If you don't want to use
Invoke-Command, you could useAddScript('. $args[0]')alx9r commentedon Aug 21, 2018
Thanks Jason Shirk (@lzybkr). I think that will get me there. For posterity, here's what it seems to take to accomplish all of the following:
That outputs
alx9r commentedon Aug 21, 2018
Jason Shirk (@lzybkr) I'm seeing crashes and "InvalidOperationException: Stack Empty" using this technique combined with concurrent calls to
.BeginInvoke().Repro
Expected
Actual
This is the most verbose output I have witnessed. The run ended in a "PowerShell Core 6 has stopped working" message box.
lzybkr commentedon Aug 21, 2018
That looks like a potentially serious bug, maybe open a new issue?
This looks like the stack to save and restore variables like
$_when dot sourcing. If the stack was empty, then the wrong stack may have been used, probably from another runspace.SeeminglyScience commentedon Aug 22, 2018
alx9r Might be due to PowerShell attempting to send the scriptblock back to it's origin runspace. Try
AddArgument($scriptBlock.Ast.GetScriptBlock())lzybkr commentedon Aug 22, 2018
Patrick Meinecke (@SeeminglyScience) -
$scriptBlock.Clone()should work as well and should be faster - it would avoid recompiling the script block.Also - if that workaround works, I still think this issue should not be ignored - if my assumption is correct, it might also manifest silently and do something unexpected.
SeeminglyScience commentedon Aug 22, 2018
Jason Shirk (@lzybkr) It's internal unfortunately :/
lzybkr commentedon Aug 22, 2018
I don't see any immediate downsides to making it public.
Maybe try calling it via reflection in some experiments where you were using
$scriptBlock.Ast.GetScriptBlock()to see if there are any problems or if I'm mistaken about the performance impact.alx9r commentedon Aug 23, 2018
Done. The new issue is #7626.
alx9r commentedon Aug 24, 2018
Thanks for the help Jason Shirk (@lzybkr) and Patrick Meinecke (@SeeminglyScience).
It seems like the peformance of .Clone() and .Ast.GetScriptBlock() are similar:
One typical result of this run on my computer is:
alx9r commentedon Aug 24, 2018
FWIW I have settled (for now) on the following for creating scriptblock clone from C#:
animasc commentedon May 8, 2020
This is interesting! Any non reported progress since 2018? Thanks
alx9r commentedon May 8, 2020
animasc I just checked. It looks like I settled on the following for my general-purpose runspace invoker:
and