How do you call a PowerShell function with an Object of Arguments - powershell

In PowerShell, one can generally call a function with arguments as follows:
DoRoutineStuff -Action 'HouseKeeping' -Owner 'Adamma George' -Multiples 4 -SkipEmail
To trap these 4 supplied arguments at runtime, one might place this inside the function definition
""
"ARGUMENTS:"
$PSBoundParameters
And the resulting object displayed might look like so:
ARGUMENTS:
Key Value
--- -----
Action HouseKeeping
Owner Adamma George
Multiples 4
SkipEmail True
Now, my question is: If I were to manually build the $MyObject identical to $PSBoundParameters displayed above, is there a way to say:
RunFunction 'DoRoutineStuff' -oArgument $MyObject
Again, if it were to be a script file rather than the function DoRoutineStuff, does that make any difference?
Why might one need to do this?
Picture a situation where you need to catch the arguments supplied to first script or function, using $PSBoundParameters, like so:
DoRoutineStuff{
param(
[string]$Action,
[string]$Owner,
[Int]$Multiples,
[switch]$SkipEmail
)
$Data = $PSBoundParameters
#Update one object property
$Data.Multiples = 1
#Then, recursively call `DoRoutineStuff` using `$Data`
#Other tasks
exit;
}

It sounds like the language feature you're looking for is splatting.
You simply pack you're named parameter arguments into a hashtable, store that in a variable and then pass the variable using # in front of its name:
$myArguments = #{
Action = 'HouseKeeping'
Owner = 'Adamma George'
Multiples = 4
SkipEmail = $true
}
Do-Stuff #myArguments
You can also use this technique to only pass a partial set of parameter arguments (or none at all), great for passing along conditional arguments:
$myArguments = #{}
if($someCondition){
$myArguments['Multiples'] = 1
$myArguments['SkipEmail'] = $true
}
if($somethingElse){
$myArguments['Multiple'] = 4
}
Do-Stuff -Action 'HouseKeeping' -Owner 'Adamma George' #myArguments
You can also reuse $PSBoundParameters for splatting further - very useful for proxy functions:
function Measure-Files
{
param(
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $false)]
[string]$Filter,
[Parameter(Mandatory = $false)]
[switch]$Recurse
)
return (Get-ChildItem #PSBoundParameters |Measure-Object -Property Length).Sum
}

Related

export a string from poweshell 1 to powershell 2

