Tag Archives: GetType

Variables, and More About Note Properties

I have been thinking a lot about variables and note properties recently. You know that, if you read A Better Way to Solve the Same Problem. It sets the stage for what we are going to see today. The question that started that post was, whether or not I could add note properties to a single variable, such as PowerShell does with the $PROFILE variable. I could. I ended up creating a variable that held one URL when you returned the variable but also held four other URLs, one in each additional note property.

I want to take this further, and the best part is that all the things I was worried about trying to do myself, PowerShell just does for me without any thinking about it. Follow along and you will see.

Let’s set up the variable I was using last time to help this recap. Then we will create another variable and work with it to explore some new things I learned. Building this variable is being done a little differently than it was previously. It incorporates some concepts from another recent post, There is a Difference: Arrays Versus Hash Tables. First, we will assign our initial value to the variable.

$PSSites = 'https://docs.microsoft.com/en-us/powershell/scripting/overview'

Next, we will create a hash table that includes four key-value pairs. Each pair includes a website name and an associated URL, because as we learned in that post, a hash table is an associative array.

$Sites = @{
    GitHub  = 'https://github.com/PowerShell/PowerShell'
    Docs    = 'https://docs.microsoft.com/en-us/powershell/'
    Gallery = 'https://www.powershellgallery.com/'
    Reddit  = 'https://www.reddit.com/r/PowerShell/'
}

Following that, we will use the foreach statement to loop through the key-value pairs in the hash table, running Add-Member against each of them, and thusly adding each as a note property on our $PSSites variable.

foreach ($Site in $Sites.GetEnumerator()) {
    $PSSites = $PSSites | Add-Member -NotePropertyName $Site.Key -NotePropertyValue $Site.Value -PassThru
}

We can use Get-Member to ensure the previous command added the additional URLs as note properties.

$PSSites | Get-Member -MemberType NoteProperty

   TypeName: System.String

Name    MemberType   Definition
----    ----------   ----------
Docs    NoteProperty string Docs=https://docs.microsoft.com/en-us/powershell/
Gallery NoteProperty string Gallery=https://www.powershellgallery.com/
GitHub  NoteProperty string GitHub=https://github.com/PowerShell/PowerShell
Reddit  NoteProperty string Reddit=https://www.reddit.com/r/PowerShell/

At this point, we have our own variable like the $PROFILE variable that contains multiple string values. We can access the note properties of $PSSites using dot notation.

$PSSites.GitHub
$PSSites.docs
$PSSites.Gallery
$PSSites.Reddit

https://github.com/PowerShell/PowerShell
https://docs.microsoft.com/en-us/powershell/
https://www.powershellgallery.com/
https://www.reddit.com/r/PowerShell/

Now, let’s create another variable and add some members to it, as well. These will be a little different and you will see that momentarily. We will start by assigning a string value to the variable, as we did above.

$TestingVariable = 'A string value'
$TestingVariable
A string value

Before we add the rest, I suppose I should remind everyone about my end goal written at the bottom of the first post linked above: Save the previous value of a variable to a note property when assigning a new value to the variable itself.

This would be much easier if we could guarantee that every new value assigned to the variable was a string, and therefore, every old value property would also be a string. My worries, as mentioned earlier, were about arrays, hash tables, ordered dictionaries, and other data structures I may have to save to a note property. Can other data structures like those be put in a note property? Let’s work through these data structures and see if we can get them into note properties, to begin with. In this example, we will add two arrays to two separate note properties, as Array01 and Array02. One of these will and one will not use the array, sub-expression operator (@()).

$TestingVariable = $TestingVariable | Add-Member -NotePropertyName 'Array01' -NotePropertyValue 1,2,3 -PassThru
$TestingVariable = $TestingVariable | Add-Member -NotePropertyName 'Array02' -NotePropertyValue @(4,5,6) -PassThru

Here, we will create a hash table and store it in the $HashTable variable. We will then use that variable as a part of another Add-Member command.

