There once was a time I wrote a post. Realistically, there have been many times. Like many posts though, I was proud of it. I can’t show it to you, as it wasn’t written on my site and it has since been lost. I am actually kind of embarrassed by it these days, so I’m mostly glad it is gone.
Someone, on some forum, wanted to know the previous value of a variable. Not the current value, but the last value it had been assigned before its current value. My idea then, which seems ridiculous now, was to store its last value in its description property. If you don’t know, variables have a writable description property; really, they do. It is a pretty nice feature, were anyone to actually use it. I don’t imagine many people do. I know about it, and honestly, I don’t use it.
Instead of using a variable’s description property to store its last value, I got to thinking about the $PROFILE
variable and how it works. Let’s have a look, but before we do, let’s make sure we all know what this variable holds. This variable contains a path to your profile script, whether your profile script exists or not.
[PS7.2.0][C:\] $PROFILE C:\Users\tommymaynard\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
The profile script is invoked when PowerShell launches, allowing you to create variables, define functions, and modify your PowerShell environment to suit you. In a recent post, I discussed creating a work-based ASCII image and sending in some keys. This made sure the first command I want to invoke was ready when PowerShell launched; all I had to do was press Enter. Oh, and here is every time I mentioned the $PROFILE
variable on tommymaynard.com going all the way back to 2014. It has come up quite a few times over the years.
We have seen the value the $PROFILE
variable holds, but there’s more. Let’s run it another way.
[PS7.2.0][C:\] $PROFILE | Select-Object -Property * AllUsersAllHosts : C:\Program Files\PowerShell\7\profile.ps1 AllUsersCurrentHost : C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1 CurrentUserAllHosts : C:\Users\tommymaynard\Documents\PowerShell\profile.ps1 CurrentUserCurrentHost : C:\Users\tommymaynard\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 Length : 71
Using the Select-Object
cmdlet produced three additional paths: AllUsersAllHosts
, AllUsersCurrentHost
, and CurrentUserAllHosts
. I am not going to go into what these all mean, but host refers to the program hosting the PowerShell engine. Read more about profiles here. With these three additional paths, there are four total locations where a profile script can be located and loaded by default. So, what do we have here? We have a variable with the ability to hold more than a single value (without making it an array or a hash table). That’s just how this variable works and I want the same thing for my example variable.
In this example, we’ve returned the same values as we did above, however, in this instance, we’re using the Get-Member
cmdlet. I think it is important to see the values returned a couple of different ways.
[PS7.2.0][C:\] $PROFILE | Get-Member -MemberType NoteProperty TypeName: System.String Name MemberType Definition ---- ---------- ---------- AllUsersAllHosts NoteProperty string AllUsersAllHosts=C:\Program Files\PowerShell\7\profile.ps1 AllUsersCurrentHost NoteProperty string AllUsersCurrentHost=C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1 CurrentUserAllHosts NoteProperty string CurrentUserAllHosts=C:\Users\tommymaynard\Documents\PowerShell\profile.ps1 CurrentUserCurrentHost NoteProperty string CurrentUserCurrentHost=C:\Users\tommymaynard\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Let’s start the remainder of this post by creating my example variable. Like the $PROFILE
variable, we’re just going to work with string values.
[PS7.2.0][C:\] $PROFILE.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object [PS7.2.0][C:\] [PS7.2.0][C:\] $PSSites = 'https://docs.microsoft.com/en-us/powershell/scripting/overview' [PS7.2.0][C:\] $PSSites https://docs.microsoft.com/en-us/powershell/scripting/overview [PS7.2.0][C:\] [PS7.2.0][C:\] $PSSites.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object [PS7.2.0][C:\]
At this point, we’ve assigned a docs.microsoft.com URL directly to the $PSSites
variable. Now, let’s take a few new values and assign each of them as a NoteProperty on the same variable. This is done by using the Add-Member
cmdlet. We assign the current value of the $PSSites
variable back to the $PSSites
variable, while also adding the new note property.
[PS7.2.0][C:\] $PSSites = $PSSites | Add-Member -NotePropertyName 'GitHub' -NotePropertyValue 'https://github.com/PowerShell/PowerShell' -PassThru [PS7.2.0][C:\] $PSSites = $PSSites | Add-Member -NotePropertyName 'Docs' -NotePropertyValue 'https://docs.microsoft.com/en-us/powershell/' -PassThru [PS7.2.0][C:\] $PSSites = $PSSites | Add-Member -NotePropertyName 'Gallery' -NotePropertyValue 'https://www.powershellgallery.com/' -PassThru [PS7.2.0][C:\] $PSSites = $PSSites | Add-Member -NotePropertyMembers @{Reddit='https://www.reddit.com/r/PowerShell/'} -PassThru
You may have noticed, but in the last of the above four examples, we used the NotePropertyMembers
parameter with a hash table for the associated value. This option allows us to supply both the name and value at the same time. It does exactly what the first three examples did — it is just another way to do it.
I should mention the PassThru
switch parameter. This is a requirement because Add-Member
cannot add types to strings, so this will generate an object. It’s worth keeping this in mind. Without it, you’ll drive yourself crazy trying to determine why it isn’t working — always, read the help!
Using dot notation we can see the additional values (note properties), that our variable has been assigned.
[PS7.2.0][C:\] $PSSites.GitHub https://github.com/PowerShell/PowerShell [PS7.2.0][C:\] [PS7.2.0][C:\] $PSSites.Docs https://docs.microsoft.com/en-us/powershell/ [PS7.2.0][C:\] [PS7.2.0][C:\] $PSSites.Gallery https://www.powershellgallery.com/ [PS7.2.0][C:\] [PS7.2.0][C:\] $PSSites.Reddit https://www.reddit.com/r/PowerShell/
Like we did with the $PROFILE
variable, we can use the Select-Object
cmdlet to return all of our URLs. We can also use Get-Member
.
[PS7.2.0][C:\] $PSSites | Select-Object -Property * 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/ Length : 62 [PS7.2.0][C:\] $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/
Now, with the PowerShell site URLs stored in the $PSSites
variable, I can easily open whichever website I prefer using Start-Process
and the corresponding property. No real idea if I’ll use this, but I’m grateful to know how to use a note property to store additional data along with a simple string variable.
[PS7.2.0][C:\] Start-Process -Path $PSSites.Gallery
Join me next time, perhaps, if I can devise a way to save the previous value of a variable to a note property when assigning a new value to the variable itself. It will take a little thought and work, but for now, I think it is possible.