I have a shell script file.
./1.ps1
./2.ps1
I generate a string such as env-0 in 1.ps1 and need to export it to 2.ps1.
UPDATE:
1.ps1 generate many string and I couldn't pass my env-0 as argument to 2.ps1.
Do you have another solution?
PowerShell's stream-like I/O model is a little unusual, but any value not captured is basically output - so to output the string env-0 from 1.ps1, this is literally all you need:
"env-0"
Now that 1.ps1 outputs a string value, we need some way to feed it to 2.ps1.
You can either rely on unbound positional arguments, which will automatically be available in the target script/function via the $args variable:
# 2.ps1
$envString = $args[0]
# work with your `$envString` value here
To invoke:
$envString = ./1.ps1
./2.ps1 $envString
# or
./2.ps1 $(./1.ps1)
You can also accept pipeline input by consuming the $input automatic input enumerator variable:
# 2.ps1
$input |ForEach-Object {
$envString = $_
# work with your `$envString` value here
}
To invoke:
./1.ps1 |./2.ps1
This might be useful if you intend to provide multiple inputs to 2.ps1 in succession:
# This will execute `./1.ps1` 100 times, but `./2.ps1` will only be executed once, and the output continuously fed to it as pipeline input
1..100 |ForEach-Object { ./1.ps1 } | ./2.ps1
Finally, if you want to write scripts for more advanced scenarios (multiple input parameters, input validation, argument completion etc.), you'll want to explicitly declare named parameter(s) with a param() block:
# ./2.ps1
param(
[Parameter(Mandatory)]
[string]$Environment
)
# work with $Environment here
To invoke:
./2.ps1 -Environment $(./1.ps1)
It's worth noting that you can use the [Parameter()] attribute to modify the binding behavior so you still get pipeline support:
# ./2.ps1
param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[string]$Environment
)
# work with $Environment here
Now that we've added both the Position and a ValueFromPipeline flags, we can pass the string via the pipeline, by name, or positionally all at once:
# These all work now
./2.ps1 -Environment $(./1.ps1)
./2.ps1 $(./1.ps1)
./1.ps1 |./2.ps1
The only caveat is that you can't pipe multiple input values anymore - for that, you'll need to move the script body into a special process block:
# ./2.ps1
param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[string]$Environment
)
process {
# work with $Environment here
}
The process block will execute exactly once for each pipeline input, so now piping multiple values works again ()along with the previous 3 examples:
1..100 |ForEach-Object { ./1.ps1 } | ./2.ps1
So that's my solution:
# 1.ps1
"env-0"
# 2.ps1
# ./2.ps1
param(
[Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[string]$Environment
)
process {
# work with $Environment here
}
For more information about advanced parameters and their binding semantics and how to utilise them, see the about_Functions_Advanced_Parameters help topic

Powershell splatting operator only for accepted parameters?

Is it possible, using PowerShell, to use splatting from hashtable when the hashtable contains more entries that the function accepts ?
My use case is to have config objects I pass from one function to another. However, all functions does not require same parameters.
Ex:
function Process-Something{
param(
[Parameter()]
[string]$Owner
)
}
function Process-SomethingElse{
param(
[Parameter()]
[string]$Owner,
[Parameter()]
[int]$x,
[Parameter()]
[int]$y
)
}
$config = #{
"Owner" = "Bart Simpson"
"X" = 10
"Y" = 20
}
Process-Something #config
Process-SomethingElse #config
It fails with these error:
Process-Something : Cannot find a matching parameter « Y ».
The idea is to avoid specifying individual properties for each functions.
As #Ansgar is stating in the comments, the whole idea of having defined your parameters, is to get validation. When you are splatting parameters to your function, you are forcing them to the function. So if a given property of your hashtable doesn't exist as a parameter, you will get an error - just like it is intended.
What you can do, is going into a PSCustomObject and utilize the pipe. If you set all you parameters to accept value from the pipeline, using property name (ValueFromPipelineByPropertyName = $true), then you can actually get the desired behavior.
First I'm redefining your different functions, to have the ValueFromPipelineByPropertyName = $true parameter attribute configured.
function Process-Something{
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[string]$Owner
)
$PSBoundParameters
}
function Process-SomethingElse{
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[string]$Owner,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[int]$x,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[int]$y
)
$PSBoundParameters
}
With that in place, I'm able to create a hashtable like your example, convert it to a PSCustomObject, and now I can pipe that new object to the different methods and have them pick up only the properties that they need.
I included the PSBoundParameters to showcase that they get what they expect.
Testing is done like this:
$config = #{
"Owner" = "Bart Simpson"
"X" = 10
"Y" = 20
}
$psConfig = [PSCustomObject]$config
$psConfig | Process-Something
$psConfig | Process-SomethingElse

Dynamic invoke command with different parameters

In a PowerShell script, I want to read a CSV file that contains something like this:
Type Title Param1 Param2
---- ----- ------ ------
Type1 Foo type 1 ValueForType1
Type2 Foo type 2 ValueForType2
When type is Type1, I have to call a function named New-FooType1, when type is Type2, the funcation is named New-FooType2, and so on:
function New-FooType1{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Title,
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Param1
)
Write-Host "New-FooType1 $Title with $Param1"
}
function New-FooType2{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Title,
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Param2
)
Write-Host "New-FooType2 $Title with $Param2"
}
I'm trying to route the call to either of the functions, using a dynamic invocation:
$csv | % {
$cmdName = "New-Foo$($_.Type)"
Invoke-Command (gcm $cmdName) -InputObject $_
}
However, I always get an error:
Parameter set cannot be resolved using the specified named parameters
As you can see, different type mean different parameters set.
How can I solve this? I would like to avoid manipulating properties manually, because in my real life script, I have a dozen of different types, with up to 6 parameters.
Here is a complete repro sample of the issue:
$csvData = "Type;Title;Param1;Param2`nType1;Foo type 1;ValueForType1;;`nType2;Foo type 2;;ValueForType2"
$csv = ConvertFrom-csv $csvData -Delimiter ';'
$csv | ft -AutoSize
function New-FooType1{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Title,
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Param1
)
Write-Host "New-FooType1 $Title with $Param1"
}
function New-FooType2{
param(
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Title,
[Parameter(Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[string]$Param2
)
Write-Host "New-FooType2 $Title with $Param2"
}
$csv | % {
$cmdName = "New-Foo$($_.Type)"
Invoke-Command (gcm $cmdName) -InputObject $_
}
The expected output of this script is:
New-FooType1 Foo type 1 with ValueForType1
New-FooType2 Foo type 2 with ValueForType2
Use the call operator &:
$CmdName = "New-FooType1"
$Arguments = "type1"
& $CmdName $Arguments
the call operator also supports splatting if you want the arguments bound to specific named parameters:
$Arguments = #{
"title" = "type1"
}
& $CmdName #Arguments
To invoke command by name you should use invoke operator &. Invoke-Command cmdlet support only ScriptBlock and file invocation, and file invocation only supported for remote calls.
For dynamic parameter binding you can use spatting, but in that case you have to convert PSCustomObjects, returned by ConvertFrom-Csv cmdlet, to Hashtable. You also have to strip any extra parameters from Hashtable because splatting will fail if you try to bind non-existing parameter.
Another approach for dynamic parameter binding would be to use binding from pipeline object. It looks like it is what you want to do, since you mark all your parameters with ValueFromPipelineByPropertyName option. And this approach will just ignore any extra property it can not bind to parameter. I recommend you to remove ValueFromPipeline option, because with this option in case of absence of property with parameter name PowerShell will just convert PSCustomObject to string (or to whatever type you use for parameter) and pass it as value for parameter.
So, all you need is to pass object by pipeline and use invoke operator for invocation of command with dynamic name:
$_ | & "New-Foo$($_.Type)"
dont know exactly what your trying to do, but
Invoke-Command (gcm $cmdName) ?
Try invoke-expression $cmdname

Pass an unspecified set of parameters into a function and thru to a cmdlet

Let's say I want to write a helper function that wraps Read-Host. This function will enhance Read-Host by changing the prompt color, calling Read-Host, then changing the color back (simple example for illustrative purposes - not actually trying to solve for this).
Since this is a wrapper around Read-Host, I don't want to repeat the all of the parameters of Read-Host (i.e. Prompt and AsSecureString) in the function header. Is there a way for a function to take an unspecified set of parameters and then pass those parameters directly into a cmdlet call within the function? I'm not sure if Powershell has such a facility.
for example...
function MyFunc( [string] $MyFuncParam1, [int] $MyFuncParam2 , Some Thing Here For Cmdlet Params that I want to pass to Cmdlet )
{
# ...Do some work...
Read-Host Passthru Parameters Here
# ...Do some work...
}
It sounds like you're interested in the 'ValueFromRemainingArguments' parameter attribute. To use it, you'll need to create an advanced function. See the about_Functions_Advanced and about_Functions_Advanced_Parameters help topics for more info.
When you use that attribute, any extra unbound parameters will be assigned to that parameter. I don't think they're usable as-is, though, so I made a little function that will parse them (see below). After parsing them, two variables are returned: one for any unnamed, positional parameters, and one for named parameters. Those two variables can then be splatted to the command you want to run. Here's the helper function that can parse the parameters:
function ParseExtraParameters {
[CmdletBinding()]
param(
[Parameter(ValueFromRemainingArguments=$true)]
$ExtraParameters
)
$ParamHashTable = #{}
$UnnamedParams = #()
$CurrentParamName = $null
$ExtraParameters | ForEach-Object -Process {
if ($_ -match "^-") {
# Parameter names start with '-'
if ($CurrentParamName) {
# Have a param name w/o a value; assume it's a switch
# If a value had been found, $CurrentParamName would have
# been nulled out again
$ParamHashTable.$CurrentParamName = $true
}
$CurrentParamName = $_ -replace "^-|:$"
}
else {
# Parameter value
if ($CurrentParamName) {
$ParamHashTable.$CurrentParamName += $_
$CurrentParamName = $null
}
else {
$UnnamedParams += $_
}
}
} -End {
if ($CurrentParamName) {
$ParamHashTable.$CurrentParamName = $true
}
}
,$UnnamedParams
$ParamHashTable
}
You could use it like this:
PS C:\> ParseExtraParameters -NamedParam1 1,2,3 -switchparam -switchparam2:$false UnnamedParam1
UnnamedParam1
Name Value
---- -----
switchparam True
switchparam2 False
NamedParam1 {1, 2, 3}
Here are two functions that can use the helper function (one is your example):
function MyFunc {
[CmdletBinding()]
param(
[string] $MyFuncParam1,
[int] $MyFuncParam2,
[Parameter(Position=0, ValueFromRemainingArguments=$true)]
$ExtraParameters
)
# ...Do some work...
$UnnamedParams, $NamedParams = ParseExtraParameters #ExtraParameters
Read-Host #UnnamedParams #NamedParams
# ...Do some work...
}
function Invoke-Something {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true, Position=0)]
[string] $CommandName,
[Parameter(ValueFromRemainingArguments=$true)]
$ExtraParameters
)
$UnnamedParameters, $NamedParameters = ParseExtraParameters #ExtraParameters
&$CommandName #UnnamedParameters #NamedParameters
}
After importing all three functions, try these commands:
MyFunc -MyFuncParam1 Param1Here "PromptText" -assecure
Invoke-Something -CommandName Write-Host -Fore Green "Some text" -Back Red
One word: splatting.
Few more words: you can use combination of $PSBoundParameters and splatting to pass parameters from external command, to internal command (assuming names match). You would need to remove any parameter that you don't want to use though from $PSBoundParameters first:
$PSBoundParameters.Remove('MyFuncParam1')
$PSBoundParameters.Remove('MyFuncParam2')
Read-Host #PSBoundParameters
EDIT
Sample function body:
function Read-Data {
param (
[string]$First,
[string]$Second,
[string]$Prompt,
[switch]$AsSecureString
)
$PSBoundParameters.Remove('First') | Out-Null
$PSBoundParameters.Remove('Second') | Out-Null
$Result = Read-Host #PSBoundParameters
"First: $First Second: $Second Result: $Result"
}
Read-Data -First Test -Prompt This-is-my-prompt-for-read-host