$HashTable = @{Dad = 'David'; Mom = 'Betty'; Daughter = 'Janice'; Son = 'Bryan'}
$TestingVariable = $TestingVariable | Add-Member -NotePropertyName 'HashTable' -NotePropertyValue $HashTable -PassThru

Finally, we’ll create an ordered dictionary and add it as a note property, as well. If the hash table takes, then it is probably safe to assume this will take, too.

$OrderedDictionary = [ordered]@{
    Monday    = 'Chipotle'
    Tuesday   = 'Pizza'
    Wednesday = 'Mahi Mahi';
    Thursday  = 'Ravioli'
    Friday    = 'Orange Chicken'
}
$TestingVariable = $TestingVariable | Add-Member -NotePropertyName 'OrderedDictionary' -NotePropertyValue $OrderedDictionary -PassThru

At this point, we should probably see what Get-Member returns about the note properties we have assigned to our $TestingVariable. We have yet to test that anything has actually been added so far, although we have not received any errors stating otherwise. In the below example, we can see the four, note properties that we have added. The best part, the definition property indicates it knew the data structure of these when they were added as note properties. The arrays show object[], the hash table, hashtable, and the ordered dictionary, OrderedDictionary.

$TestingVariable | Get-Member -MemberType NoteProperty

   TypeName: System.String

Name               MemberType   Definition
----               ----------   ----------
Array01            NoteProperty Object[] Array01=System.Object[]
Array02            NoteProperty Object[] Array02=System.Object[]
HashTable          NoteProperty hashtable Hash Table=System.Collections.Hashtable
OrderedDictionary  NoteProperty OrderedDictionary Ordered Dictionary=System.Collections.Specialized.OrderedDictionary

Let’s take a closer look at each of our new note properties. For each of them, we will run GetType() against the note property and then return the value it has stored. When we return a note property that contains an array, it returns that. Same for the others; the data structure was recognized and retained when it was added as a member. And it is respected on the way out, too. I cannot tell you how grateful I am that I do not have to be the one to figure out the underlying data structure of a value going in and then coming back out. This is great news for some of the other things I have planned.

$TestingVariable.Array01.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

$TestingVariable.Array01
1
2
3

$TestingVariable.Array02.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

$TestingVariable.Array02
4
5
6

$TestingVariable.HashTable.GetType()       

IsPublic IsSerial Name                                     BaseType     
-------- -------- ----                                     --------     
True     True     Hashtable                                System.Object

$TestingVariable.HashTable

Name                           Value
----                           -----
Daughter                       Janice
Son                            Bryan
Dad                            David 
Mom                            Betty

$TestingVariable.OrderedDictionary.GetType()

IsPublic IsSerial Name                                     BaseType      
-------- -------- ----                                     --------      
True     True     OrderedDictionary                        System.Object 

$TestingVariable.OrderedDictionary

Name                           Value
----                           -----
Monday                         Chipotle
Tuesday                        Pizza
Wednesday                      Mahi Mahi
Thursday                       Ravioli
Friday                         Orange Chicken

There is a Difference: Arrays Versus Hash Tables

After reading a short post on the PowerShell subreddit recently, I was compelled to write a quick post here about arrays and hash tables. The concepts are similar, but the two are different, meaning that — interruption! There have now been two posts where the OP didn’t know one versus the other. It is basic stuff, sure, but it is important stuff.

Anyway, talking about one when you mean the other isn’t going to be okay any longer — it really never was. While someone mentioned the incorrect usage in the thread, writing, for me, still felt necessary and potentially beneficial.

Instead of writing my own definitions, let’s use Microsoft’s. We’ll begin with an array: “Data structures designed to store collections of items.“ If you think of a variable, back when you learned about those the first time, you probably learn how to store a single value in your variable. Okay good. This time we’re going to store multiple values in a single variable. That is what this data structure provides.

We are beginning with a simple variable that contains a simple, single value. Not much to it.

[PS7.2.0][C:\] $SingleValue = 'One thing'
[PS7.2.0][C:\] $SingleValue
One thing
[PS7.2.0][C:\] $SingleValue.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Now, let’s work with arrays. We’re still going to use a single variable, we’re just going to load it up with a different data structure that’s going to let us store multiple values in it. We actually don’t have to do much to make this happen, so here we go.

