Powershell running a scriptblock - scope, dot-sourcing
I want to write a function that accepts a scriptblock as a parameter and executes that scriptblock in the scope in which it was invoked.
The Measure-Command is an example of the behavior I would like. The scriptblock runs in with the same scope as the Measure-Command itself. If the scriptblock references a variable in this scope, the script can change it.
Attached is a sample scriptblock that increments the $a variable. When invoked by Measure-Command, the variable is incremented. But when invoked by the Wrapper functions, the variable will not increment -- unless I dot-source both the invocation of the Wrapper function and the Wrapper function itself uses dot-sourcing.
function Wrapper1
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
& $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
function Wrapper2
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
. $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
$a = 1
Write-Output "Initial state: `$a = $a"
Measure-Command $a++ | Out-Null
Write-Output "Measure-Command results: `$a = $a"
Wrapper1 $a++
Write-Output "Wrapper1 results: `$a = $a"
. Wrapper1 $a++
Write-Output "dot-sourced Wrapper1 results: `$a = $a"
Wrapper2 $a++
Write-Output "Wrapper2 results: `$a = $a"
. Wrapper2 $a++
Write-Output "dot-sourced Wrapper2 results: `$a = $a"
The result of running this code is:
Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3
Although this last option works, I'd like to avoid the dot-source syntax invoking Wrapper2. Is this possible? The Measure-Command doesn't use the dot-source syntax so it seems that it would be possible.
function powershell scope
add a comment |
I want to write a function that accepts a scriptblock as a parameter and executes that scriptblock in the scope in which it was invoked.
The Measure-Command is an example of the behavior I would like. The scriptblock runs in with the same scope as the Measure-Command itself. If the scriptblock references a variable in this scope, the script can change it.
Attached is a sample scriptblock that increments the $a variable. When invoked by Measure-Command, the variable is incremented. But when invoked by the Wrapper functions, the variable will not increment -- unless I dot-source both the invocation of the Wrapper function and the Wrapper function itself uses dot-sourcing.
function Wrapper1
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
& $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
function Wrapper2
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
. $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
$a = 1
Write-Output "Initial state: `$a = $a"
Measure-Command $a++ | Out-Null
Write-Output "Measure-Command results: `$a = $a"
Wrapper1 $a++
Write-Output "Wrapper1 results: `$a = $a"
. Wrapper1 $a++
Write-Output "dot-sourced Wrapper1 results: `$a = $a"
Wrapper2 $a++
Write-Output "Wrapper2 results: `$a = $a"
. Wrapper2 $a++
Write-Output "dot-sourced Wrapper2 results: `$a = $a"
The result of running this code is:
Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3
Although this last option works, I'd like to avoid the dot-source syntax invoking Wrapper2. Is this possible? The Measure-Command doesn't use the dot-source syntax so it seems that it would be possible.
function powershell scope
1
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14
add a comment |
I want to write a function that accepts a scriptblock as a parameter and executes that scriptblock in the scope in which it was invoked.
The Measure-Command is an example of the behavior I would like. The scriptblock runs in with the same scope as the Measure-Command itself. If the scriptblock references a variable in this scope, the script can change it.
Attached is a sample scriptblock that increments the $a variable. When invoked by Measure-Command, the variable is incremented. But when invoked by the Wrapper functions, the variable will not increment -- unless I dot-source both the invocation of the Wrapper function and the Wrapper function itself uses dot-sourcing.
function Wrapper1
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
& $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
function Wrapper2
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
. $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
$a = 1
Write-Output "Initial state: `$a = $a"
Measure-Command $a++ | Out-Null
Write-Output "Measure-Command results: `$a = $a"
Wrapper1 $a++
Write-Output "Wrapper1 results: `$a = $a"
. Wrapper1 $a++
Write-Output "dot-sourced Wrapper1 results: `$a = $a"
Wrapper2 $a++
Write-Output "Wrapper2 results: `$a = $a"
. Wrapper2 $a++
Write-Output "dot-sourced Wrapper2 results: `$a = $a"
The result of running this code is:
Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3
Although this last option works, I'd like to avoid the dot-source syntax invoking Wrapper2. Is this possible? The Measure-Command doesn't use the dot-source syntax so it seems that it would be possible.
function powershell scope
I want to write a function that accepts a scriptblock as a parameter and executes that scriptblock in the scope in which it was invoked.
The Measure-Command is an example of the behavior I would like. The scriptblock runs in with the same scope as the Measure-Command itself. If the scriptblock references a variable in this scope, the script can change it.
Attached is a sample scriptblock that increments the $a variable. When invoked by Measure-Command, the variable is incremented. But when invoked by the Wrapper functions, the variable will not increment -- unless I dot-source both the invocation of the Wrapper function and the Wrapper function itself uses dot-sourcing.
function Wrapper1
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
& $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
function Wrapper2
param( $scriptBlock )
$startTime = Get-Date
Write-Output ( "0:HH:mm:ss Start script" -f $startTime )
. $scriptBlock
$endTime = Get-Date
Write-Output ( "0:HH:mm:ss End script - 1:c seconds elapsed" -f $endTime, ( $endTime - $StartTime ) )
$a = 1
Write-Output "Initial state: `$a = $a"
Measure-Command $a++ | Out-Null
Write-Output "Measure-Command results: `$a = $a"
Wrapper1 $a++
Write-Output "Wrapper1 results: `$a = $a"
. Wrapper1 $a++
Write-Output "dot-sourced Wrapper1 results: `$a = $a"
Wrapper2 $a++
Write-Output "Wrapper2 results: `$a = $a"
. Wrapper2 $a++
Write-Output "dot-sourced Wrapper2 results: `$a = $a"
The result of running this code is:
Initial state: $a = 1
Measure-Command results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00.0157407 seconds elapsed
dot-sourced Wrapper1 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
Wrapper2 results: $a = 2
13:44:49 Start script
13:44:49 End script - 00:00:00 seconds elapsed
dot-sourced Wrapper2 results: $a = 3
Although this last option works, I'd like to avoid the dot-source syntax invoking Wrapper2. Is this possible? The Measure-Command doesn't use the dot-source syntax so it seems that it would be possible.
function powershell scope
function powershell scope
asked Nov 14 '18 at 22:11
bretthbretth
787
787
1
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14
add a comment |
1
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14
1
1
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14
add a comment |
1 Answer
1
active
oldest
votes
PetSerAl, as he is wont to do, has provided the crucial pointer in a terse comment on the question:
Putting the function in a module, along with dot-sourced invocation of the script-block argument, solves the problem:
$null = New-Module
function Wrapper
param($ScriptBlock)
. $ScriptBlock
$a = 1
Wrapper $a++
$a
The above yields 2
, proving that the script block executed in the caller's scope.
For an explanation of why this works and why it is necessary, see this answer to a related question.
Note: The above approach doesn't extend to pipeline use, where you'll want to pass script blocks that expect to use automatic variable $_
to reference the object at hand (e.g., 1, 2, 3 | Wrapper $_ ...
; to support this use case, a workaround is needed - see this answer.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309503%2fpowershell-running-a-scriptblock-scope-dot-sourcing%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
PetSerAl, as he is wont to do, has provided the crucial pointer in a terse comment on the question:
Putting the function in a module, along with dot-sourced invocation of the script-block argument, solves the problem:
$null = New-Module
function Wrapper
param($ScriptBlock)
. $ScriptBlock
$a = 1
Wrapper $a++
$a
The above yields 2
, proving that the script block executed in the caller's scope.
For an explanation of why this works and why it is necessary, see this answer to a related question.
Note: The above approach doesn't extend to pipeline use, where you'll want to pass script blocks that expect to use automatic variable $_
to reference the object at hand (e.g., 1, 2, 3 | Wrapper $_ ...
; to support this use case, a workaround is needed - see this answer.
add a comment |
PetSerAl, as he is wont to do, has provided the crucial pointer in a terse comment on the question:
Putting the function in a module, along with dot-sourced invocation of the script-block argument, solves the problem:
$null = New-Module
function Wrapper
param($ScriptBlock)
. $ScriptBlock
$a = 1
Wrapper $a++
$a
The above yields 2
, proving that the script block executed in the caller's scope.
For an explanation of why this works and why it is necessary, see this answer to a related question.
Note: The above approach doesn't extend to pipeline use, where you'll want to pass script blocks that expect to use automatic variable $_
to reference the object at hand (e.g., 1, 2, 3 | Wrapper $_ ...
; to support this use case, a workaround is needed - see this answer.
add a comment |
PetSerAl, as he is wont to do, has provided the crucial pointer in a terse comment on the question:
Putting the function in a module, along with dot-sourced invocation of the script-block argument, solves the problem:
$null = New-Module
function Wrapper
param($ScriptBlock)
. $ScriptBlock
$a = 1
Wrapper $a++
$a
The above yields 2
, proving that the script block executed in the caller's scope.
For an explanation of why this works and why it is necessary, see this answer to a related question.
Note: The above approach doesn't extend to pipeline use, where you'll want to pass script blocks that expect to use automatic variable $_
to reference the object at hand (e.g., 1, 2, 3 | Wrapper $_ ...
; to support this use case, a workaround is needed - see this answer.
PetSerAl, as he is wont to do, has provided the crucial pointer in a terse comment on the question:
Putting the function in a module, along with dot-sourced invocation of the script-block argument, solves the problem:
$null = New-Module
function Wrapper
param($ScriptBlock)
. $ScriptBlock
$a = 1
Wrapper $a++
$a
The above yields 2
, proving that the script block executed in the caller's scope.
For an explanation of why this works and why it is necessary, see this answer to a related question.
Note: The above approach doesn't extend to pipeline use, where you'll want to pass script blocks that expect to use automatic variable $_
to reference the object at hand (e.g., 1, 2, 3 | Wrapper $_ ...
; to support this use case, a workaround is needed - see this answer.
edited Jan 23 at 15:02
answered Nov 15 '18 at 3:48
mklement0mklement0
132k21246284
132k21246284
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53309503%2fpowershell-running-a-scriptblock-scope-dot-sourcing%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Put wrapper function in a module.
– PetSerAl
Nov 14 '18 at 23:14