Calling functions with maps using # - powershell

I've come across some syntax that I cannot understand. Here is a sample
$someList = #( <# ... #> )
$name = "someString"
$myMap = #{
Name = $name
Foo = 15
}
Invoke-MyFoo #myMap #someList
What is the meaning #-signs in the Invoke-MyFoo expression? What does it do?

It's a technique known as splatting. It lets you pass a set of parameters as a hashtable or array instead of specifying them all with the cmdlet.
If you're asking a more basic question, then #( ) identifies an array, and #{ } identifies a hashtable.

Related

How do I reverse transversal in a PowerShell array

Given a PowerShell array hashtable1 similar to the following:
$dept= #{
'Sales' = #{
'SAM' = 'Manager'
'SAP' = 'Person'
}
'IT' = #{
'ITM' = 'Manager'
'ITS' = 'Specialist'
'ITT' = 'Technician'
'ITC' = 'Consultant'
}
}
If enter the following in the console:
$dept.it.itc
$dept.sales.sam
I get:
Consultant
Manager
Which is as expected.
However, what I'd like to do is something like
write-host $dept.itc
write-host $dept.sam
and get
IT Consultant
Sales Manager
in return.
I'm looking for a sort function to do a 'reverse traversal' of the array because 'IT', 'Sales' etc are the OU's I need to put new users into. There are many more OU's that I have removed for brevity.
[1] An array is simply a list of values and a hashtable is a collection of key/value pairs similiar to Javascript's JSON or Python's dict.
It is worth noting that your object is not an Array. In PowerShell #{} is a Hashtable. You can read more about working with Hashtables here.
If you have what I am going to call a unique Role Code for each role in your department OU's, all you want to do is match the Key in the nested Hashtables to find your department. It's easiest to create a quick helper function to deal with multiple calls, unless you are just looping through an array or list of strings.
Here is an example of how to extract the string you want: (If you do not have unique keys, then you may need to add additional filtering)
$Departments = #{
'Sales' = #{
'SAM' = 'Manager'
'SAP' = 'Person'
}
'IT' = #{
'ITM' = 'Manager'
'ITS' = 'Specialist'
'ITT' = 'Technician'
'ITC' = 'Consultant'
}
}
function Get-DepartmentOU {
Param (
[CmdletBinding()]
[Parameter(Mandatory = $true)]
[System.String]
$RoleCode
)
# Get the DictionaryEntry in the main Hashtable where the nested Hashtable value matches the role you are looking for.
$Department = $script:Departments.GetEnumerator() | Where-Object { $_.Value.ContainsKey($RoleCode) }
# Print the name of the DictionaryEntry (Your department) and retrieve the value from the Hashtable for the role.
Write-Output ("{0} {1}" -f $Department.Name, $Department.Value[$RoleCode])
}
And then you can get them by running the function and specifying the code.
PS > Get-DepartmentOU -RoleCode ITC
IT Consultant

What is '#{}' meaning in PowerShell

I have line of scripts for review here, I noticed variable declaration with a value:
function readConfig {
Param([string]$fileName)
$config = #{}
Get-Content $fileName | Where-Object {
$_ -like '*=*'
} | ForEach-Object {
$key, $value = $_ -split '\s*=\s*', 2
$config[$key] = $value
}
return $config
}
I wonder what #{} means in $config = #{}?
#{} in PowerShell defines a hashtable, a data structure for mapping unique keys to values (in other languages this data structure is called "dictionary" or "associative array").
#{} on its own defines an empty hashtable, that can then be filled with values, e.g. like this:
$h = #{}
$h['a'] = 'foo'
$h['b'] = 'bar'
Hashtables can also be defined with their content already present:
$h = #{
'a' = 'foo'
'b' = 'bar'
}
Note, however, that when you see similar notation in PowerShell output, e.g. like this:
abc: 23
def: #{"a"="foo";"b"="bar"}
that is usually not a hashtable, but the string representation of a custom object.
The meaning of the #{}
can be seen in diffrent ways.
If the #{} is empty, an empty hash table is defined.
But if there is something between the curly brackets it can be used in a contex of an splatting operation.
Hash Table
Splatting
I think there is no need in explaining what an hash table is.
Splatting is a method of passing a collection of parameter values to a command as unit.
$prints = #{
Name = "John Doe"
Age = 18
Haircolor = "Red"
}
Write-Host #prints
Hope it helps! BR
Edit:
Regarding the updated code from the questioner the answer is
It defines an empty hash table.
Be aware that Get-Content has its own parameters!
THE MOST IMPORTANT 1:
[-Raw]