In this example, we’re creating a variable named $Array01. We’re storing the numeric values of 1, 2, and 3 inside the variable as an array.

[PS7.2.0][C:\] $Array01 = 1,2,3
[PS7.2.0][C:\] $Array01
1
2
3
[PS7.2.0][C:\] $Array01.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Well, that was easy. This next example is the same as above, however, it includes @() around our numeric values. This operator — the array sub-expression operator — takes whatever is inside it and makes it into an array.

[PS7.2.0][C:\] $Array02 = @(4,5,6)
[PS7.2.0][C:\] $Array02
4
5
6
[PS7.2.0][C:\] $Array02.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

The array sub-expression operator will even make an array of nothing.

[PS7.2.0][C:\] $Array03 = @()
[PS7.2.0][C:\] $Array03
[PS7.2.0][C:\] $Array03.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Here is one you probably do not see often. The comma in front of the 7 will indicate to PowerShell to create an array that contains a single value, which we will prove when we start returning the count of our various arrays.

[PS7.2.0][C:\] $Array04 = ,7
[PS7.2.0][C:\] $Array04
7
[PS7.2.0][C:\] $Array04.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

[PS7.2.0][C:\] $Array04.Count
1
[PS7.2.0][C:\] $Array03.Count
0
[PS7.2.0][C:\] $Array02.Count
3
[PS7.2.0][C:\] $Array01.Count
3

Do you get it? It is a data structure designed to accommodate multiple values. You did not see it here yet, but arrays can hold strings (words or sentences), just as easily as numbers. You can even mix them in the same array and store them in a single variable.

This array, stored in the $Array05 variable contains five different colors.

[PS7.2.0][C:\] $Array05 = 'black','red','green','blue','brown'
[PS7.2.0][C:\] $Array05
black
red
green
blue
brown

Each item in an array can be referenced by an index — a number that represents its location. It is a positional place in line. The first element, or item in the array — black in our case — is in index zero. This is because arrays are always zero-based. This means red would be in index 1, green in index 2, blue in 3, and brown in 4. Zero through four is five, as in five total elements, or values, in our array. Let’s verify.

[PS7.2.0][C:\] $Array05[0]
black
[PS7.2.0][C:\] $Array05[1]
red
[PS7.2.0][C:\] $Array05[2]
green
[PS7.2.0][C:\] $Array05[3]
blue
[PS7.2.0][C:\] $Array05[4]
brown
[PS7.2.0][C:\]

Let’s try some other things! While not often used in my day-to-day, we can perform arithmetic on the indexes. We can even use the range operator (..) and go forward and backward through our elements. What else… Oh, let’s try some negative indexes numbers, too. Those work in reverse from the end of the array to the beginning.

[PS7.2.0][C:\] $Array05[3-3]
black
[PS7.2.0][C:\] $Array05[2+1]
blue
[PS7.2.0][C:\] $Array05[0..4]
black
red
green
blue
brown
[PS7.2.0][C:\] $Array05[4..0]
brown
blue
green
red
black
[PS7.2.0][C:\] $Array05[-1]
brown
[PS7.2.0][C:\] $Array05[-2]
blue
[PS7.2.0][C:\] $Array05[-3]
green
[PS7.2.0][C:\] $Array05[-4]
red
[PS7.2.0][C:\] $Array05[-5]
black

Hash tables have a good number of similarities to arrays, and perhaps that is the reason why there is some confusion. Microsoft even uses the word array to describe them: “A hash table, also known as a dictionary or associative array, is a compact data structure that stores one or more key/value pairs.” I don’t use the words associative array often enough, but I should; I like it.

To the person on Reddit that called hash tables, hashmaps, and just maps: No. I believe that term is a carryover from maybe Java. In my experience, I have not heard it in the PowerShell community.

Anyway, arrays and associative arrays are both data structures. They can both hold multiple values, and they can both be stored in a single variable. The difference is keys and values. Arrays hold single items in each index, while a hash table holds a key-value pair in each.

