Natalie Perret
Natalie Perret

Reputation: 9037

Closure and imported functions in Powershell

I have two PowerShell scripts. Test-Stuff.ps1 and Functions.ps1. Test-Stuff.ps1 rely on Functions.ps1, including a function that surround a function call to Write-Host the beginning and the end of the function excecution passed as parameter.

It works fine as long as the function passed as parameter does also not come from Functions.ps1. If that's the case the parameters to the passed functions are not captured by the invocation function.

Test-Stuff.ps1


# Let's stop whenever there is something wrong
$ErrorActionPreference = "Stop"

# Cleanup screen
Clear-Host

# We import the functions in that other PowerShell files
Import-Module "$PSScriptRoot\Functions.ps1" -Force

# Works fine
Invoke { Set-Location -Path $PSScriptRoot } "Change Current Working Directory to $PSScriptRoot"

# works fine too
Invoke { Write-Host "Testing" -ForegroundColor Red }

$configurationFileName = "Preprod.json"

# Works just fine
$configuration = Invoke { Get-Content -Raw -Path $configurationFileName | ConvertFrom-Json } "Fetch configuration"

$userName = $configuration.userName
$password = $configuration.serviceAccountPassword

# Does not work
$credential = Invoke { New-Credential $userName $password } "Fetch credential"

Functions.ps1

Function Write-Start($text)
{
    Write-Host ([System.Environment]::NewLine + "${text}...") -ForegroundColor Gray
}

Function Write-Stop($text)
{
    Write-Host ("${text}: Done") -ForegroundColor Green
}

Function Invoke([scriptblock]$scriptBlock, $text)
{
    Write-Start $text
    $result = $scriptBlock.Invoke()
    Write-Stop $text
    return $result
}

Execution of .\TestStuff.ps1:

Change Current Working Directory to C:\Users\eperret\Desktop\LetsSortThingsOut\KYC\Manual Deployment...
Change Current Working Directory to C:\Users\eperret\Desktop\LetsSortThingsOut\KYC\Manual Deployment: Done

...
Testing
: Done

Fetch configuration...
Fetch configuration: Done

Fetch credential...
Exception calling "Invoke" with "0" argument(s): "Exception calling ".ctor" with "2" argument(s): "Cannot process argument because the value of argument "userName" is not
valid. Change the value of the "userName" argument and run the operation again.""
At C:\Users\eperret\Desktop\LetsSortThingsOut\KYC\Manual Deployment\Functions.ps1:15 char:5
+     $result = $scriptBlock.Invoke()
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : CmdletInvocationException

PS C:\Users\eperret\Desktop\LetsSortThingsOut\KYC\Manual Deployment>

I tried to leverage GetNewClosure

$credential = Invoke { New-Credential $userName $password }.GetNewClosure() "Fetch credential"

... but does not seem to help much, how can I enforce the capture of the passed function parameters?

Upvotes: 0

Views: 98

Answers (1)

Dustin
Dustin

Reputation: 326

The problem seems to be with the contents of your scriptblock New-Credential $userName $password. I am unfamiliar with that cmdlet, is it from a module you have written or imported? If it is a valid cmdlet, it seems that maybe there is a problem with the contents of the arguments or there isn't an "overload" that matches them.

Maybe you should .Trim() and .ToString() that $Configuration.userName

Upvotes: 1

Related Questions