function Using-Object { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [AllowEmptyString()] [AllowEmptyCollection()] [AllowNull()] [Object] $InputObject, [Parameter(Mandatory = $true)] [scriptblock] $ScriptBlock ) try { . $ScriptBlock } finally { if ($null -ne $InputObject -and $InputObject -is [System.IDisposable]) { $InputObject.Dispose() } } }
I don’t know why I did this. Performance is better if you use try/finally directly, rather than passing script blocks around. But, if you want PowerShell “using” syntax that looks similar to the C# examples you see on MSDN / etc, enjoy!
# Demonstrating the usage of Using-Object Using-Object ($streamWriter = New-Object System.IO.StreamWriter("$pwd\newfile.txt")) { $streamWriter.WriteLine('Line written inside Using block.') } # The second call to $streamWriter.WriteLine() produces an error, because # the stream is already closed. $streamWriter.WriteLine('Line written outside Using block.') Get-Content .\newfile.txt
More examples on…C# Using Statement
Brian
LikeLike
Great post, thanks!
LikeLike
Pingback: Wrapping using statement with dispose in powershell - Alexander Williamson
I like this idea. But this implementation never disposes $streamWriter because $streamWriter is never passed to Using-Object. Unlike for C#, variable assignments in PowerShell evaluate to $null so the assignment to $streamWriter occurs but the result is $null.
LikeLike
The parentheses in the example matter. 🙂 When you put an assignment expression in parentheses, in PowerShell, the value also surfaces as output. You can try it out at a console:
$i = 1 # outputs nothing
($i = 2) # outputs 2
LikeLike
The only problem with this is that it’s not a true “using” statement – it’s basically a glorified function. The moment you enter it, scope goes bye bye.
You can fix a hack with a hack – use [ref] on variables out of scope.
function Main {
$test1 = “foo”;
$test2 = “foo”;
Using-Object ($streamWriter = New-Object System.IO.StreamWriter(“$pwd\newfile.txt”)) {
$streamWriter.WriteLine(‘Line written inside Using block.’)
$test1 = “bar”;
([ref]$test2).Value = “bar”;
}
Write-Host $test1;
Write-Host $test2;
}
Main;
LikeLike
If the Using-Object function is defined in a script module that’s separate from where the call comes from, it works fine. Another workaround if it’s defined in the same file / scope is to dot-source the call to Using-Object: . Using-Object ($object = Whatever) { $someVariable = ‘Value }
LikeLike