Tag Archives: Start-Process

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

A Better Way to Solve the Same Problem

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.

ConsoleHost to ConsoleHost Variable

I often do things, or learn things, in PowerShell that lead me in the direction of writing a new post. Sometimes it’s just experimenting, and sometimes it’s a part of a bigger project. Well, the latter is why we are here today. A current profile script project of mine — that I’ll post as soon as possible — requires that a new ConsoleHost (that’s the standard blue console screen; not the ISE), open and then the current one close. That part is easy.

The problem is that my new ConsoleHost needs to know if a variable has been set, or not, in the previous ConsoleHost. Here, follow along. Start by opening a new ConsoleHost. Inside that host program, create a variable and assign it some sort of value, as I’ve done in the below example.

PS > $Variable = 'This is my standard variable.'
PS > $Variable
This is my standard variable.

In my above example, I tested that my variable had been properly assigned by returning its value. So far, so good. Now, we’ll run a command to (1) open a ConsoleHost from this ConsoleHost, and (2) exit the original ConsoleHost. The semi-colon is a command separator. It allows me to put two commands on the same line and have them run in succession with a single press of the Enter key. One ConsoleHost closes and a new one opens.

PS > Start-Process -FilePath powershell.exe; exit

Now that we have a new ConsoleHost and our old one has exited, let’s see if our variable is waiting for us.

PS > $Variable
PS > 

Nope. That variable was created in a different PowerShell session, and so there’s no getting it back. It simply doesn’t exist any longer. Without fully thinking it through, I briefly thought to use a globally scoped variable instead. It wasn’t long at all, before I realized what a foolish idea that had been. My ConsoleHost was the global scope. With another ConsoleHost, all I’d have is another, separate global scope. Not helpful. I considered writing the variable to disk, but luckily, I didn’t have to consider that option for long either. I had a better idea; I was going to use an environmental variable. Follow along.

PS > $env:Variable = 'This is my standard, environmental variable.'
PS > $env:Variable
This is my standard, environmental variable.
PS > Start-Process -FilePath powershell.exe; exit
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS > # This is a new PowerShell ConsoleHost.
PS > $env:Variable
This is my standard, environmental variable.
PS > ise
PS > # This is in the PowerShell ISE Host.
PS > $env:Variable
This is my standard, environmental variable.

So, as we’ve seen, the environmental variable will follow us along from ConsoleHost to ConsoleHost to the ISE too, providing we open each of them from an existing host that includes the environment variable. Oh, and if you were wondering, the variable is still with us if we launch a ConsoleHost from the ISE (there’s a button for that). The environmental variable option works beautifully for my upcoming profile script project. I’ll link that from here when it’s up, and you’ll already understand that piece of it!

So it’s been included, the environmental variables are presented as a drive by PowerShell. The following command will show all of these variables. If you see some in there that you can use, then do so. It’s always better to use $env:COMPUTERNAME, than it is to hard code a computer name inside your functions.

Get-ChildItem -Path env:

Name                           Value
----                           -----
ALLUSERSPROFILE                C:\ProgramData
APPDATA                        C:\Users\tommymaynard\AppData\Roaming
CommonProgramFiles             C:\Program Files\Common Files
CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
CommonProgramW6432             C:\Program Files\Common Files
...
USERNAME                       tommymaynard
USERPROFILE                    C:\Users\tommymaynard
Variable                       This is my standard, environmental variable.
windir                         C:\Windows

Okay, now we’re really done with today’s post, and oh, hey look, there’s our $env:Variable variable again.

Automate App Server (Visual) Website Test

To visually determine if a website is loading slowly, or not, you might open the browser, enter the URL, and note the speed at which the page loads. Well, since I write tools to speed things up, writing one for this need, seemed to make sense. Part of the work was already done, thanks to the little function below that I had already written. It’s a function called Open-InternetExplorer and you can likely guess what it does. If you feed it a URL as the value for the -Url parameter, it’ll open up that webpage, otherwise, it’ll just open to the default homepage.

Set-Alias -Name iexplore -Value Open-InternetExplorer
Function Open-InternetExplorer {
    Param ([string]$Url)
 
    If ($Url) {
        Start-Process -FilePath iexplore $Url
    } Else {
        Start-Process -FilePath iexplore
    }
}

If you didn’t already notice, I’ve also included an alias be set for this function. With that in place, I can also enter iexplore to invoke the Open-InternetExplorer function. Notice that the Start-Process cmdlets inside the function include iexplore as the value for the -FilePath parameter. This is the Internet Explorer executable, and not the function alias.

Okay, so now we know how we can quickly open a new IE browser and determine what webpage to load. Let’s assume the page I want to check is http://appsrv01.subdomain.mydomain.com. This means, I can enter Open-InternetExplorer http://appsrv01.subdomain.mydomain.com and IE will open to that webpage (on that server). I may use a load balanced, front end URL for users to access the application, such as http://myapp.subdomain.mydomain.com. While the app is important (as it is one of the servers), knowing that all the app servers are responding and loading the page quickly is helpful.

For the remaining examples, let’s assume I have a variable called $MyAppServers that contains the default properties for five servers, returned from the Get-ADComputer cmdlet.

