Reputation: 75
For sake the of learning only.
Let's say I have a variable, in this example a textbox, how could I set many properties at once without typing the variable name over and over.
I've attempted some stuff my self, one of them work for some odd reason.
This example works. Break is used to shorten the loop.
$Textbox | % {
$_.Text = "Hello World"
$_.Background = "Black"
$_.Foreground = "Green"
Break
}
These two examples do not work and are here just to see what I've attempted.
This was with and without "$_."s and instead of a "." I've used "=" and "+=", none of which worked.
$Textbox.@{
Text = "Hello World"
Background = "Black"
Foreground = "Green"
}
$Textbox.({
$_.Text = "Hello World"
$_.Background = "Black"
$_.Foreground = "Green"
})
There may be a easier way to do, I haven't come across anything on google.
Upvotes: 4
Views: 3995
Reputation: 61
Building on the example by @mklement0:
It is possible to initialize an object even if the class does not have a parameter-less constructor by using a combination of -ArgumentList [Object[]] and -Property [IDictionary].
Class TestClass
{
[string]$ConstructorProperty
[string]$PublicProperty
[string]$PublicProperty1
# ...
# Note: a constructor is defined.
TestClass([string]$ConstructorProperty) {
$this.ConstructorProperty = $ConstructorProperty
}
}
New-Object TestClass `
-ArgumentList @('c0') `
-Property @{ PublicProperty = 'p0'; PublicProperty1 = 'p1'}
Upvotes: 0
Reputation: 437663
What you're looking for is a language construct such as VB[Script]'s With
statement, which allows you to set an implied context for "object-less" property references (such as .Text
) inside a block.
There is no such construct in PowerShell.
Your 1st attempt is the closest emulation in PowerShell, albeit at the expense of performance (though that may not matter): in a pipeline, automatic variable $_
allows for a concise reference to the input object at hand.
Important: Do not use break
inside a pipeline: it won't just exit the pipeline, it will exit any enclosing loop and, in the absence of one, the enclosing script. Use return
instead.
That said, in the case at hand, with only a single input object, return
is not needed.
As for your other attempts:
Syntax @{...}
is only used for hashtable literals. Trying to use this syntax as a property name causes a syntax error.
Syntax (...)
evaluates any single command / expression enclosed; {...}
defines a script block.
A script block that isn't actually executed (which would require &
), when used in a string context - such as a property name here, evaluates to its literal contents between {
and }
, i.e., a multiline string that clearly does not represent the name of an existing property of $TextBox
, so the overall result is $null
.
Note that a script run in the appropriate strict mode - with Set-StrictMode -Version 2
or higher - would have flagged the above attempt to access a non-existent property as an error.
By contrast, an attempt to assign to a non-existent property always generates an error.
Note, however, that PowerShell offers convenient multi-property initialization in the context of constructing objects, which in PowerShell you can frequently also achieve with casts, via hashtable initializers.
# Cast a hashtable with property name/value pairs to
# [System.Windows.Forms.TextBox], which implicitly constructs
# an instance with the specified property values:
$TextBox = [System.Windows.Forms.TextBox] @{
Text = "Hello World"
Location = [Point]::new(10, 50)
}
The caveat is that the availability of this technique depends on whether the target type has a parameter-less constructor - see this answer for details.
Upvotes: 7
Reputation: 73556
In case you maintain dictionaries (hashtables) of properties for other purposes as well, you can write a simple function that applies the data to an object:
function Set-Properties(
[parameter(ValueFromPipeline)] $inputObject,
[hashtable] $properties,
[switch] $passThru
) {
process {
Add-Member -InputObject $inputObject -NotePropertyMembers $properties -force
if ([bool]$passThru) { $inputObject }
}
}
Usage:
Set-Properties $Textbox @{
Text = "Hello World"
Background = "Black"
Foreground = "Green"
}
$Textbox1, $Textbox2 | Set-Properties -properties @{
Text = "Hello World"
Background = "Black"
Foreground = "Green"
} -passThru | ForEach {
# do something
}
Upvotes: 1