Reputation: 110
I'm trying to write a few scripts using calculated properties (love that feature), and I seem to have an issue when I assign variables in it, for example:
ls | select @{N='What';E={get-acl | Tee-Object -Variable something}},@{N="ok";E={$something}}
it seems that the output I'm getting is:
And I'm unsure if there's a way to save a variable so I can use it in a different calculated property or even just piped to the next command? ( I do know that you can use that variable in the same calculated property though.)
Thanks to anyone who helps.
Upvotes: 0
Views: 186
Reputation: 174485
If you need to construct many inter-related properties and Select-Object
is too verbose or inefficient, the idiomatic approach is to pipe to ForEach-Object
and construct the output object manually:
Get-ChildItem |ForEach-Object {
$acl = $_ |Get-Acl
# now we can just use this local variable directly
$isOK = Test-WhateverYouNeedToTest $acl
# construct new object
[pscustomobject]@{
FilePath = $_.FullName
ACL = $acl
RuleCount = $acl.Access.Count
IsOK = $isOK
}
}
I'm unsure if there's a way to save a variable so I can use it in a different calculated property
You can't "cross-reference" the resolved value of one calculated property expression from another in the same call, if that's what you mean.
Property expressions are executed in their own local scope, which is why variable assignments also don't persist.
You could (but probably shouldn't) assign to a variable in a parent scope:
ls | select Name,@{N='ACL';E={ ($global:something = $_ |Get-Acl) }},@{N='RuleCount';E={$something.Access.Count}}
I would strongly recommend against it - keeping calculated properties free of side effects will make your code easier to read and understand.
[...] or even just piped to the next command
Again, you could, (but probably shouldn't) assign to a variable in a parent scope and use that with the downstream command:
ls | select @{N='ACL';E={ ($global:something = $_ |Get-Acl) }} | select ACL,@{N='RuleCount';E={$something.Access.Count}}
To explain why this is a bad idea, let's take this example instead:
function TimesTen {
1..10 | select @{N='Base';E={$global:v10 = $_ * 10; $_}} | select Base,@{N='Tenfold';E={$v10}}
}
This might appear to work as intended:
PS ~> TimesTen
Base Tenfold
---- -------
1 10
2 20
3 30
4 40
5 50
6 60
7 70
8 80
9 90
10 100
But this only works as long as pipeline output from Select-Object
isn't buffered:
PS ~> $PSDefaultParameterValues['Select-Object:OutBuffer'] = 4
PS ~> TimesTen
Base Tenfold
---- -------
1 50
2 50
3 50
4 50
5 50
6 100
7 100
8 100
9 100
10 100
Oops! Now you need to explicitly prevent that:
function TimesTen {
1..10 | select @{N='Base';E={$global:v10 = $_ * 10; $_}} -OutBuffer 0 | select Base,@{N='Tenfold';E={$v10}}
}
With ForEach-Object
, you avoid all of this.
Upvotes: 1