Another Old HTA: WoL Manager

There’s a not so recent post that I wrote that discussed two old HTAs (HTML Applications) that I wrote long ago. I decided to link the post on the, The Scripting Guys’ Facebook Page (direct link: https://www.facebook.com/groups/5901799452/permalink/10154015674414453). It seemed to me that this group of people might be interested in these HTAs. It made sense, as I had learned plenty about VBS and HTAs from The Scripting Guy, Ed Wilson himself. It turned out to be good idea to share those old HTAs, as there were many downloads. If anyone really used them, I can’t honestly even say.

Someone back when I did this asked if I can, or would, add WoL (Wake on LAN), to the LoggedOnUser HTA. I think the idea was that if the computer didn’t respond, that it would leave the option to wake the computer. While I’m not interested in spending time adding that feature (unless there’s cash involved, or a whole lot of Chipotle gift cards), I did mention another HTA I had written back in my VBS/HTA days, called WoL Manager.

This HTA’s sole purpose was to wake up computers in a computer lab. I had opted to try and save some money by reducing electricity costs, by allowing the lab computers to drop into hibernation, or some form of deep sleep when they weren’t being used during the day, each evening, and over the weekends. It was an often used lab during all hours of the day. Being that I’m very much into Windows PowerShell and automation in general, you can understand that I would rather not walk to the lab every time I needed to wake up a computer. No, I would rather send a WoL magic packet, give it a moment, and then remotely connect to the system, which I did for a few years. The last time this thing was used, was… 2013.

We’ll start by looking at the WoL Manager HTA and then discuss a little more about it. There’s some things you’ll need to know if you opt to try it out. I’ll include a download link at the bottom of this post. Here’s three different views of the HTA: (left) when the HTA is first opened, (center) when the HTA is ready to wake a single computer, and (right) when the HTA is ready to wake all the computers.

script-sharing-another-old-htas-wol-manager-2015-01     script-sharing-another-old-htas-wol-manager-2015-02     script-sharing-another-old-htas-wol-manager-2015-03

Much like the LoggedOnUser HTA, this one also requires a computers.txt files arranged like the example below (name, colon, MAC address). The file needs to remain in the same directory as the HTA. The download includes this file which can be easily edited.

Server01:053ae714eaca
Server02:0044e924f241
Server03:0034e734f2a2
Server04:0043e944f5a3
Server05:0034e654a533
Server06:0043e664e3d3

The HTA requires a third-party executable to wake the computer, which I’m not distrubuting. It’s called wol.exe and can be downloaded here: http://www.gammadyne.com/cmdline.htm#wol. Make sure this executable is located in the same directory with the HTA and computers.txt file, too.

In the environment where I (used to) use WoL Manager, I was able to use the wol.exe command line tool, such as:

PS> wol.exe 0043e944f5a2

It did not require that I include an IP address, like it does in the second example back on this page: http://www.gammadyne.com/cmdline.htm#wol, or in my below example. If your environment requires the IP address of the computer where the HTA is running (not the computer you’re trying to wake), then the HTA will need to be modified (which you’re welcome to do). I think there’s some commented out HTML at the bottom where I may have been getting ready to add this option. I don’t believe there’s any logic in the HTA, however.

I used this same wol.exe executable at home to wake up my desktop computer, although at home, it’s used as part of a Windows PowerShell function. To use this there, my laptop’s IP must be included to wake up the home desktop, such as:

PS> wol.exe 0043e944f5a2 10.10.10.33

If you’re interested in this HTA, start by downloading wol.exe and seeing if it works, first. Also, you may have to make some modifications to the system(s) in which you want to wake, but I’m sure Google, or Bing, can help with setting up the NIC(s) to accept WoL magic packets, if they don’t already.

One final note: I cannot remember for the life of me if the Wake All option actually works, or not. I briefly looked a the subroutine called by clicking that button, and it looks good. Someone might want to let me know. After writing all this, and reading it two years later, maybe I understand why this post as been sitting in my drafts for so long. Enjoy, if you try it and it works!

You can download this HTA here: WoLManager1.1.zip (14106 downloads )

Functions Finding Variable Values

Every once in awhile I forget something I know, I know. Not sure why, but for a quick moment, I suddenly couldn’t remember which can access what. Can a nested, or child, function, access the variable in the containing, or parent, function, or is it the other way around? That is, can a containing, or parent, function access the variable in the nested, or child, function? Even as I write this, I still can’t believe that for a moment I forgot what I’ve known for so long.

Duh. A nested or child function can access a variable assigned in the containing or parent function. If the child function cannot find a declared variable inside itself, it’ll go upward in scope to its mom or dad, and ask if they have the variable assigned, and if so, they can borrow it. Being good parents, they offer it if they have it.

It’s so obnoxious that in a quick moment, I wasn’t sure, even though I’ve pictured it in my own head multiple times, as well as relied on it. Anyway, here’s an example that does prove that a nested function will go upward to find a variable, if it’s not been assigned inside itself.

Function AAA {
    'In function AAA.'
    Function BBB {
        'In function BBB.'
        $x = 5
    }
    $x
    BBB
}
AAA

Function CCC {
    'In function CCC.'
    $x = 5
    Function DDD {
        'In function DDD.'
        $x
    }
    DDD
}
CCC
In function AAA.
In function BBB.
In function CCC.
In function DDD.
5

This got me wondering, how far up will it go!? I assume it’ll go up and up and up, and well I was right. Take a look at this example. I guess if I had to forget something so simple that at least I got an opportunity to build this example. Enjoy the weekend!

Function Top {
    $x = 10
    "0. Assigned `$x with $x."
    "1. Inside the $($MyInvocation.MyCommand.Name) function."
 
    Function MidTop {
        "2. Inside the $($MyInvocation.MyCommand.Name) function."
 
        Function MidBottom {
            "3. Inside the $($MyInvocation.MyCommand.Name) function."
 
            Function Bottom {
                "4. Inside the $($MyInvocation.MyCommand.Name) function."
                If (Get-Variable -Name x -Scope Local -ErrorAction SilentlyContinue) {
                    '5. Can find the variable in the local scope.'
                } Else {
                    '5. Cannot find the variable in the local scope.'
                }
                "6. The value of `$x is $x."
            } # End Function: Bottom.
            Bottom
 
        } # End Function: MidBottom.
        MidBottom
 
    } # End Function: MidTop.
    MidTop
 
} # End Function: Top.
Top
0. Assigned $x with 10.
1. Inside the Top function.
2. Inside the MidTop function.
3. Inside the MidBottom function.
4. Inside the Bottom function.
5. Cannot find the variable in the local scope.
6. The value of $x is 10.

Update: I made a few modifications to the above function. Now, it indicates that it cannot find the $x variable in the local scope of the Bottom function. That’s one way to help prove it goes upward through the parent functions looking for a value for $x.

The Pester Book Chapter Review ToC

Update: As this project is now complete, I’ve updated the publish date on this Table of Contents post, in order that it comes before (really, it’s after), all 23 of my chapter reviews.

Welcome to The Pester Book Chapter Review, Table of Contents (ToC). Use the below links to read my chapter reviews. If this project isn’t yet completed, you can check back for updates every week, at most. Once done, however, the links will remain so you can read my chapter reviews, as you read the book. If you’re writing PowerShell and haven’t started testing your code, it’s probably time you did.

“…you really should know PowerShell, and if you’re going to have to learn it and write it, then let’s learn to test it, too. Pester is going to be one of those things, that in time, people will assume you know, if you know PowerShell…”
-Tommy Maynard

My Introduction
The Introduction

Part I: Meet Pester

Pester Concepts
Designing for Testing
Describe Blocks
Before and After Blocks
It Blocks
Should
Test Cases
Mocks
The TestDrive Drive

Part II: Using Pester

Design Practices
Adding Tests for a Function
Adding Tests – Again
Working with Pester Output
Infrastructure Validation
Mocking the Unmockable
Troubleshooting Tests

Part III: Using Gherkin with Pester

Using Gherkin with Pester

Part IV: Code Coverage

Why Code Coverage?
Using Pester to Measure Code Coverage
Improving Code Coverage

Part V: Pester Cookbook

Recipe: Testing for Live Conditions
Recipe: Testing for Scheduled Tasks
Recipe: Testing for Installed Software
Recipe: Ensuring all Functions in a Module Have Tests
Recipe: Testing External Applications
Recipe: Testing Syntax
Recipe: Testing Remote Scripts Blocks
Other Resources

The Pester Book Chapter Review (23)

Table of ContentsPart V: Pester Cookbook

Well, this is it. We’re just about done with this project in its entirety. That’s right, we’ve come to the end of The Pester Book chapter reviews. Originally, I was going to do one post per recipe in this section; however, there’s so little to discuss on each that it makes more sense to wrap things up in a single post. And, so here we are.

These recipes, as Adam as chosen to call them, are little, bite-sized mini chapters that discuss a quick topic one might encounter while testing. I especially enjoyed them in that they included simple functions and a simple, corresponding test, or tests. We covered testing for live conditions where we compared a function’s internal WMI call against the actual WMI outside the function, we tested for installed software, determined a way to ensure all the functions in a module have a test, we tested exit codes from executable in scripts, we tested external applications in conjunction with the $LastExitCode automatic variable, we tested syntax errors (think exceptions), and how to handle remote script blocks — that was important to see.

In closing, Adam shared other Pester related resources. There were some I’ve already seen and used, and others I haven’t. I’m not as confident as I’d like to be (and that’s a common theme with me), but after reading this book, I’m armed with enough information to have meaningful conversations about Pester, as well as starting to write more test suites, even as I may need to use Pester included help and the Internet, as I do. It was a good read, and certainly brought me to a new high in my Pester testing knowledge.

Therefore, if you’ve been reading along and learning with me, then we’re both at a better place, as new coding ideas and opportunities start with what do we test, before anything else. I don’t know about you, but I’m looking forward to that next project.

The Pester Book Chapter Review (22)

Table of Contents Improving Code Coverage

This, was a very involved chapter, and it required a good deal of concentration. We first had to understand a good amount of PowerShell that we then had to write tests around. Even so, this turned out to be a great opportunity in that we had not typically seen some of the examples that were included in this chapter. We saw multiple mocks for the same command, mocks that included New-MockObject, a good deal of ParameterFilter parameters on our mocks, and even a Foreach around an Assert-MockCalled command. Awesome.

All that said, the idea behind this chapter wasn’t to present various ideas for testing — although it most certainly did — it was to do a full code walkthrough in regard to code coverage. Once we understood the example function, we met three initial tests someone new at Pester might write. Then the example took off, with a whole new test suite written by Adam. After a multiple page understanding of what had been written, we tested the code coverage. It wasn’t perfect, but it was close. A few changes and we got to a place where the percentage was high enough to feel confident that everything in this function had been tested.

There was a quote I liked, I’ll share in closing. I liked it because we got an image that just like you or me, Adam walked the code in his own mind and extracted those things in which he wanted to test. “These tests were created by following the various code paths of the function. I followed the code from top to bottom and when it “did something,” I created a test for that thing. I followed all code paths.”

Well, next we’ll start Part V, and work to wrap up this chapter-by-chapter book review. I’m excited to finish, but mostly so I can head back and review a touch before I find my next Pester resource. I don’t feel like I know it, know it, so like PowerShell before this, I’ll keep looking for new information to consume in regard to Pester. Back soon.

The Pester Book Chapter Review (21)

Table of ContentsUsing Pester to Measure Code Coverage

Oh man, this was good. This chapter was short, simple, and to the point. In it, we used Pester to measure our code coverage. If you didn’t know this feature was included in Pester, then I suspect you’re grateful now. You should be, as for me at least, I can easily see how this can be helpful. Providing you use it correctly, and get a grasp on what it’s testing and whether it’s testing, then there’s definitely going to be some benefit here.

We discussed a few scenarios during this chapter. These included executing a simple code coverage test — so we could see how this thing works. We saw how Pester will notice untested functions, how Pester will indicate full coverage even if a test doesn’t include an assertion, and how to force a test against a single function, even if there’s more than one in a single .ps1 file. In addition, we saw how we can test a single function by including line numbers for the function, instead of providing the function’s name.

I suspect this was a great intro and build up for the upcoming, and final chapter, in this part of the book. The next chapter looks involved. Time to get started.

The Pester Book Chapter Review (20)

Table of Contents Why Code Coverage?

Welcome to Part IV: Code Coverage. I read this chapter in the most recent version of The Pester Book, which was released on Saturday, April 28, 2018. Be sure to get the newest version if you’re following along. I hope you have been, as according to the ePub file on my iPad, Part IV began with only 51 pages left in the entire book. We’re nearing the end.

Code Coverage is the ability to determine the amount of code that executes as a part of your testing. There are a few metrics, or measurements, that we use along with code coverage. These are statement coverage, branch coverage, path coverage, and condition coverage. Each of these allow us to measure the coverage of code, even as they may sometimes overlap. Be sure to make these, make sense to you.

It was nearing the end of this shorter than normal chapter when it spelled it out like so: “Simply put, code coverage is a way of measuring whether or not you’re executing all of your code through a given set of tests.” In closing here, I do want to bring up test cases. As they were mentioned as a part of this chapter, you may want to head back and review theses if you don’t remember them well. I remember them, but that’s because I’ve put them to use in some of my own testing.

I’m already looking forward to the next chapter, where I’ve spotted some example code. It’ll be helpful to see some examples after this introduction.

The Pester Book Chapter Review (19)

Table of Contents Using Gherkin with Pester

It turns out there’s this whole thing called Gherkin. Before this chapter, all I knew is that I liked saying Gherkin, but that I didn’t really know much else about it (besides the whole cucumber/pickle thing). This single part of The Pester Book had just a single chapter in order to introduce us to Gherkin. I’m not going to try and explain it exactly. What I’ll do instead, is allow the book to partially do it for me. Here’s a quick couple of sentences from the text:

“Gherkin is a Business Readable, Domain Specific Language. It’s meant to decouple the business logic from the actual code being tested. It’s a language that can be used with any development language thus how we’ve been able to use Gherkin with PowerShell and Pester.”

That’s kind of neat, the whole, it can be used with any development language. I guess that’s why it’s in here. I did want to mention that Gherkin appears “…to be more suited for infrastructure testing rather than unit testing.” That’s probably a good thing to know.

Gherkin requires two files. There’s a .feature file and a .steps.ps1 file. One holds code, and one does not. The layout of these two files are specific in that the .feature file contains text description of how the tests will be structured (no code). The actual code — the tests — are located in the steps.ps1 file. These should be kept together inside the same directory with the script, or module, that is being tested. I won’t go into the layouts of each of the files, but it was certainly interesting to see, how each file was dependent on the other in order to execute the code — the tests. You’ll be glad to know that embedded within the .steps.ps1 files was PowerShell, and Pester, used to test the expected vs. the actual results.

I would recommend you work through and understand the example in the chapter. I didn’t really want to at first — I’m doing Pester, not pickle — but in the end, I’m glad I had some exposure to Gherkin, just in case it comes up another time.

Linux Prompt on Windows – Part IX

In the last installment of this series, just published a day ago, I mentioned that I’d like to be able to pass in the fake username and computer name to my prompt function, instead of relying on a hard coded value. Let’s back up, but seriously, only for a second. There’s only so much I’m willing to repeat if you’re starting to read this series at the ninth installment. You can use the links at the very bottom to easily access any of the previous posts.

My prompt function includes my real username and computer name. At times, I like to switch it to a fake username and computer name, so that screen captures won’t include my real information. These hard coded, fake username and computer name values are inside my prompt function as “tommymaynard@cpux1789.” Until now, I wasn’t able to choose the fake username and computer name, and that’s why we’re here today. I’ve added a way to make these values dynamic. I’ve included everything you’d need to copy to your $PROFILE script in order to use this same prompt function. I warn you however, once you start using it, you may not want switch back. And that’s fine, because it just got better.

Here’s an example, before I include the current prompt code. Do notice that the new UserName and ComputerName parameters are completely ignored when the Type parameter value is “Real.” This is because they are not needed in order to use the real username and computer name.

Unfortunately, the Set-Prompt function didn’t feel like a job for ParameterSets. I imagine I could have accomplished “adding” the UserName and ComputerName parameters, when the Type parameter had a value of “Fake,” using dynamic parameters; however, that’s just way too much involvement for now, and would likely bring little return on the invested time. I can be happy with this, at the moment.

Here’s the newest version. Copy it to your $PROFILE script and try it out! You will need a fake, default username and computer name. Toward the bottom of the code, inside the parameter section of the Set-Prompt function, swap out “tommymaynard” for your default, fake username, and “cpux1789,” with your default, fake computer name.

https://gist.github.com/tommymaynard/0dc88b5927ab5f63ee4738d87252fd63

Part VIII | Part VII | Part VI | Part V | Part IV | Part III | Part II | Part I

Linux Prompt on Windows – Part VIII

Update: There’s a part nine, now.

This, is the topic that will never die.

I’m literally about to begin the eighth installment on this topic. There’s no question about it, I love my prompt. In the last installment, we added a more complete PowerShell version number to the prompt, and the entire version number to the WindowTitle. We also added a Type parameter to the prompt function. This allowed me to manually (yuck) edit my function’s Type parameter default value between “Real” and “Fake.” Well, those days are done.

As of now, I’ve removed the default assignment of the Type parameter ([string]$Type = ‘Real’) in the below prompt function. Instead, I added a second function. It’s toward the bottom of the included code, so let’s meet down there.

https://gist.github.com/tommymaynard/4a544e89f71c00abf3611eb18971c71e

Hello again.

The additional function is called Set-Prompt. As the prompt function and this function are in my $PROFILE script, I can expect that they’re both loaded into memory each time a PowerShell host program is opened. In addition to loading the Set-Prompt function into memory, my $PROFILE script also invokes the function. Even though Set-Prompt has a default value for the Type parameter (much like the prompt function had previously), I still pass the “Real” parameter value to the Type parameter.

What this provides is an assurance that my prompt will always be real (include my real username and computer name), when I open a new PowerShell host. If I want to change it to my fake username and computer name for a screen recording, or screen captures, I simply run the below command. The Set-Prompt function doesn’t truly interact with the prompt function. What it does instead, is it updates the $PSDefaultParameterValues variable, so that every time the prompt function is invoked (each new prompt is created), it includes the correct Type parameter value even though we don’t actually see it entered.

Set-Prompt -Type Fake

Since I can’t seem to get away from adding more to my prompt function and this topic, perhaps we’ll do a ninth installment. I would kind of like a way to pass in the fake username and computer name, too. As of now, those values are still hard coded in the prompt function.

Update: I decided to add a graphic to this post. In the below image, although it looks like two different consoles, we’re actually working in the same PowerShell console. In each instance where it was necessary I hid a portion of the computer name. This may actually assist in seeing the real vs. the fake prompt, as I hid a part of my real computer name. The red line helps to indicate the same command in each image.

Part VII | Part VI | Part V | Part IV | Part III | Part II | Part I