简体   繁体   中英

PowerShell 5.1 Can someone please explain hashtable and splatting

Given:
PowerShell 5.1

I'm having a little trouble understanding hashtable and splatting. When splatting are use using a hash table to do that or is it something completely different?

I have the following code:

$hashtable1 = @{}       
$hashtable1.add('PROD',@{ FirstName = 'John'; LastName = 'Smith'})

function Main() {
    $sel = $hashtable1['PROD']
    
    Function1 $sel    
    Function2 @sel
}

function Function1([hashtable] $x) {
    "Value: $($x.LastName)"
    $x.FirstName
}

function Function2([string] $firstName) {
    "Value: $($firstName)"
}

Main

在此处输入图像描述

Splatting and hashtables are related concepts in PowerShell, but they are not the same thing.

A hashtable is a data structure in PowerShell that allows you to store key-value pairs. You can think of it like a dictionary or an associative array in other programming languages. You can create a hashtable using the @{} notation and then add key-value pairs using the = operator, like so:

$hashtable = @{
    "Key1" = "Value1"
    "Key2" = "Value2"
}

Splatting, on the other hand, is a technique that allows you to pass a collection of parameter values to a command or function using the @ symbol. When you use the @ symbol in front of a variable that contains a hashtable, PowerShell will automatically expand the hashtable into its individual key-value pairs and pass them as separate arguments to the command or function.

For example, you could use splatting to call a function and pass the values from a hashtable as arguments:

function MyFunction([string]$Name, [int]$Age) {
    Write-Host "Name: $Name"
    Write-Host "Age: $Age"
}

$parameters = @{
    "Name" = "John"
    "Age" = 30
}

MyFunction @parameters

This will call the MyFunction function, passing the values "John" and 30 as the Name and Age arguments, respectively.

@postanote has some very good links about hashtables and splatting and are good reads. Taking your examples, you have two different functions. One to handle hashtables as a parameter, and the second one that can only handle a single string parameter. The hashtable cannot be used to pass parameters to the second function, eg:

PS C:\> Function2 $sel
Value: System.Collections.Hashtable

Conceptually, the real difference between using hashtables and splatting is not about how you are using them to pass information and parameters to functions, but how the functions and their parameters receive the information .

Yes, certain functions can have hashtables and arrays as parameters, but, typically in 98% of the cases, functions don't use hashtables as a named parameter to get its values.

For ex. Copy-Item doesn't use hash tables as a parameter. If it did, would you want to do this every time you want to copy anything:

$hashtable = @{
  Path = "C:\Temp\myfile.txt",
  Destination = "C:\New Folder\"
}
Copy-Item -Parameters $hashtable

No, instead, you want the parameters as strings, so you can make it a much easier one liner:

Copy-Item -Path "C:\Temp\myfile.txt" -Destination "C:\New Folder\"

It makes more sense to most people to deal with individual strings as opposed to a generic, large, hashtable "config" to pass. Also, by separating the parameters as separate strings, integers, floats, chars, etc. it is also easier to do validation, default values, mandatory/not mandatory parameters, etc.

Now despite saying all that, there is a situation where you have certain functions with lots of parameters (eg sending an email message), or you want to do something multiple times (eg copying/moving lots of files from a CSV file). In that case, using a hashtable, and/or arrays, and/or arrays of hashtables, would be useful.

This is where splating comes in. It takes a hashtable and instead of treating it like you are passing a single value (ie why Function2 $sel returns System.Collections.Hashtable ), the @ signt tells PowerShell that it is a collection of values, and to use the collection to try and match to the parameters of the function. That's why passing the hashtable to Function2 doesn't work, but splatting works eg:

PS C:\> Function2 @sel
Value: John

In this case, it takes the hashtable $sel and by using splatting @sel PowerShell now knows to not pass the hashtable as-is, but to open up the collection and to matche the $sel.FirstName to the -Firstname parameter.