Array of hash tables not output

This is a basic question but I'm stuck. I have the below code:
$array = #(
$hashtable1 = #{
Name = "Test1"
Path = "C:\Test1"
}
$hashtable2 = #{
Name = "Test1"
Path = "C:\Test1"
}
)
The array is created but empty. I have tried comma separation:
$hashtable1 = #{}, $hashtable2 = #{}
But this did not work. What is wrong?
You are assigning the hashtables as variables. Take out the variable assignment:
$array = #(
#{
Name = "Test1"
Path = "C:\Test1"
},
#{
Name = "Test1"
Path = "C:\Test1"
}
)
gms0ulman's helpful answer provides an effective solution for constructing your array of hashtables.
To provide some background information:
A variable assignment such as $hashtable1 = ... is not an expression, so it produces no output, which is why your $array = assignment ended up containing an empty array, given that #(...) saw no output.
However, you can make assignment statements produce output simply by enclosing them in (...), which turns them into expressions, which allows you to assign to the variable and output the assigned value.
#(...) is not needed to construct arrays; instead, you can use ,, the array-construction operator.
Even though it may not be needed, the following demonstrates how to both construct the array of hashtables and save the individual hashtables in dedicated variables:
$array =
($hashtable1 = #{
Name = "Test1"
Path = "C:\Test1"
}),
($hashtable2 = #{
Name = "Test1"
Path = "C:\Test1"
})

Check if a string is not NULL or EMPTY

