microsoft / Requirements

PowerShell framework for declaratively defining and idempotently imposing system configurations
MIT License
159 stars 26 forks source link

Passing variable through Requirement blocks #73

Open FireHelmet opened 2 years ago

FireHelmet commented 2 years ago

Hello @chriskuech ,

Could we passthrough variables between block ?

Because I use "invoke-command" cmdlet in block of Requirements and I would like to use a PSSession instead of creating a new session each time I invoke a remote command. Initiate a New-PSSession inside a Requirement is mandatory because in my code I test the WinRM connection before invoking any remote command, like:

@{ Describe = "Test WinRM connection '$VmName'" Test = { $online = $false ; while ($online -ne $true) { try { Test-WSMan -ComputerName $VmName -ErrorAction Stop ; $online = $true } catch { Start-Sleep 5 } } } },

Thank you !

chriskuech commented 2 years ago

Current pattern for shared state is to read/write to an object in the parent scope.

$sharedState = @{}

@{
    Describe = "State is set"
    Set = { $sharedState["myProp"] = 42 }
}
@{
    Describe = "State is read to file"
    Set = {  $sharedState["myProp"] > .\state.txt }
}
FireHelmet commented 2 years ago

@chriskuech ,

Okay, so from your example I should be able to pass $PSSession if it's defined before the invoke-command, like

@{
    Describe = "Initiate PSSession"
    Set      = { $PSSession = New-PSSession -ComputerName $VmName }
},
@{
    Describe = "Invoke-Command"
    Test     = { Invoke-Command -Session $PSSession -ScriptBlock { ... } }
    Set      = { Invoke-Command -Session $PSSession -ScriptBlock { ... } }
}

But I still get an error

chriskuech commented 2 years ago

No, in your example $PSSession is declared in a script block, so it is only scoped to that scriptblock, whereas in my example, $sharedState is defined outside any script block--that's why you have to set properties on the referenced object instead of only setting the variable.

I haven't used this module recently so I'm a little rusty, but you might also need to call the GetNewClosure() method on the scriptblock itself.