1

I have a function written in PowerShell:

function replace([string] $name,[scriptblock] $action) {
    Write-Host "Replacing $name"
    $_ = $name
    $action.Invoke()
}

and would be used as:

$name = "tick"
replace $agentPath\conf\buildAgent.dist.properties {
    (cat templates\buildAgent.dist.properties.tpl) `
        -replace '@@serverurl@@', 'http:/localhost:8080/teamcity' `
        -replace '@@name@@', $name `
        > $_
}

However I've discovered that within the scriptblock the variable $name is overwritten by the $name param from within the replace function.

Is there a way to execute the script block so that only the variable $_ is added to the scope of the scriptblock but nothing else is?

2 Answers 2

1

I preface my answer by claiming that powershell is only for sadists. The trick is that if you put the function into a module the local variables become private and are not passed to the script block. Then to pass in the $_ variable you have to jump some more hoops.

The gv '_' get's the powershell variable $_ and passes it to the context via InvokeWithContext.

Now I know more than I ever wanted to :|

New-Module {
    function replace([string] $name,[scriptblock] $action) {
        Write-Host "Replacing $name"
        $_ = $name
        $action.InvokeWithContext(@{}, (gv '_'))
    }
}

and as before

$name = "tick"
replace $agentPath\conf\buildAgent.dist.properties {
    (cat templates\buildAgent.dist.properties.tpl) `
        -replace '@@serverurl@@', 'http:/localhost:8080/teamcity' `
        -replace '@@name@@', $name `
        > $_
}
Sign up to request clarification or add additional context in comments.

Comments

0

You could use the $global: prefix for the $name variable within your scriptblock:

$name = "tick"
replace $agentPath\conf\buildAgent.dist.properties {
    (cat templates\buildAgent.dist.properties.tpl) `
        -replace '@@serverurl@@', 'http:/localhost:8080/teamcity' `
        -replace '@@name@@', $global:name `
        > $_
}

3 Comments

I could but that is asking for me or another developer to forget one day and the problem randomly appears in the future. I'd expect there to be some kind of solution working from the other end where the caller of the script block is polite and doesn't inject all their local variables into the scope.
I found a way to do it. It's ugly for sure :) See my answer.
It looks ugly but I agree that its better for other developer using the function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.