In below code, I need to check if version string is not empty then append its value to the request variable.
if ([string]::IsNullOrEmpty($version))
{
$request += "/" + $version
}
How to check not in if condition?
if (-not ([string]::IsNullOrEmpty($version)))
{
$request += "/" + $version
}
You can also use ! as an alternative to -not.
You don't necessarily have to use the [string]:: prefix. This works in the same way:
if ($version)
{
$request += "/" + $version
}
A variable that is null or empty string evaluates to false.
As in many other programming and scripting languages you can do so by adding ! in front of the condition
if (![string]::IsNullOrEmpty($version))
{
$request += "/" + $version
}
If the variable is a parameter then you could use advanced function parameter binding like below to validate not null or empty:
[CmdletBinding()]
Param (
[parameter(mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$Version
)
if (!$variablename)
{
Write-Host "variable is null"
}
I hope this simple answer will resolve the question.
Source
I would define $Version as a string to start with
[string]$Version
and if it's a param you can use the code posted by Samselvaprabu
or if you would rather not present your users with an error you can do something like
while (-not($version)){
$version = Read-Host "Enter the version ya fool!"
}
$request += "/" + $version
You can use the [string]::IsNullOrEmpty($version) method if it is a string.
But, I was looking for a universal way to check nulls (regardless of data type)
in Powershell. Checking for null (or not null) values in
PowerShell is tricky. Using ($value -eq $null) or ($value -ne
$null) does not always work. Neither does if($value). Using them
can even cause problems later on.
Just read this Microsoft article below (IN IT'S ENTIRETY) to get a grasp
of how tricky nulls can be in Powershell.
[https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-null?view=powershell-7.1][1]
I wrote these two functions below for checking for null (or not null) values
in PowerShell. I "believe" they should work for any and all values
and data types.
I hope someone finds them helpful.
I am not sure why MS hasn't put something like this into PowerShell natively to
make handling nulls easier (and less dangerous) in PowerShell.
I hope this helps someone.
If anyone knows of an unseen "pitfall" or problem with this method,
please post a comment here so we can know that.
Thanks!
<#
*********************
FUNCTION: ValueIsNull
*********************
Use this function ValueIsNull below for checking for null values
rather using -eq $null or if($value) methods. Those may not work as expected.
See reference below for more details on $null values in PowerShell.
[https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-null?view=powershell-7.1][1]
An if statement with a call to ValueIsNull can be written like this:
if (ValueIsNull($TheValue))
#>
function ValueIsNull {
param($valueToCheck)
# In Powershell when a parameter of a function does not have a data type defined,
# it will create the parameter as a PSObject. It will do this for
# an object, an array, and a base date type (int, string, DateTime, etc.)
# However if the value passed in is $null, then it will still be $null.
# So, using a function to check null gives us the ability to determine if the parameter
# is null or not by checking if the parameter is a PSObject or not.
# This function could be written more efficiently, but intentionally
# putting it in a more readable format.
# Special Note: This cannot tell the difference between a parameter
# that is a true $null and an undeclared variable passed in as the parameter.
# ie - If you type the variable name wrong and pass that in to this function it will see it as a null.
[bool]$returnValue = $True
[bool]$isItAnObject=$True
[string]$ObjectToString = ""
try { $ObjectToString = $valueToCheck.PSObject.ToString() } catch { $isItAnObject = $false }
if ($isItAnObject)
{
$returnValue=$False
}
return $returnValue
}
<#
************************
FUNCTION: ValueIsNotNull
************************
Use this function ValueIsNotNull below for checking values for
being "not-null" rather than using -ne $null or if($value) methods.
Both may not work as expected.
See notes on ValueIsNull function above for more info.
ValueIsNotNull just calls the ValueIsNull function and then reverses
the boolean result. However, having ValueIsNotNull available allows
you to avoid having to use -eq and\or -ne against ValueIsNull results.
You can disregard this function and just use !ValueIsNull($value).
But, it is my preference to have both for easier readability of code.
An if statement with a call to ValueIsNotNull can be written like this:
if (ValueIsNotNull($TheValue))
#>
function ValueIsNotNull {
param($valueToCheck)
[bool]$returnValue = !(ValueIsNull($valueToCheck))
return $returnValue
}
You can use the following list of calls to ValueIsNull to test it out.
$psObject = New-Object PSObject
Add-Member -InputObject $psObject -MemberType NoteProperty -Name customproperty -Value "TestObject"
$valIsNull = ValueIsNull($psObject)
$props = #{
Property1 = 'one'
Property2 = 'two'
Property3 = 'three'
}
$otherPSobject = new-object psobject -Property $props
$valIsNull = ValueIsNull($otherPSobject)
# Now null the object
$otherPSobject = $null
$valIsNull = ValueIsNull($otherPSobject)
# Now an explicit null
$testNullValue = $null
$valIsNull = ValueIsNull($testNullValue)
# Now a variable that is not defined (maybe a type error in variable name)
# This will return a true because the function can't tell the difference
# between a null and an undeclared variable.
$valIsNull = ValueIsNull($valueNotDefine)
[int32]$intValueTyped = 25
$valIsNull = ValueIsNull($intValueTyped)
$intValueLoose = 67
$valIsNull = ValueIsNull($intValueLoose)
$arrayOfIntLooseType = 4,2,6,9,1
$valIsNull = ValueIsNull($arrayOfIntLooseType)
[int32[]]$arrayOfIntStrongType = 1500,2230,3350,4000
$valIsNull = ValueIsNull($arrayOfIntStrongType)
#Now take the same int array variable and null it.
$arrayOfIntStrongType = $null
$valIsNull = ValueIsNull($arrayOfIntStrongType)
$stringValueLoose = "String Loose Type"
$valIsNull = ValueIsNull($stringValueLoose)
[string]$stringValueStrong = "String Strong Type"
$valIsNull = ValueIsNull($stringValueStrong)
$dateTimeArrayLooseValue = #("1/1/2017", "2/1/2017", "3/1/2017").ForEach([datetime])
$valIsNull = ValueIsNull($dateTimeArrayLooseValue)
# Note that this has a $null in the array values. Still returns false correctly.
$stringArrayLooseWithNull = #("String1", "String2", $null, "String3")
$valIsNull = ValueIsNull($stringArrayLooseWithNull)

Splatting after passing hashtable by reference in Powershell

I ran into a snag when I passed a hash table by reference to a function for splatting purposes. How can I fix this?
Function AllMyChildren {
param (
[ref]$ReferenceToHash
}
get-childitem #ReferenceToHash.Value
# etc.etc.
}
$MyHash = #{
'path' = '*'
'include' = '*.ps1'
'name' = $null
}
AllMyChildren ([ref]$MyHash)
Result: an error ("Splatted variables cannot be used as part of a property or array expression. Assign the result of the expression to a temporary variable then splat the temporary variable instead.").
Tried to do this:
$newVariable = $ReferenceToHash.Value
get-childitem #NewVariable
That did work and seemed right per the error message. Is it the preferred syntax in a case like this?
1) Passing hashtables (or any instances of classes, i.e. reference types) with [ref] makes no sense because they are always passed by reference themselves. [ref] is used with value types (scalars and instances of structures).
2) The splatting operator can be applied to a variable directly, not an expression.
Thus, in order to resolve the problem simply pass the hashtable in the function as it is:
Function AllMyChildren {
param (
[hashtable]$ReferenceToHash # it is a reference itself
)
get-childitem #ReferenceToHash
# etc.etc.
}
$MyHash = #{
'path' = '*'
'include' = '*.ps1'
'name' = $null
}
AllMyChildren $MyHash