There's good information in the existing answer, but let me attempt a focused summary:

The answer to your actual question is:

  • Yes, @{ FirstName = 'John'; LastName = 'Smith' } @{ FirstName = 'John'; LastName = 'Smith' } is a hashtable too, namely in the form of a declarative hashtable literal - just like @{} is an empty hashtable literal (it constructs an instance that initially has no entries).

    • A hashtable literal consists of zero or more key-value pairs, with = separating each key from its value, and pairs being separated with ; or newlines.
    • Keys usually do not require quoting (eg FirstName ), except if they contain special characters such as spaces or if they're provided via an expression , such as a variable reference; see this answer for details.
  • This contrasts with adding entries to a hashtable later , programmatically , as your $hashtable1.Add('PROD', ...) method call exemplifies (where PROD is the entry key , and ... is a placeholder for the entry value ).

    • Note that a more convenient a lternative to using the .Add() method is to use an index expression or even dot notation (property-like access), though note that it situationally either adds an entry or updates an existing one : $hashtable1['PROD'] =... or $hashtable1.PROD =...

The answer to the broader question implied by your question's title :

  • PowerShell's hashtables are a kind of data structure often called a dictionary or, in other languages, associative array or map . Specifically, they are case-insensitive instances of the .NET [hashtable] ( System.Collections.Hashtable ) type, which is a collection of unordered key-value pair entries . Hashtables enable efficient lookup of values by their associated keys.

    • Via syntactic sugar [ordered] @{... } , ie by placing [ordered] before a hashtable literal, PowerShell offers a case-insensitive ordered dictionary that maintains the entry-definition order and allows access by positional index in addition to the usual key-based access. Such ordered hashtables are case-insensitive instances of the .NET System.Collections.Specialized.OrderedDictionary type.

      • A quick example:

         # Create an ordered hashtable (omit [ordered] for an unordered one). $dict = [ordered] @{ foo = 1; bar = 'two' } # All of the following return 'two' $dict['bar'] # key-based access $dict.bar # ditto, with dot notation (property-like access) $dict[1] # index-based access; the 2nd entry's value.
  • Splatting is an argument-passing technique that enables passing arguments indirectly , via a variable containing a data structure encoding the arguments, which is useful for dynamically constructing arguments and making calls with many arguments more readable.

    • Typically and robustly - but only when calling PowerShell commands with declared parameters - that data structure is a hashtable , whose entry keys must match the names of the target command's parameters (eg, key Path targets parameter -Path ) and whose entry values specify the value to pass.

      • In other words: This form of splatting uses a hashtable to implement passing named arguments (parameter values preceded by the name of the target parameter, such as -Path /foo in direct argument passing).

      • A quick example:

         # Define the hashtable of arguments (parameter name-value pairs) # Note that File = $true is equivalent to the -File switch. $argsHash = @{ LiteralPath = 'C:\Windows'; File = $true } # Note the use of "@" instead of "$"; equivalent to: # Get-ChildItem -LiteralPath 'C:\Windows' -File Get-ChildItem @argsHash
    • Alternatively, an array may be used for splatting, comprising parameter values only, which are then passed positionally to the target command.

      • In other words: This form of splatting uses an array to implement passing positional arguments (parameter values only ).

      • This form is typically only useful:

        • when calling PowerShell scripts or functions that do not formally declare parameters and access their - invariably positional - arguments via the automatic $args variable
        • when calling external programs ; note that from PowerShell's perspective there's no concept of named arguments when calling external programs, as PowerShell's knows nothing about the parameter syntax in that case, and all arguments are simply placed on the process command line one by one, and it is up to the target program to interpret them as parameter names vs. values.
      • A quick example:

         # Define an array of arguments (parameter values) $argsArray = 'foo', 'bar' # Note the use of "@" instead of "$", though due to calling an # *external program* here, you may use "$" as well; equivalent to: # cmd /c echo 'foo' 'bar' cmd /c echo @argsArray

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM