Last active
December 8, 2024 18:29
-
-
Save santisq/f9a94b15f450c5f350a27fb05da22e1b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add-Type (Get-Content .\UseObjectCommand.cs -Raw) -PassThru | | |
Import-Module -Assembly { $_.Assembly } | |
try { | |
$tmp = New-TemporaryFile | |
0..10 | use ($writer = [System.IO.StreamWriter]::new($tmp.FullName)) { | |
$writer.WriteLine($_) | |
if ($_ -eq 5) { | |
throw 'Should correctly dispose `$writer`.' | |
} | |
} | |
} | |
catch { | |
# ignore the script terminating error | |
} | |
finally { | |
# StreamWriter __if not disposed correctly__ shouldn't allow this. | |
# It opens a FileStream with NO shared permissions | |
Add-Content $tmp.FullName 'Should be able to append content.' | |
} | |
# Expected here is `0 to 5 + Should be able to append content.` | |
Get-Content $tmp.FullName | Write-Host | |
$tmp.Delete() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Management.Automation; | |
using System.Management.Automation.Language; | |
using System.Text; | |
using System.Threading; | |
[Cmdlet(VerbsOther.Use, "Object")] | |
[Alias("use")] | |
public sealed class UseObjectCommand : PSCmdlet, IDisposable | |
{ | |
private SteppablePipeline _pipe; | |
private CancellationTokenSource _src; | |
[Parameter(ValueFromPipeline = true)] | |
public object InputObject { get; set; } | |
[Parameter(Mandatory = true, Position = 0)] | |
public IDisposable Disposable { get; set; } | |
[Parameter(Mandatory = true, Position = 1)] | |
public ScriptBlock ScriptBlock { get; set; } | |
[Parameter] | |
public SwitchParameter UseLocalScope { get; set; } | |
[Parameter] | |
public SwitchParameter CancellationToken { get; set; } | |
protected override void BeginProcessing() | |
{ | |
List<object> args = new List<object> | |
{ | |
ConvertToProcessBlockIfUnnamed(ScriptBlock) | |
}; | |
StringBuilder builder = new StringBuilder() | |
.Append("param($__sb"); | |
if (CancellationToken.IsPresent) | |
{ | |
_src = new CancellationTokenSource(); | |
builder.Append(", $__token"); | |
args.Add(_src.Token); | |
} | |
builder | |
.Append(") ") | |
.Append(UseLocalScope.IsPresent ? "." : "&") | |
.Append(" $__sb") | |
.Append(_src != null ? " $__token" : null); | |
_pipe = ScriptBlock | |
.Create(builder.ToString()) | |
.GetSteppablePipeline( | |
CommandOrigin.Internal, | |
args.ToArray()); | |
_pipe.Begin(this); | |
} | |
protected override void ProcessRecord() | |
{ | |
_pipe.Process(InputObject); | |
} | |
protected override void EndProcessing() | |
{ | |
_pipe.End(); | |
} | |
protected override void StopProcessing() | |
{ | |
if (_src != null) | |
{ | |
_src.Cancel(); | |
} | |
} | |
private static ScriptBlock ConvertToProcessBlockIfUnnamed(ScriptBlock scriptBlock) | |
{ | |
ScriptBlockAst sbAst = (ScriptBlockAst)scriptBlock.Ast; | |
ParamBlockAst param = sbAst.ParamBlock; | |
NamedBlockAst begin = sbAst.BeginBlock; | |
NamedBlockAst process = sbAst.ProcessBlock; | |
NamedBlockAst end = sbAst.EndBlock; | |
if ((begin != null) || (process != null && !process.Unnamed) || (end != null && !end.Unnamed)) | |
{ | |
return scriptBlock; | |
} | |
if (param != null) | |
{ | |
param = (ParamBlockAst)param.Copy(); | |
} | |
ScriptBlockAst newSbAst = new ScriptBlockAst( | |
scriptBlock.Ast.Extent, | |
paramBlock: param, | |
beginBlock: null, | |
processBlock: new NamedBlockAst( | |
sbAst.EndBlock.Extent, | |
TokenKind.Process, | |
new StatementBlockAst( | |
sbAst.EndBlock.Extent, | |
sbAst.EndBlock.Statements.Select(s => s.Copy()).Cast<StatementAst>(), | |
Enumerable.Empty<TrapStatementAst>()), | |
unnamed: false), | |
endBlock: null, | |
dynamicParamBlock: null); | |
return newSbAst.GetScriptBlock(); | |
} | |
public void Dispose() | |
{ | |
if (_src != null) | |
{ | |
_src.Dispose(); | |
} | |
_pipe.Dispose(); | |
Disposable.Dispose(); | |
GC.SuppressFinalize(this); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment