How to pass value along with parameter? Something like ./test.ps1 -controllers 01. I want the script to use hyphen and also a value is passed along for the parameter.
Here is the part of the script I wrote. But if I call the script with hyphen (.\test.ps1 -Controllers) it says A parameter cannot be found that matches parameter name 'Controllers'.
param(
# [Parameter(Mandatory=$false, Position=0)]
[ValidateSet('Controllers','test2','test3')]
[String]$options
)
Also I need to pass a value to it which is then used for a property.
if ($options -eq "controllers")
{
$callsomething.$arg1 | where {$_ -eq "$arg2" }
}
Lets talk about why it does not work
function Test()
param(
[Parameter(Mandatory=$false, Position=0)]
[ValidateSet('Controllers','test2','test3')]
[String]$options
)
}
Parameters are Variables that are created and filled out at the start of the script
ValidateSet will only allow the script to run if $Options equals one of the three choices 'Controllers','test2','test3'
Lets talk about what exactly all the [] are doing
Mandatory=$false means that $options doesnt have to be anything in order for the script to run.
Position=0 means that if you entered the script without using the -options then the very first thing you put would still be options
Example
#If Position=0 then this would work
Test "Controllers"
#Also this would work
Test -options Controllers
[ValidateSet('Controllers','test2','test3')] means that if Option is used or is Mandatory then it has to equal 'Controllers','test2','test3'
It sounds like you are trying to create parameters at runtime. Well that is possible using DynamicParam.
function Test{
[CmdletBinding()]
param()
DynamicParam {
$Parameters = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
'Controllers','test2','test3' | Foreach-object{
$Param = New-Object System.Management.Automation.ParameterAttribute
$Param.Mandatory = $false
$AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$AttribColl.Add($Param)
$RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter("$_", [string], $AttribColl)
$Parameters.Add("$_", $RuntimeParam)
}
return $Parameters
}
begin{
$PSBoundParameters.GetEnumerator() | ForEach-Object{
Set-Variable $_.Key -Value $_.Value
}
}
process {
"$Controllers $Test2 $Test3"
}
}
DynamicParam allows you to create parameters in code.
The example above turns the array 'Controllers','test2','test3' into 3 separate parameters.
Test -Controllers "Hello" -test2 "Hey" -test3 "Awesome"
returns
Hello Hey Awesome
But you said you wanted to keep the hypen and the parameter
So the line
$PSBoundParameters.GetEnumerator() | ForEach-Object{
Set-Variable $_.Key -Value $_.Value
}
allows you to define each parameter value. a slight change like :
$PSBoundParameters.GetEnumerator() | ForEach-Object{
Set-Variable $_.Key -Value "-$($_.Key) $($_.Value)"
}
Would return
-Controllers Hello -test2 Hey -test3 Awesome
I have an array of objects like this
$all = #(
#{ Name = 'First'; Method = { FirstMethod 1 }; Description = "First Description"; }
#{ Name = 'Second'; Description = "Second Description" }
#{ Name = 'Third'; Method = { ThirdMethod }; Description = "Third Description" }
)
Which every obeject has a Name (string), a Description (string), and a Method (which contains a function and its optional)
While the FirstMethod and SecondMethod looks like this:
Function FirstMethod
{
param($number)
Write-Host "$number - some other things"
return $number
}
Function ThirdMethod
{
Write-Host "Second called"
return 'test'
}
And I am iterating through all the items in $all and trying to call Method parameter if it exists:
Function RunAll
{
foreach($item in $all)
{
If($item.Method)
{
Write-Host "It has method and its running it"
$returned_from_method = $item.Method
Write-Host "Value returned from method: $returned_from_method"
}
Else
{
Write-Host "Does not have a method!"
}
}
}
So basically what I need here is that: when the loop is in the First item in array $returned_from_method = $item.Method it should return 1 (because it calls FirstMethod and passes 1. And when the loop is in the Third item in array it should return test (because it calls ThirdMethod).
Is there anyway I can achieve this?
The code you posted does neither define (custom) objects nor methods. It defines a list of hashtables where one key has a scriptblock value. Using dot-access on that key will just return the definition of the scriptblock, not invoke it.
Demonstration:
PS C:\> $ht = #{Name='foo'; Method={FirstMethod 1}; Description='bar'}
PS C:\> $ht.Method
FirstMethod 1
Even if you convert the hashtable to an object, that behavior does not change:
PS C:\> $obj = [PSCustomObject]$ht
PS C:\> $obj.Method
FirstMethod 1
To actually invoke the scriptblock you need to call the scriptblock's Invoke() method:
PS C:\> $ht.Method.Invoke()
1 - some other things
1
PS C:\> $obj.Method.Invoke()
1 - some other things
1
Whether the function called in the scriptblock is defined before or after creation of the hashtable or object doesn't matter, as long as it is defined before the scriptblock is invoked. The code in your own answer seems to work only because you replaced the scriptblock (curly brackets) with a grouping expression (parentheses). That means, however, that the "method" is evaluated upon definition of the hashtable and only the return value of the function is stored with the key. The Write-Host output is written to the console immediately and not stored with the key.
PS C:\> $ht = #{Name='foo'; Method=(FirstMethod 1); Description='bar'}
1 - some other things
PS C:\> $ht.Method
1
For creating an object with an actual (script)method you need to add a property with the correct type:
PS C:\> $obj | Add-Member -Name 'Method2' -Type ScriptMethod -Value {FirstMethod 2}
PS C:\> $obj.Method2()
2 - some other things
2
The code for creating your objects should thus look somewhat like this:
$obj1 = [PSCustomObject]#{
Name = 'First'
Description = 'First Description'
}
$obj1 | Add-Member -Name 'Method' -Type ScriptMethod -Value {FirstMethod 1}
$obj2 = [PSCustomObject]#{
Name = 'Second'
Description = 'Second Description'
}
$obj3 = [PSCustomObject]#{
Name = 'Third'
Description = 'Third Description'
}
$obj3 | Add-Member -Name 'Method' -Type ScriptMethod -Value {ThirdMethod}
$all = $obj1, $obj2, $obj3
If anyone is struggling with this one here's the answer:
The methods FirstMethod and ThirdMethod should be declared before the array
and then i needed to add the function inside (), and not {}.
Function FirstMethod
{
param($number)
Write-Host "$number - some other things"
return $number
}
Function ThirdMethod
{
Write-Host "Second called"
return 'test'
}
$all = #(
#{ Name = 'First'; Method = ( FirstMethod 1 ); Description = "First Description"; }
#{ Name = 'Second'; Description = "Second Description" }
#{ Name = 'Third'; Method = ( ThirdMethod ); Description = "Third Description" }
)
And it works fine now!
Curious about how to loop through a hash table where each value is an array. Example:
$test = #{
a = "a","1";
b = "b","2";
c = "c","3";
}
Then I would like to do something like:
foreach ($T in $test) {
write-output $T
}
Expected result would be something like:
name value
a a
b b
c c
a 1
b 2
c 3
That's not what currently happens and my use case is to basically pass a hash of parameters to a function in a loop. My approach might be all wrong, but figured I would ask and see if anyone's tried to do this?
Edit**
A bit more clarification. What I'm basically trying to do is pass a lot of array values into a function and loop through those in the hash table prior to passing to a nested function. Example:
First something like:
$parameters = import-csv .\NewComputers.csv
Then something like
$parameters | New-LabVM
Lab VM Code below:
function New-LabVM
{
[CmdletBinding()]
Param (
# Param1 help description
[Parameter(Mandatory=$true,
Position=0,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[Alias("p1")]
[string[]]$ServerName,
# Param2 help description
[Parameter(Position = 1)]
[int[]]$RAM = 2GB,
# Param3 help description
[Parameter(Position=2)]
[int[]]$ServerHardDriveSize = 40gb,
# Parameter help description
[Parameter(Position=3)]
[int[]]$VMRootPath = "D:\VirtualMachines",
[Parameter(Position=4)]
[int[]]$NetworkSwitch = "VM Switch 1",
[Parameter(Position=4)]
[int[]]$ISO = "D:\ISO\Win2k12.ISO"
)
process
{
New-Item -Path $VMRootPath\$ServerName -ItemType Directory
$Arguments = #{
Name = $ServerName;
MemoryStartupBytes = $RAM;
NewVHDPath = "$VMRootPath\$ServerName\$ServerName.vhdx";
NewVHDSizeBytes = $ServerHardDriveSize
SwitchName = $NetworkSwitch;}
foreach ($Argument in $Arguments){
# Create Virtual Machines
New-VM #Arguments
# Configure Virtual Machines
Set-VMDvdDrive -VMName $ServerName -Path $ISO
Start-VM $ServerName
}
# Create Virtual Machines
New-VM #Arguments
}
}
What you're looking for is parameter splatting.
The most robust way to do that is via hashtables, so you must convert the custom-object instances output by Import-Csv to hashtables:
Import-Csv .\NewComputers.csv | ForEach-Object {
# Convert the custom object at hand to a hashtable.
$htParams = #{}
$_.psobject.properties | ForEach-Object { $htParams[$_.Name] = $_.Value }
# Pass the hashtable via splatting (#) to the target function.
New-LabVM #htParams
}
Note that since parameter binding via splatting is key-based (the hashtable keys are matched against the parameter names), it is fine to use a regular hashtable with its unpredictable key ordering (no need for an ordered hashtable ([ordered] #{ ... }) in this case).
Try this:
for($i=0;$i -lt $test.Count; $i++)
{$test.keys | %{write-host $test.$_[$i]}}
Weirdly, it outputs everything in the wrong order (because $test.keys outputs it backwards).
EDIT: Here's your solution.
Using the [System.Collections.Specialized.OrderedDictionary] type, you guarantee that the output will come out the same order as you entered it.
$test = [ordered] #{
a = "a","1";
b = "b","2";
c = "c","3";
}
After running the same solution code as before, you get exactly the output you wanted.
teaching myself about functions - I have written the below and problem I have at the moment is this:
1.The output is displayed in a hash table like format - ie #{FileVersion=6.1.7601.18606; IsReadOnly?=False; Directory=C:\windows\system32}. Is there a way of not displaying it in this format?
2.For the IF statment how do I get the code to just look at the ProductVersion bit of the output and not the whole function...or is that the point of a function, should I just have a function that just gets the file version separatly?
clear
function fileversion {
param ([string]$fileToCheck)
$fileInput = Get-Item $fileToCheck
$versionCheck = $fileInput.VersionInfo.ProductVersion
$DirectoryOfFile = $fileInput.DirectoryName
$IsReadOnly = $fileInput.IsReadOnly
$obj = New-Object psobject
$obj | Add-Member NoteProperty FileVersion $versionCheck
$obj | Add-Member NoteProperty IsReadOnly? $IsReadOnly
$obj | Add-Member NoteProperty Directory $DirectoryOfFile
Write-host $obj
}
$firstFile = fileversion C:\windows\system32\lsasrv.dll
If ($versionCheck -eq '6.1.7601.18606')
{ Write-host "File for is $TRUE" }
Else
{ Write-Host $False }
Don't know why you need a function since in the end you are just using one property of the object returned. Still, if you need the function you can just simplify it.
function fileversion{
param ([string]$fileToCheck)
Get-Item $fileToCheck | Select-Object #{Label="FileVersion";Expression={$_.VersionInfo.ProductVersion}},
#{Label="IsReadOnly?";Expression={$_.IsReadOnly}},
#{Label="Directory";Expression={$_.DirectoryName}}
}
No need to create a new object when the current one already has what you need. We use calculated properties to create the property names you wanted.
By default all output from functions is returned to the output stream. By sending the $obj to Write-Host you were removing that data from the stream. The output you say was Write-host casting the entire object as a [string]
Simple If
You could have just done this as well depending on your needs. This way you dont need a custom function
$version = (Get-Item C:\windows\system32\lsasrv.dll).VersionInfo.ProductVersion
If($version -eq '6.1.7601.18606'){
write-host "Version match"
} Else {
write-host "$version does not match"
}
You could always change the file path to a variable. Again, this was just suggestion. Please do whatever makes your scripting life comfortable.
use Write-output instead of write-host and check the version using the right property name (FileVersion) on the returned object:
If ($firstFile.FileVersion -eq '6.1.7601.18606')
{ Write-host "File for is $TRUE" }
Else
{ Write-Host $False }
** Revised **
1.) 'IF' condition statement should be applied to the property before $obj is created.
2.) To make the function more flexible and reusable, you should expand on the parameter criteria to allow for values from pipeline and and array of values as input.
function fileversion {
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True)]
[Alias('files')]
[string[]]$filesToCheck
)
$fileInput = Get-Item $filesToCheck
foreach($f in $fileInput) {
$properties = #{
'File'=Split-Path $f -Leaf;
'FileVersion'=$f.VersionInfo.ProductVersion;
'CorrectVersion'=IF($versionCheck -eq '6.1.7601.18606') {$TRUE } ELSE {$False };
'IsReadyOnly'=$f.IsReadOnly;
'DirectoryOfFile'=$f.DirectoryName
}
$obj = New-Object psobject -Property $properties
Write-Output $obj
}
}
I'm trying to find a way to get all parameter information from a powershell script. Ex script:
function test()
{
Param(
[string]$foo,
[string]$bar,
[string]$baz = "baz"
)
foreach ($key in $MyInvocation.BoundParameters.keys)
{
write-host "Parameter: $($key) -> $($MyInvocation.BoundParameters[$key])"
}
}
test -foo "foo!"
I'd like to get the values of $bar and $baz in a dynamic way without knowing the names of the parameters ahead of time.
I've looked through $MyInvocation properties and methods but I don't see anything besides parameters that are set/passed.
Update 1:
I'm close to getting it with:
function test()
{
Param(
[string]$foo,
[string]$bar,
[string]$baz = "baz"
)
foreach($var in (get-variable -scope private))
{
write-host "$($var.name) -> $($var.value)"
}
}
test -foo "foo!"
If i could filter out the script parameters vs the default parameters I would be good to go.
Update 2:
The final working solution looks like this:
function test {
param (
[string] $Bar = 'test'
, [string] $Baz
, [string] $Asdf
)
$ParameterList = (Get-Command -Name $MyInvocation.InvocationName).Parameters;
foreach ($key in $ParameterList.keys)
{
$var = Get-Variable -Name $key -ErrorAction SilentlyContinue;
if($var)
{
write-host "$($var.name) > $($var.value)"
}
}
}
test -asdf blah;
Check this solution out. This uses the CmdletBinding() attribute, which provides some additional metadata through the use of the $PSCmdlet built-in variable. You can:
Dynamically retrieve the command's name, using $PSCmdlet
Get a list of the parameter for the command, using Get-Command
Examine the value of each parameter, using the Get-Variable cmdlet
Code:
function test {
[CmdletBinding()]
param (
[string] $Bar = 'test'
, [string] $Baz
, [string] $Asdf
)
# Get the command name
$CommandName = $PSCmdlet.MyInvocation.InvocationName;
# Get the list of parameters for the command
$ParameterList = (Get-Command -Name $CommandName).Parameters;
# Grab each parameter value, using Get-Variable
foreach ($Parameter in $ParameterList) {
Get-Variable -Name $Parameter.Values.Name -ErrorAction SilentlyContinue;
#Get-Variable -Name $ParameterList;
}
}
test -asdf blah;
Output
The output from the command looks like this:
Name Value
---- -----
Bar test
Baz
Asdf blah
To read the value dynamically use the get-variable function / cmdlet
write-host (get-variable "foo")
To print out all of the parameters do the following
foreach ($key in $MyInvocation.BoundParameters.keys)
{
$value = (get-variable $key).Value
write-host "$key -> $value"
}
Hopefully, some may find this one-liner useful:
function test()
{
Param(
[string]$foo,
[string]$bar,
[string]$baz = "baz"
)
$MyInvocation.MyCommand.Parameters | Format-Table -AutoSize #{ Label = "Key"; Expression={$_.Key}; }, #{ Label = "Value"; Expression={(Get-Variable -Name $_.Key -EA SilentlyContinue).Value}; }
}
test -foo "foo!"
Result
Keys Value
---- -----
foo foo!
bar
baz baz
I found this most useful for PS4 (Windows 2012 R2) - it includes default values / optional parameters:
$cmdName = $MyInvocation.InvocationName
$paramList = (Get-Command -Name $cmdName).Parameters
foreach ( $key in $paramList.Keys ) {
$value = (Get-Variable $key -ErrorAction SilentlyContinue).Value
if ( $value -or $value -eq 0 ) {
Write-Host "$key -> $value"
}
}
For those of you who do not want to use cmdletbinding() here's a variation on the one liner I found above:
(Get-Command -Name $PSCommandPath).Parameters | Format-Table -AutoSize #{ Label = "Key"; Expression={$_.Key}; }, #{ Label = "Value"; Expression={(Get-Variable -Name $_.Key -EA SilentlyContinue).Value}; }
$PSCommandPath is always available
I played with the 2 solutions i liked in this thread, they both work.
however I needed to produce an error out on missing parameter for a build script
$cmdName = $MyInvocation.InvocationName
$paramList = (Get-Command -Name $cmdName).Parameters
foreach ( $key in $paramList.Keys ) {
$value = (Get-Variable $key -ErrorAction Stop)
#Write-Host $value.Value #remove comment for error checking
if ([string]::IsNullOrEmpty($value.Value)){
$(throw ("$key is a mandatory value please declare with -$key <Required value> " ))
}
}
What if I don't know what arguments or how many will be passed? For example, the function could be called with:
test -foo "value1" -bar "value2" -baz "value3"
and someone else might call it with:
test -variable1 "somevalue" -variable2 "somevalue2" -variable3 "somevalue3" -variable4 "value4"
I looked at $MyInvocation and the arguments come across as UnboundArguments, so theoretically I could "pair up" argument 0 with argument 1, 2 with 3, etc and error out if there's an odd number of UnboundArguments.
Stumbled upon this trying to do something similar and figured out my preferred option.
Function ParamTest {
Param (
$t1 = '1234',
$t2,
[switch]$3
)
$MyInvocation |Add-Member -Name:'Param' -MemberType:'NoteProperty' -Value:(
(Get-Variable -Scope:'Local' -Include:#($MyInvocation.MyCommand.Parameters.keys)|
ForEach-Object -begin:{$h=#{}} -process:{$h.add($_.Name,$_.Value)} -end:{$h}
))
$MyInvocation.Param
}
Result
Name Value
---- -----
t1 1234
3 False
t2
PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.1320
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.1320
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
A streamlined solution that:
builds on your own approach now shown at the bottom of the question,
while also including an additional piece of information, namely whether each parameter was bound on invocation, i.e. whether an argument was passed or not, based on its presence in the automatic $PSBoundParameter variable, which is a dictionary containing the bound parameters and their values (arguments).
Note: $PSBoundParameters does not include parameters bound by a default value, only those parameters to which an argument was explicitly passed; for your use case, that is arguably desirable in order to distinguish between a default value and an explicit one, but in scenarios where arguments should be passed through it may be desirable to have default-value parameters included - see GitHub issue #3285.
function test {
param (
[string]$foo,
[string]$bar,
[string]$baz = "baz"
)
foreach ($paramName in $MyInvocation.MyCommand.Parameters.Keys) {
$bound = $PSBoundParameters.ContainsKey($paramName)
[pscustomobject] #{
ParameterName = $paramName
ParameterValue = if ($bound) { $PSBoundParameters[$paramName] }
else { Get-Variable -Scope Local -ErrorAction Ignore -ValueOnly $paramName }
Bound = $bound
}
}
}
test -foo "foo!"
The above yields the following:
ParameterName ParameterValue Bound
------------- -------------- -----
foo foo! True
bar False
baz baz False
Note: This solution also handles dynamic parameters correctly:
Such parameters are reflected in $MyInvocation.MyCommand.Parameters if they situationally apply, but - unlike regular static parameters - are never reflected in scope-local variables. If they apply and are also bound, they and their values are reflected in $PSBoundParameters.
Thus - given that an applicable dynamic parameter may not be bound - the Get-Variable call to look for scope-local variables representing static parameters:
Must explicitly be limited to the current scope with -Scope Local so as not to accidentally pick up unrelated variables of the same name from ancestral scopes for unbound dynamic parameters.
Must ignore errors from the potentially resulting failure to find a variable in the current scope, using -ErrorAction Ignore.
I wanted a compact string of parameter key/value pairs that I can write out when catching error. Use content of the other answers, I came up with this:
$parameters = (Get-Variable -Scope:'Local' -Include:#($MyInvocation.MyCommand.Parameters.keys) |
Select-Object Name, Value | ForEach-Object { "$($_.Name) : $($_.Value)" }) -join ' | '
Sample output:
ComputerName : SomePC | Directory : C:\Tools\LogExpert | UserName : Hans Wurst | YesOrNo : False
Thanks to all other posters with great & helpful answers above!
I'm cobbling together some of the above posts to try to meet my requirements.
I'd like to show Params in a Powershell-language-compatible format, so that one could easily see & display these params, and then also copy+pasta back into either a script as Param() Defaults (ParamsFormat1) or into a commandline/function call (CommandFormat2). I struggled with this for a while, so I hope this saves someone some time.
Collection of various Scripts from above:
# Note: there are some subtle differences between these versions below
# Specifically in the first line for *which* object you're checking for Parameters, and subsequently what type of Parameters you're looking at.
# PSCmdlet version REQUIRES [CmdletBinding()] on your function!!!
# $($(Get-Command -Name $($PSCmdlet.MyInvocation.InvocationName)).Parameters) | `
# %{ Get-Variable -Name $_.Values.Name -ErrorAction SilentlyContinue; }
# -Scope:'Local' FILTERS out any global params
# (Get-Variable -Scope:'Local' -Include:#($MyInvocation.MyCommand.Parameters.keys)) | ft
# PSCommandPath supposedly available/usable "in all situations" - so this may be the most useful of all of them, BUT it shows global params [Debug, ErrorAction, etc...]
# (Get-Command -Name $PSCommandPath).Parameters | `
# %{ Get-Variable -Name $_.Values.Name -ErrorAction SilentlyContinue; }
ParamsFormat1 / HYBRID VERSION: To output "Default Params" as you would see them in a function definition. Combines the -Scope:"Local" and "always available" versions to get BOTH param TYPES as well as Name, Value
Write-Host "Params("
# TBD Figure out how to expand #{} of System.Collections.Hashtable
# HYBRID VERSION: Combine the -Scope:"Local" and "always available" versions to get BOTH param TYPES as well as Name, Value
# If you remove LocalList Filter here, it will also show "Global" function properties like Debug, ErrorAction, etc...
$LocalList = $(Get-Variable -Scope:'Local' -Include:#($MyInvocation.MyCommand.Parameters.keys) | Select-Object -ExpandProperty Name) -join "|"
# VERSION: Wrapper script with DEFAULTS : normally DOES include Global vars [Debug, ErrorAction, etc]. but DOES preserve param order as-written.
((Get-Command -Name $PSCommandPath).Parameters | `
Select -ExpandProperty Values | `
Where-Object { $_.Name -Match $LocalList } | `
Format-Table -HideTableHeaders -AutoSize `
#{ Label="Type"; Expression={"[$($_.ParameterType )]"}; }, `
#{ Label="Name"; Expression={"`t`$$($_.Name)"}; }, `
#{ Label="Equals"; Expression={"="}; }, `
#{ Label="Value"; Expression={ If( $_.ParameterType -Match "String" ) { "`"$((Get-Variable -Name $_.Name -EA SilentlyContinue).Value)`"" } Else{ $((Get-Variable -Name $_.Name -EA SilentlyContinue).Value)}; }; }, `
#{ Label="RowEndComma"; Expression={ "," }; }
##{ Label="Value"; Expression={ $((Get-Variable -Name $_.Name -EA SilentlyContinue).Value) }; } # (OPTIONAL) Values only, no wrapping quotes
)
Write-Host ")";
CommandFormat2 / SIMPLER VERSION: Call with CommandLine Args (TYPES not needed). This filters out Global vars, does NOT preserve param ordering. (sorted alphabetically?)
# VERSION: Call with CommandLine Args (TYPES not available - TBD needs more work to display String, Array, and Hashmap/PsCustomObject ["", #() and {}] types better): filters out Global vars, does NOT preserve param ordering.
# If needed, cut+paste OPTIONAL lines down above Format-Table line.
# Where-Object { $_.Value } | ` # (Optional) remove any Null items.
# Sort-Object -Property Name | ` # (Optional) sort output
(Get-Variable -Scope:'Local' -Include:#($MyInvocation.MyCommand.Parameters.keys) | `
Format-Table -HideTableHeaders -AutoSize `
#{ Label="Name"; Expression={"`t-$($_.Name)"}; }, `
#{ Label="Equals"; Expression ={":"}; }, `
#{ Label="Value"; Expression={ If( $_.ParameterType -NotMatch "String" ) { $_.Value; } Else {"`"$($_.Value)`"";} }; Alignment="left"; }
)