Before we fill this up, let’s create an empty hash table. Notice the difference between this and the array. If it is used for an array, the operator will always be an instant giveaway: @() is for arrays, and @{} is for hash tables. Notice my liberal use of the GetType() method in this post; it’ll help you make object determinations, so you can always know which you’re working with, without having to view, or see, the data stored in the data structure.

[PS7.2.0][C:\] $Hash01 = @{}
[PS7.2.0][C:\] $Hash01
[PS7.2.0][C:\] $Hash01.Count
0
[PS7.2.0][C:\] $Hash01.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object

Now, let’s populate a hash table… in VS Code. Somethings I would just rather not demonstrate in the console.

$Hash02 = @{
    Dad = 'David'
    Mom = 'Betty'
    Daughter = 'Janice'
    Son = 'Bryan'
}
$Hash02
Name                           Value
----                           -----
Son                            Bryan
Dad                            David
Mom                            Betty
Daughter                       Janice

This also could have been written in a couple of other ways.

$Hash02 = @{
    Dad = 'David'; Mom = 'Betty'; Daughter = 'Janice'; Son = 'Bryan'
}
$Hash02 = @{
    Dad      = 'David'
    Mom      = 'Betty'
    Daughter = 'Janice'
    Son      = 'Bryan'
}

While hash tables have indexes, they’re non-numeric. Actually, I am not even sure I like the term index when working with hash tables. I suggest we call it what they are: keys. Maybe you noticed, but the order in which we created our hash table was not the order in which it was returned. A numeric value here would not help us anyway. Instead, we’re going to use the keys as our indexes to return our values.

$Hash02['Dad']
David
$Hash02['Daughter']
Janice

There is a good possibility that you are probably going to want to loop through and display all the values in your hash table. It’s a little out of place, but we’ll do that with one of our arrays here, too. Using the GetEnumerator() method allows us to get to the key and value, values out of our hash table. In this first, hash table example we are using the key and associated value in a string. This requires the use of the subexpression operator ($()), so that we can display our values within the string.

foreach ($Person in $Hash02.GetEnumerator()) {
    "The $($Person.Key) is $($Person.Value)."
}

The Son is Bryan
The Dad is David
The Mom is Betty
The Daughter is Janice

We are using the subexpression operator in the string created by looping over our array, too.

$Array05 = 'black','red','green','blue','brown'
foreach ($Color in $Array05) {
	"Is your favorite color $($Color)?"
}
Is your favorite color black?
Is your favorite color red?
Is your favorite color green?
Is your favorite color blue?
Is your favorite color brown?

This has been a lengthy post — who knew this would happen!? There is one last thing I want to mention, and that is about creating an ordered hash table, or dictionary. We tend to use the dictionary term when we order a hash table.

$Hash03 = [ordered]@{
    Monday    = 'Chipotle'
    Tuesday   = 'Pizza'
    Wednesday = 'Mahi Mahi'
    Thursday  = 'Ravioli'
    Friday    = 'Orange Chicken'
}
$Hash03

Name                           Value
----                           -----
Monday                         Chipotle
Tuesday                        Pizza
Wednesday                      Mahi Mahi
Thursday                       Ravioli
Friday                         Orange Chicken

Because this is ordered, we can use numeric indexes again. Keep in mind, however, that doing this is only going to return the values and not the keys, as well. It may even momentarily confuse you into thinking this is an array, not a hash table, or an associative array. Maybe stick to using a foreach at this point. Do not forget the GetType() method to ensure you know your data structures.

$Hash03[0..4]
Chipotle      
Pizza
Mahi Mahi     
Ravioli       
Orange Chicken

$Hash03.GetType()
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------     
True     True     OrderedDictionary                        System.Object

Okay, I am stopping here. There’s plenty to know about these two data structures, and at this point, it is more than I’m willing to share. Even so, this should provide a decent breakdown to go along with the Microsoft documentation and other information that’s available to consume on this topic. Know what you are talking about.

A Variable’s Current and Previous Value