PS> $MyAppServers = Get-ADComputer -Filter * -SearchBase 'OU=MyApp,DC=subdomain,DC=mydomain,DC=com'
PS> $MyAppServers.Name
appsrv01
appsrv02
appsrv03
appsrv04
appsrv05

Now, let’s combine the $MyAppServers variable, with the function (and the ForEach-Object cmdlet, as the function wasn’t written to accept multiple URLs), so that we can open each app server’s webpage. This will allow us to determine if any of the pages load slower than any others, or more importantly, to determine if a page doesn’t load at all. Here’s how we do that.

PS> $MyAppServers.Name | ForEach-Object {Open-InternetExplorer -Url "$_.subdomain.mydomain.com"}

Once this command is run, it’ll open an Internet Explorer browser window for each app URL. In my case (Windows 8.1), I can hover over the IE taskbar items and view a small image of each IE window. Notice in the image below that one of the application servers didn’t load. I’ll need to look into that server!

automate-app-server-visual-website-test01

While I haven’t yet, the command above could be added to its own function, so I don’t have to type it out each time, and instead can simply enter the function’s name, or alias. In closing, I’ll mention another small function I added to my profile. This one will dump all running instances of Internet Explorer, allowing me to avoid manually closing each IE window, or typing out the Get-Process–Stop-Process command that the function runs.

Set-Alias -Name diexplore -Value Stop-InternetExplorer
Function Stop-InternetExplorer {
    Get-Process -Name iexplore | Stop-Process
}

Create a Function to Open Internet Explorer (Like in Run)

Even before Windows PowerShell, I strove to do things quickly. One such thing was to open Internet Explorer (IE) from the Run dialog. In the image below, you can see how you can enter iexplore followed by a space and then a URL. When you press OK, it will launch IE and direct itself to the URL that was passed along. If no URL is provided, it will open the home page.

Create Function to Open Internet Explorer (Like in Run)01

When I transferred this knowledge to PowerShell, I was sad to see that entering the same thing in the console host resulted in an error: “The term ‘iexplore’ is not recognized as the name of a cmdlet, function, script file, or operable program.”  I wasn’t overly concerned about it, moved on, and mostly forgot about it.

After spending last week at the PowerShell Summit North America 2015, I saw several demos from speakers that included ‘start iexplore <URL>,’ where start is an alias for Start-Process. Use Get-Alias to see this yourself: Get-Alias -Name start. I decided I would write up a simple function, to add to my profile, that would allow me to just use iexplore again.

With the function below, in place, I can enter iexplore in PowerShell to open Internet Explorer to the home page, or iexplore bing.com to open Internet Explorer to bing.com, for example — pretty straightforward. Here it is: the little function that saves me six keystrokes every time I use it. Don’t worry, it won’t be long before I make up for the lost keystrokes from writing the function itself.

Function iexplore {
	Param ([string]$Url)

	If ($Url) {
		start iexplore $Url
	} Else {
		start iexplore
	}
}

And, here’s the results.

Create Function to Open Internet Explorer (Like in Run)02

Before we close for the day, we should probably makes a couple changes to our function. We should change the function name so it uses an approved verb, along with the verb-noun naming convention, and then create an alias (iexplore), to call the function.

Set-Alias -Name iexplore -Value Open-InternetExplorer

Function Open-InternetExplorer {
	Param ([string]$Url)

	If ($Url) {
		start iexplore $Url
	} Else {
		start iexplore
	}
}

Clear-Host, Without Clearing the Host – Part 2 (TMConsole Module)

Download the TMConsole Module here: https://gallery.technet.microsoft.com/TMConsole-Module-Clear-487eff0e

Back in early September, I wrote a post about “clearing” the host. I was proud of my simple, little function, that I then called clx, and so in early October, I linked the post on Twitter. To my surprise, a few well-known names in Windows PowerShell helped promote the blog post. I’m talking about PowerShell MVPs, authors, and community bloggers – the very people I look up to and learn from.

Just recently, I decided it would be wise to add comment-based help and some minor logic-based, error checking to the function, and then post it on the Microsoft TechNet Gallery. In addition, I wanted to combine it with another simple console function that I use, and upload them both as a module.

If you’ve read the link above then you already know about the first half of the module (the Clear-TMConsole function, aka clx). The second half of this module (the New-TMConsole function) simply opens a new PowerShell console and provides the user the option to keep, or close the current console. I wrote this function because there are many times when I want a fresh console that doesn’t have any left over variables. I was tired of typing Start-Process (or saps) powershell. I understand these are simple, but I’ve become quite dependent on them to speed up my work, and to mildly safeguard information I want to keep in my console(s).

Below are a few aliases I use to help speed up my use of the functions. Opening a new console, and closing the current one, is as simple as entering: nc y n and pressing enter. The y is to indicate to continue running the New-TMConsole function, and the n indicates to not keep the current console. Hopefully this module can be helpful to others, too.

Set-Alias -Name nc -Value New-TMConsole
Set-Alias -Name clx -Value Clear-TMConsole
Set-Alias -Name cc -Value Clear-TMConsole

Download the TMConsole Module here: https://gallery.technet.microsoft.com/TMConsole-Module-Clear-487eff0e