Is it possible to extend indexers in PowerShell?

PowerShell's type extension facility is neat, but I haven't yet figured out the way -- if one exists -- to extend an indexer. I've tried to add a ScriptProperty for the indexer property (Chars in the case of System.String) and a ScriptMethod for the getter (get_Chars), but neither approach seems fruitful. Is it at all possible, or am I wasting my time? :)
[Edit] Apparently the proper member type is ParameterizedProperty, but when I try that, I get:
Add-Member : Cannot add a member with type "ParameterizedProperty". Specify a different
type for the MemberTypes parameter.
At line:1 char:11
+ Add-Member <<<< -MemberType ParameterizedProperty -Name Item -InputObject $string { "x" }
+ CategoryInfo : InvalidOperation: (:) [Add-Member], InvalidOperationException
+ FullyQualifiedErrorId : CannotAddMemberType,Microsoft.PowerShell.Commands.AddMemberCommand
I'm going to conclude that the error message I'm getting is the final word on the matter. Also, on further reflection it has become obvious that the sort of extending I was hoping for is not supported by this mechanism anyway. :-)
You can't create ParameterizedProperty properties directly in Powershell, but you are able to indirectly create them by allowing Powershell to wrap a PSObject around an object that has an accessor property. You then make this PSObject a NoteProperty on the object to which you want to add the property.
In C#, we are talking about a this[] accessor. I have written a Powershell script which creates a minimal .NET object which has as this[] accessor. In order to make this as generic as possible, I have tried to copy what the ScriptProperty member does, and I have added two properties of type ScriptBlock - one for a Get block, and another for a Set block. So essentially, when the user sets the this[] accessor, it calls the Set block, and when the user retrieves from the this[] accessor, it calls the Get block.
The following module, I have called PSObjectWrappers.psm1:
<#
.SUMMARY
Creates a new ParameterizedPropertyAccessor object.
.DESCRIPTION
Instantiates and returns an object compiled on the fly which provides some plumbing which allows a user to call a new Parameterized
Property, which looks as if it is created on the parent object. In fact, a NoteProperty is created on the parent object which retrieves
an instance of ParameterizedPropertyAccessor, which has a this[] accessor which Powershell wraps in a ParameterizedProperty object.
When the this[] accessor is retrieved, it tries to retrieve a value via a Get script block. When the this[] accessor is updated, this
triggers a Set script block.
.NOTES
No actual variable value state is stored by this object.
The C# code is conditionally compiled to take advantage of new functionality in Powershell 4. Before this version, the first parameter
in the Set and Get script blocks must be "[PSObject] $this". From this version, the $this parameter is automatically created for the user.
#>
Function New-ParameterizedPropertyAccessor
{
Param(
# Contains the object on which the "ParameterizedProperty" will be added.
[Parameter(Mandatory = $true, Position = 0)]
[PSObject] $Parent,
# The name of the parameterized property.
[Parameter(Mandatory = $true, Position = 1)]
[string] $Name,
# Script block which will be called when the property is retrieved.
# First parameter must be $this. Second parameter must be $key.
[Parameter(Mandatory = $true, Position = 2)]
[scriptblock] $Get,
# Script block which will be called when the property is set.
# First parameter must be $this. Second parameter must be $key. Third parameter must be $value.
[Parameter(Mandatory = $true, Position = 3)]
[scriptblock] $Set
);
# Note. You *MUST* ensure the next line starts at position 1 on the line. Likewise, the last line of the code *MUST*
# start at position 1 on the line.
$csharpCode = #'
using System;
using System.Collections.Generic;
using System.Management.Automation;
public class ParameterizedPropertyAccessor
{
private PSObject _parentPsObject;
private ScriptBlock _getBlock;
private ScriptBlock _setBlock;
public ParameterizedPropertyAccessor(PSObject parentPsObject, string propertyName, ScriptBlock getBlock, ScriptBlock setBlock)
{
_parentPsObject = parentPsObject;
PSVariable psVariable = new PSVariable(propertyName, this, ScopedItemOptions.ReadOnly);
PSVariableProperty psVariableProperty = new PSVariableProperty(psVariable);
_parentPsObject.Properties.Add(psVariableProperty);
_getBlock = getBlock;
_setBlock = setBlock;
}
public object this[object key]
{
get
{
#if WITH_CONTEXT
return _getBlock.InvokeWithContext(null, new List<PSVariable> { new PSVariable("this", _parentPsObject) }, new object[] { key });
#else
return _getBlock.Invoke(new object[] { _parentPsObject, key });
#endif
}
set
{
#if WITH_CONTEXT
_setBlock.InvokeWithContext(null, new List<PSVariable> { new PSVariable("this", _parentPsObject) }, new object[] { key, value });
#else
_setBlock.Invoke(new object[] { _parentPsObject, key, value });
#endif
}
}
}
'#;
<#
The version of the ScriptBlock object in Powershell 4 and above allows us to create automatically declared
context variables. In this case, we are providing a $this object, like you would get if we were using a
ScriptMethod or ScriptProperty member script. If we are using this version, then set the WITH_CONTEXT symbol
to conditionally compile a version of the C# code above which takes advantage of this.
#>
If ($PSVersionTable.PSVersion.Major -ge 4)
{
$compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters;
$compilerParameters.CompilerOptions = "/define:WITH_CONTEXT";
$compilerParameters.ReferencedAssemblies.Add( "System.dll" );
$compilerParameters.ReferencedAssemblies.Add( "System.Core.dll" );
$compilerParameters.ReferencedAssemblies.Add( ([PSObject].Assembly.Location) );
}
# Compiles the C# code in-memory and allows us to instantiate it.
Add-Type -TypeDefinition $csharpCode -CompilerParameters $compilerParameters;
# Instantiates the object.
New-Object ParameterizedPropertyAccessor -ArgumentList $Parent,$Name,$Get,$Set;
}
Note that I have done so conditional compilation in the C# code to make the code behave like a proper ScriptBlock in Powershell 4 and above, so a $this variable is automatically provided. Otherwise, you must ensure that the first parameter in each script block is called $this.
The following is my test script, Test-PPA.ps1:
<#
.SYNOPSIS
Test script for the ParameterizedPropertyAccessor object.
#>
<#
.SYNOPSIS
Create a new PSCustomObject which will contain a NoteProperty called Item accessed like a ParameterizedProperty.
#>
Function New-TestPPA
{
# Instantiate our test object.
$testPPA = New-Object -TypeName PSCustomObject;
# Create a new instance of our PPA object, added to our test object, providing it Get and Set script blocks.
# Note that currently the scripts are set up for Powershell 4 and above. If you are using a version of Powershell
# previous to this, comment out the current Param() values, and uncomment the alternate Param() values.
$ppa = New-ParameterizedPropertyAccessor -Parent $testPPA -Name Item -Get `
{
Param(
<#
[Parameter(Mandatory = $true, Position = 0)]
[PSObject] $this,
[Parameter(Mandatory = $true, Position = 1)]
[string] $Key
#>
[Parameter(Mandatory = $true, Position = 0)]
[string] $Key
)
$this._ht[$Key];
} -Set {
Param(
<#
[Parameter(Mandatory = $true, Position = 0)]
[PSObject] $this,
[Parameter(Mandatory = $true, Position = 1)]
[string] $Key,
[Parameter(Mandatory = $true, Position = 2)]
[string] $Value
#>
[Parameter(Mandatory = $true, Position = 0)]
[string] $Key,
[Parameter(Mandatory = $true, Position = 1)]
[string] $Value
)
$this._ht[$Key] = $Value;
};
# Add a HashTable <_ht> used as our backing store. Note that this could be any keyed collection type object.
$testPPA | Add-Member -MemberType NoteProperty -Name _ht -Value #{} -PassThru;
}
[string] $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent;
Import-Module $scriptDir\PSObjectWrappers.psm1;
# Create test object.
$testPPA = New-TestPPA;
# Note that "Item" property is actually a NoteProperty of type ParameterizedPropertyAccessor.
Write-Host "Type '`$testPPA | gm' to see Item NoteProperty.";
# Note that it is the ParameterizedPropertyAccessor object retrieved that has a ParameterizedProperty.
# Also note that Powershell has named this property "Item".
Write-Host "Type '`$testPPA.Item | gm' to see Item ParameterizedProperty";
# Step through what happens when we "set" the "parameterized" Item property.
# Note that this is actually retrieving the Item NoteProperty, and then setting its default accessor, which calls
# the 'Set' ScriptBlock.
Write-Host "";
Write-Host "Setting Name value";
Write-Host "... to 'Mark'."
$testPPA.Item["Name"] = "Mark";
# Step through what happens when we "get" the "parameterized" Item property.
# Note that this is actually retrieving the Item NoteProperty, and then retrieving its default accessor, which calls
# the 'Get' ScriptBlock.
Write-Host "";
Write-Host "Retrieving Name value:";
$temp = $testPPA.Item["Name"];
Write-Host $temp;
Note that you will have to change the script blocks, as indicated, if you are using versions previous to Powershell 4.