How to Store a Variable’s Previous Value with the New Value

There was a recent post on the PowerShell Facebook group that said this: “Is there a function or option to check previous $Global:variable -ne Current $Global:variable?” The person that created the post wanted to know if there’s a way to recall the last value a variable stored, once it had already been assigned something new. Here’s my answer, and potential solution.

You have to think about a variable’s previous assignment, as if it never existed, even though you know that variable held something, or was assigned something, previously. Once its value is gone, it’s gone. Now, all that said, I came up with an option. The option, is to use a variable’s description property to store its previous value.

Let’s begin by checking the value of an uninitialized variable, and then assign it something.

PS > $x
PS > # No value.
PS > $x = 'first value'
PS > $x
first value

Now that our variable has a value, let’s take a look at all the variable’s properties using the Get-Variable cmdlet. Notice the Description property; we’re going to use this in a less than conventional way.

PS > Get-Variable -Name x | Select-Object -Property *

Name        : x
Description :
Value       : first value
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

Using the Set-Variable cmdlet, we’ll make two modifications to our variable, at nearly the same time. First, we’ll update the Description property, so that it’s holding the original variable assignment (the string ‘first value’). In the same, Set-Variable command, we’ll modify the current value of the variable to the string ‘second value.’ Notice in the final below command, that our Description property has a value now, too.

PS > Set-Variable -Name x -Value 'second value' -Description $x
PS > $x
second value
PS > Get-Variable -Name x | Select-Object -Property *

Name        : x
Description : first value
Value       : second value
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

In the next example, you’ll see how we can return the original value and the variable’s updated value. Beneath that, I’ve included a couple ways to compare these values. That gets back to what the person on Facebook was trying to determine. Again, this is fairly unconventional use of the Description property, but it does avoid the need for a second variable to hold the first variable’s original value. That said, one of my examples uses a second, comparison variable.

PS > (Get-Variable -Name x).Description
first value
PS > (Get-Variable -Name x).Value
second value
PS > $x
second value

PS > (Get-Variable -Name x).Description -ne (Get-Variable -Name x).Value
True
PS > (Get-Variable -Name x).Description -ne $x
True
PS > $y = (Get-Variable -Name x).Description
PS > $y -ne $x
True

In these last examples, we’re running into a bit of a problem, we are going to have to keep in mind (if anyone even dares use this approach). When we take a value that isn’t a string, and place it into the Description property, it becomes a string. That means, that when we take it back out, we’ll need to cast it back to its proper type. Take a look at the next series of examples for some assistance with this concept.

PS > $z = 5
PS > Set-Variable -Name z -Value 10 -Description $z
PS > Get-Variable -Name z | Select-Object -Property *

Name        : z
Description : 5
Value       : 10
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

PS > (Get-Variable -Name z).Description | Get-Member |
>>> Select-Object -Property TypeName -Unique

TypeName
--------
System.String

PS > [int](Get-Variable -Name z).Description
5
PS > [int](Get-Variable -Name z).Description | Get-Member |
>>> Select-Object -Property TypeName -Unique

TypeName
--------
System.Int32

This goes for decimals values, too. If you use the Description property to store something that’s not a string, then you’re going to have to properly cast it when you’re taking it out, or you’re going to have a string. In these next examples, I used the GetType method to determine the value’s type, as opposed to Get-Member and Select-Object used above.

PS > $m = 2.5
PS > $m.GetType().Name
Double
PS > Set-Variable -Name m -Value 3.5 -Description $m
PS > $m
3.5
PS > $m.GetType().Name
Double
PS > (Get-Variable -Name m).Description
2.5
PS > (Get-Variable -Name m).Description.GetType().Name
String
PS > [double](Get-Variable -Name m).Description
2.5
PS > ([double](Get-Variable -Name m).Description).GetType().Name
Double

And that’s it. It’s may not be the first choice for saving a previous variable’s value, but it’s a choice. I rather liked the array option that was recommended; however, like the $Error array, I’d be tempted to put the newest/current value of a variable into index 0 and not at the end of the array. Anyway, back to real life now.