Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

Weekend Scripter: Welcome to the PowerShell Information Stream

0
0

Summary: Learn about the Windows PowerShell information stream in this guest post by June Blender.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have another guest blog post by Honorary Scripting Guy, Windows PowerShell MVP, and Sapien technical evangelist, June Blender. Take it away June...

This post introduces the new information stream in Windows PowerShell 5.0. It explains the issue it tries to solve and its elegant solution.

In March 2014, I wrote a Hey, Scripting Guy! Blog post, Understanding Streams, Redirection, and Write-Host in PowerShell, which explained the output streams in Windows PowerShell.

Image

The outlier in the stream world has always been the much-maligned Write-Host cmdlet. Windows PowerShell inventor, Jeffrey Snover stateded Write-Host Considered Harmful. Famously, in his 2012 Scripting Games commentary, Stop Using Write-Host!, Windows PowerShell MVP and first follower, Don Jones, proclaimed that Write-Host kills puppies. That’s a lot of high-powered condemnation for a cmdlet.

And, it’s all about to change. With the advent of the information stream in Windows PowerShell 5.0, Write-Host is being redeemed. Actually, it's being, well...mainstreamed.

Write-Host and streams

The root of the problem is that in Windows PowerShell versions 1.0 through 4.0, Write-Host output doesn’t go to a stream. It goes straight to the host program, such as the console, ISE, or PowerShell Studio. What happens then is determined by the host program, and it might vary.

Because Write-Host doesn't go to a stream, if you put Write-Host in a script, the end-user can't suppress it, can't save it, and can't redirect it.

  • You can't suppress Write-Host output because there's no preference that silences it.
  • You can’t save Write-Host output in a variable, because the assignment operator uses the output stream. The Write-Host output is written to the host program, but the variable is empty.

Image of command output

  • You can't pass Write-Host output down the pipeline, because only the output stream goes down the pipeline.

Image of command output

  • You can't redirect Write-Host output, because redirection sends output from one stream to another, and Write-Host isn't part of any stream.

Image of command output

Write-Host and stream pollution

Despite this very high-level condemnation, people kept using Write-Host, precisely because it doesn't go to a stream. Write-Host is eco-friendly, because it doesn't pollute the output stream.

The underlying principle is that every command should generate one type of output. For example, Get-Process returns Process objects, and Start-Job returns PSRemotingJob objects.

You never want a command like the following, which returns process objects and a string:

Image of command output

In its own sad way, Write-Host solves this problem. In this version, I replaced Write-Output with Write-Host. Now this function writes a process object and a string, but only the process object is written to the output stream. The user sees the string, but it's not saved in the variable or passed down the pipeline.

Image of command output

The information stream

The dilemma was how to fix the harmful aspects of Write-Host (can't suppress, capture, or redirect), but keep it from polluting the output stream. And of course, the solution must be backward compatible.

This most elegant solution is the information stream. In Windows PowerShell 5.0, you can send Write-Host output to the information stream. Because Write-Host still writes to the host program by default, the solution is backward compatible.

By using the information stream, you can suppress Write-Host messages:

Image of command output

You can capture:

Image of command output

And you can redirect:

Image of command output

   Tip  If you're not familiar with the 'n>&1' syntax, see about_Redirection.

Unless you intentionally redirect them, Write-Host messages still don't pollute the output stream.

Now if someone was to write a function like Get-PowerShellProcess (and you still should never do this), the end-user could suppress the host message.

Image of command output

Information stream features

Image

Here are the features of the information stream in Windows PowerShell 5.0:

  • $InformationPreference variable

Determines how Windows PowerShell manages the information stream.

Like the other stream preference variables, the value of $InformationPreference is an ActionPreference option:

Continue, Ignore, Inquire, SilentlyContinue, Stop, or Suspend. The default value is Continue.

Image of command output

  • InformationAction common parameter

Determines how Windows PowerShell manages the information stream in the current command. This value takes precedence over the $InformationPreference for the current command.

Its value is also an Action Preference option:

Continue, Ignore, Inquire, SilentlyContinue, Stop, Suspend. The default value is Continue.

Image of command output

  • InformationVariable common parameter

Saves the information stream in the specified variable. Enter a variable name without a dollar sign ( $ ).

   Tip  The variable name cannot be "host" because $host is an automatic variable (see about_Automatic_Variables).

Image of command output

  • Write-Information cmdlet

The Write-Information cmdlet writes a message to the information stream. This message is not written to the console or sent to the host program, even when the $InformationPreference value is Continue. It responds to other values of InformationAction.

(This cmdlet behaves the way Write-Host probably should have from the start.)

Image of command output

Because Write-Information writes to the information stream, you can use the InformationVariable common parameter to capture its value.

Image of command output

If you really must write messages in a function or script, Write-Information won't pollute the information stream. (I had to add CmdletBinding to get the common parameters.)

Image of command output

As you learn Windows PowerShell 5.0, play around with the information stream. And the next time you're tempted to use Write-Host, use Write-Information instead.

~June

Thanks, June!

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


PowerTip: Multiply Value in Variable and Store Results

0
0

Summary: Use Windows PowerShell to multiply the value stored in a variable and store the results.

Hey, Scripting Guy! Question How can I use Windows PowerShell to multiply the value of a variable and store the results in the same variable?

Hey, Scripting Guy! Answer Use the *= operator, for example:

PS C:\> $a = 2

PS C:\> $a *= 3

PS C:\> $a

6

Weekend Scripter: When to Write a PowerShell Script

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about when to write a Windows PowerShell script.

Microsoft Scripting Guy, Ed Wilson, is here. I am enjoying a beautiful sunny morning in central Florida. The sun is shining, there is hardly a cloud in the sky, and a gentle ocean breeze tickles my skin. I am sitting outside under a beautiful, several-hundred year-old oak tree with Spanish moss that hangs to the ground from its bent branches. I mean, dude, if ZZ Top had a tree, it would look like this one.

Anyway, I am sitting out here with an oversized cup of Darjeeling tea, a plate of freshly sliced locally grown mango, and my Microsoft Surface Pro 3. It is a great, lazy day to sit and think, and to reflect.

Number one problem for noobs …

The number one problem that noobies seem to have when learning about Windows PowerShell is that they get overwhelmed with the power of Windows PowerShell, and they seem to go crazy. I mean, I can be at Ignite in Chicago, and a person comes up to me and asks a question like this:

“So, I have this server at work, and it has all of these logs. I want to write a script that will parse each of the logs, and look for problems. If there is a problem, I want it to send me a text message to my phone, send an email to my corporate account, turn off a couple dozen services, reboot our firewall and our router, send an alert to all of the users connected to the server to let them know that the router and firewall will be rebooting. I also want it to add an entry to an Excel spreadsheet to automatically calculate service up time, generate a Word document for our monthly report, and make a PowerPoint slide deck for our quarterly meetings about service availability. In addition, if it could track disk space usage and automatically submit purchase orders for additional disk drives when utilization is predicted to reach 85%, that would be nice.”

I can't help but reply, “Uh, you’re a Windows PowerShell noobie, aren’t you?”

What is wrong with the do-all-at-once script?

So what is wrong with the "do everything at once" approach to scripting? I mean, isn’t that what automation is all about?

Well, yes and no. To be fair, the noobie scenario I described could, in fact, be scripted. I could probably write such a script in less than two hours. But to be honest, I don’t think I would ever write such a script—except maybe for a demonstration about how cool Windows PowerShell really is and for how it could be useful in automating day-to-day tasks.

Why? Well, I will tell you....

Because in reality, such a thing would be of limited usefulness. It also would be a nightmare to troubleshoot and maintain.

Why a nightmare? Because there are too many moving parts. When a script has too many moving parts, the chance for it breaking is greatly enhanced. I think for every one new capability I add to a script, there is a fifty percent greater risk that the script will fail at some point in the future. That is, unless you add a lot of error handling and abstraction of parameters.

For every additional level of error handling you add to a script, you increase the development time by fifty percent. This means, that I can write a simple script with no error handling in thirty minutes. But it will take at least forty-five minutes by the time I add error handling for one potential set of problems. If I add error handling for another set of potential problems, it will take an hour… and so on.

This is why, most often, when I write a simple script for myself, I do not add much in the way of error handling. I will add comments that tell me how to run the script. For me, that is generally enough unless it is something that I expect to be more robust.

This week I am going to talk about the thought process that goes into writing Windows PowerShell scripts, and provide some guidelines that will help you decide what to script, when to script, and when to simply run a few basic Windows PowerShell commands from the Windows PowerShell shell.

Hope you have a great week, and I will see you back tomorrow.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Get Time with PowerShell

0
0

Summary: Use Windows PowerShell to get the current time.

Hey, Scripting Guy! Question How can I use Windows PowerShell to get the current time?

Hey, Scripting Guy! Answer Use the Get-Date cmdlet and specify a –DisplayHint of Time:

Get-Date -DisplayHint time

PowerShell Scripting: The Terms

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about Windows PowerShell scripting terminology.

Hey, Scripting Guy! Question Hey, Scripting Guy! So I am confused, and I am not afraid to admit that I am confused. In the old fashioned VBScript days, I wrote scripts. I could also write subroutines or functions. And that was about it. Pretty simple, and it made sense to me.

But with Windows PowerShell, it seems that there is so much more, and I do not even know where to begin. Not to mention that I have not seen a single reference about how to create a subroutine in Windows PowerShell. What gives? Can you throw me a bone?

—JT

Hey, Scripting Guy! Answer Hello JT,

Microsoft Scripting Guy, Ed Wilson, is here. I am looking out of the window from my office, and I see a big, green, grassy park. It is where people bring their dogs to walk, frolick, and catch Frisbees and other flying things. I imagine there are also a few who are throwing bones (or maybe rawhide bones) to their animals.

JT, I really don’t believe in throwing things, even bones, at people, but I can understand your confusion, and I will talk about the different scripting elements today.

Scripting pieces

So, there is the script. There is also the command line. There are the function and the advanced function, and there is the module. Knowing when to use each, in addition to the best way to use each, is a fundamental aspect of learning Windows PowerShell.

The script

The script is a basic unit in Windows PowerShell. I like to think of scripts in several ways. The first way is as an inline script. This is basically a series of Windows PowerShell commands that are interpreted sequentially. The script starts at the top and works its way down, line-by-line, until it reaches the end of the script. Usually, these are short (less than twenty lines, with 10 – 12 lines being typical).

I write these sorts of scripts as a kind of advanced Windows PowerShell command, and usually they are one-off creations. They do nothing I could not have typed from the Windows PowerShell console, but because it is a bit longer than a one-liner, it is easier to keep track of what is going on by putting the commands into a script. What I call the inline script, does not take advantage of any advanced scripting features of Windows PowerShell (no functions, advanced functions, or modules).

The function

When the script grows beyond the level of the inline script, I begin to group related commands into a function. A well-designed function has one way in and one way out, and it performs a single activity. At least, that is the way I like to write and design my functions.

Oh yeah, a well-designed function also returns an object. By having one way in and one way out, and by performing a single activity, it makes it easy to troubleshoot the function. It also makes it easy to reuse the function in another script, or to place it into a module.

A script can contain a function or more than one function. In fact, when my script begins to grow in length and complexity, I move related commands into a function. Sometimes, it means that I need to add a level of abstraction to my script, and often this requires a bit of thought.

So whereas my straight-line, quick script may have hard-coded paths, and string literals in it, I need to abstract all of these literal values into variables when I move them into the function. I need to begin to think about where those variables will be used: either only in the function, or in the script, or even outside the script.

The advanced function

The advanced function is a function that behaves like a Windows PowerShell cmdlet. In fact, the name for advanced functions, during the beta program was Script Cmdlet, and I actually liked that name because it was more descriptive.

The advanced function replicates the capability of a Windows PowerShell cmdlet, but instead of having to write in a higher language (like C#), we can write it in a Windows PowerShell script. An advanced function can duplicate the behavior of a cmdlet in that it can use the –WhatIf, –Verbose, –Confirm, and other common parameters that Windows PowerShell cmdlets support.

An advanced function can tie in with the Windows PowerShell Help system, so I can get help about the advanced function in the same way that I get help about other Windows PowerShell cmdlets.

The module

The module is the logical place to store a collection of related advanced Windows PowerShell functions. I can import a module into my script, and then I automatically have access to all of the functions stored in the module.

As an example, I created a module that contained a series of advanced functions that were designed to work with local user accounts. I had functions to create a new local user, add the local user to a local group, change the local user's password, and so on.

Because these tasks were all related to things I would do to local user accounts, I stored them all in a single module. But I did not write all of these advanced functions at one time, so I added to the module over time as the needs came up. Each time I added something, I created a new version of the module.

I also store my Windows PowerShell profile in a module. The profile is simply a Windows PowerShell script that is stored in a specific location, and it has a specific name. The first thing my Windows PowerShell profile does is import my profile module. Then on subsequent lines in my profile, it calls various functions from my profile module to configure things in my Windows PowerShell environment (such as my Windows PowerShell prompt—the prompt itself is simply a function).

JT, that is all there is to understanding Windows PowerShell scripting terminology. To Script or Not to Script Week will continue tomorrow when I will talk about best practices for using different scripting techniques.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Display Time in 24-Hour Format

0
0

Summary: Use Windows PowerShell to display the current time in 24-hour format.

Hey, Scripting Guy! Question How can I use Windows PowerShell to display the current time in 24-hour format?

Hey, Scripting Guy! Answer Use the Get-Date cmdlet and the –UFormat parameter with %R:

Get-Date -UFormat %R

A PowerShell Script Is…

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about creating and using a Windows PowerShell script.

Microsoft Scripting Guy, Ed Wilson, is here. This afternoon, it is raining—actually more like a thunderstorm because there is lightning and thunder. In the afternoon in central Florida, there is a really good chance that for 10 or 15 minutes, one will see an awesome thunderstorm. I think the weather people always have a standard line: "Chance of afternoon thunderstorms"—and there is a good chance they will be right.

Anyway, listening to Beethoven and watching a thunderstorm is awesome. I even decided to celebrate and to open one of my few Ale-8 sodas that we picked up on our way through Kentucky when we drove to Chicago for Ignite. Every time we are anywhere near the bluegrass state, we pick up a few bottles of Ale-8 and then ration them like gingerbread cookies.

I just noticed I can order them from Amazon, but that sort of spoils the effect. Besides that, they were selling it cans, and I can tell you from experience that you want it in a glass bottle. Otherwise, it doesn’t taste the same.

What is a PowerShell script?

Remember, that at its most basic form, a Windows PowerShell script is nothing more than a series of commands (even a single command) that could have been typed into the Windows PowerShell console. But instead of having to type the commands, they are stored in a .ps1 text file.

By default, Windows PowerShell scripting is turned off, and it needs to be enabled. To enable the Windows PowerShell script execution policy, I use the Set-ExecutionPolicy cmdlet. A normal user can use it to enable scripting by applying the –scope:currentuser token. This is shown here:

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned

Keep in mind that if there is a Group Policy setting for a different execution policy, the user will not be able to overwrite it.

None of this keeps me from opening a Windows PowerShell script, highlighting the commands in the Windows PowerShell ISE, and running the selected commands—nor does this prevent anyone from opening Windows PowerShell in “bypass” mode.

The script execution policy is a security convenience feature, not a security boundary. It is akin to the buzzer in your car that warns you to fasten your seatbelt. No one was ever saved by a seatbelt buzzer—unless they actually fastened their seat belt to silence the annoying buzzer. By the same token, the Windows PowerShell script execution policy is to help remind you to do the right thing when it comes to Windows PowerShell and security.

Elements of script

I like to add at least a couple of comments at the head of my script. The comments have the name of the script, when I wrote it, and a few notes that I might add. I have a function in my Windows PowerShell ISE profile modules that is called Add-HeaderToScript. The keywords that I add to my scripts are designed to make it easier for me to find my script by using Windows Search. I have changed my search settings so that I do a full text indexing of all of my .ps1 files. For example, if I type CIM in my search box, it would find all of my Windows PowerShell scripts where I added the CIM keyword in my keywords section.

The comments are free-form notes. For example, if I find a particularly helpful MSDN article, I might copy the URL for that article and paste it in my comments section. Absolutely, if I copied part or all of a script from someone else, I would provide credit to them in my comments section. If the script was used in one of my Hey, Scripting Guy! Blog posts, I would paste the URL to the post in the comments section (or at least, the date of the post). Armed with the date, I can find the URL for the Hey, Scripting Guy! Blog post.

I do not have a separate line for the version of the script. I add that into the comments section, but only when the script is a different version than 1.0. So if I revise a script, I will add a version to the comments section. But if it is the original version of the script, I do not have a version number at all. This is because I rarely revise my scripts.

If I add substantial new functionality to the script, the script becomes a new script. It is not that each script is perfect when I am done writing it. Far from it. It is simply the nature of my job to write hundreds of script samples, rather than to write one or two comprehensive, and ever evolving, script “applications.” When I think of script applications, I think of things like Clint Huffman’s PAL tool. Although it is a Windows PowerShell script, is much more like an application than a “simple Windows PowerShell script.” 

One last thing...

I write narrow code so that I can use it in books and blog posts. The commented lines at the top and bottom of my header block are 80 characters long, and this is what I use as my limit when I am writing scripts. This is sometimes very problematic, especially because the longest Windows PowerShell cmdlet name currently in production is over half of that length—and unfortunately, it does not ship with an alias!

Here is the header that I have at the top of all of my scripts:

# -----------------------------------------------------------------------------

# Script: Untitled1.ps1

# Author: ed wilson, msft

# Date: 07/05/2015 15:02:13

# Keywords:

# Comments:

#

# -----------------------------------------------------------------------------

 

Making scripts more powerful

In addition to writing a quick one-off script, I also like to import modules, or even dot-source another Windows PowerShell script to make it easier to reuse functions. In this way, I do not have to copy the function into my script. I can simply call it and use it.

The disadvantage to this approach is that you now have an external dependency. But Windows Powershell 5.0 with the One-Git repository makes it easy to have access to modules that I might want to incorporate. In addition, updating modules is easier.

The disadvantage to using a script and dot-sourcing it is that it brings everything into your current scripting environment—all functions, variables, and other things that you may not want. So, if I have a script that I will use to dot-source, I copy only the functions I want into it.

But then, if I am going to go to all that trouble, I may as well copy the functions into a module, and simply use that. With a module, I can control what I bring in—one or more functions, all aliases, no aliases, all variables, no variables, or whatever. It is very flexible, and is not much different than creating a resource script that will hold your functions.

To Script or Not to Script Week will continue tomorrow when I will talk about Windows PowerShell functions.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Get Unique List of Process Names

0
0

Summary: Use Windows PowerShell to get a list of unique process names.

Hey, Scripting Guy! Question How can I use Windows PowerShell to obtain a list of all the unique process names running on my system?

Hey, Scripting Guy! Answer Use the Get-Process cmdlet, pipe the results to the Select-Object cmdlet, and specify the Name property
           and the –Unique switch:

Get-Process | select name -Unique


PowerTip: Pick Up User Name with PowerShell

0
0

Summary: Use Windows PowerShell to easily pick up the user name.

Hey, Scripting Guy! Question How can I easily pick up the user name from my Windows PowerShell script?

Hey, Scripting Guy! Answer Use the USERNAME environmental variable, and pick it up from the $env Windows PowerShell drive:

$env:USERNAME

Fun with PowerShell Functions

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about basic design considerations for Windows PowerShell functions.

Hey, Scripting Guy! Question Hey, Scripting Guy! I keep hearing about functions, but I really do not know what they are, how to create one, or even how to use one. Can you help me with this? I am not a programmer, but it seems likely that you guys are trying to force me to become one. Help!

—DS

Hey, Scripting Guy! Answer Hello DS,

Microsoft Scripting Guy, Ed Wilson, is here. It is another beautiful day here in Central Florida. I am sipping a nice cup of Djareerling tea, with a bit of orange blossom local honey, and munching on a honeydew melon that came from a farm less than 20 miles from here. Way cool. Oh, yeah, I am also listening to Dire Straits on my Zune. They are playing “Money for Nothing” right now.

DS, using Windows PowerShell is a lot like getting your money for nothing and your checks for free...as the song goes. Why? Because when you learn Windows PowerShell, it is remarkably powerful, and it really is easy to create a script that will accomplish a lot of useful stuff in a very short period of time.

When I say "learn Windows PowerShell," I do not mean learn everything about it. Instead, there is a basic level of knowledge that you need to know, and then what you can do with it can build very quickly. For example, several of my guest bloggers teach a Windows PowerShell class for Microsoft Premier customers. This class is four days long, and at the end, the customers walk away able to accomplish incredible things.

If a class is not to your liking, you can go through my book, Windows PowerShell Step by Step, in less than a week. At the end, you have a really good grasp of what is possible with Windows PowerShell. So in less than forty hours, you can go from zero knowledge to being the hero scripting guy at your company. Then as Dire Straits said it, it will seem like you are getting your money for nothing and your checks for free.

Functions

Functions are a basic building block of a Windows PowerShell script or module. I use functions for several reasons:

  • Reusability
    I can reuse the code I have written. This really is getting a lot of bang for your buck, so to speak. I can write once, and reuse the code many times.
  • Readability
    If I can read a script, I can understand what the script is doing. This, in turn, makes it easier to troubleshoot and modify it at a later date. Readability is the key, and it will vastly simplify (or even eliminate) many troubleshooting situations. I very seldom need to use a debugger on my scripts, and the only times I really need to do so is when a script is so long and complicated that I cannot follow the flow of the argument. Good organization promotes readability, and that simplifies troubleshooting.
  • Flexibility
    A script with hard-coded values must be edited prior to reuse for an additional purpose. By abstracting tasks into functions, you add flexibility to the script and makes it easier to use for other purposes.
  • Simplicity
    A well-crafted function will simplify the flow of a script, and make it easier to write. Indeed, it can even make the script shorter by encapsulating code that may be required more than once.

A basic function

To create a function, I begin with the Function keyword. Then I need to give it a name. I like to use Verb-Noun combinations like Windows PowerShell cmdlets. This will simplify things when I decide to move my function into an advanced function. In fact, I always make sure that I use an approved verb—one that is specified in Windows PowerShell as permissible to use. I can, of course, make up any verb I wish. It is my script after all.

But if I put the unapproved verb named function in a module, a warning message appears when I load the module. That can prompt calls from users who see the warning and they wonder what is going on (kind of like the SQL module contains unapproved verbs in it, and that always prompts questions from people when I do demonstrations).

Finding an approved verb is easy: I use the Get-Verb cmdlet:

PS C:\> Get-Verb

Verb                                 Group                                 

----                                    -----                                 

Add                                  Common                                

Clear                                Common                                

Close                                Common                                

Copy                                 Common                                

Enter                                 Common                                

Exit                                    Common                                 

If I want to create a function to add a local user to a local group, I may name it Add-LocalUserToLocalGroup—or not, but you get the idea. In addition, it is good that the noun is descriptive. There is no doubt at all what Add-LocalUserToLocalGroup does. I can then create an alias for the long function name—maybe alug (for Add Local User Group), which will make it easy to remember.

After the Function keyword and the function name, I create input parameters, and then I add the code. Here is an example:

function Add-TwoNumbers

{

 Param ([int]$a,

        [int]$b)

    $a + $b

}

To use the function, I need to “load” it into memory. In the Windows PowerShell ISE, this simply means that I run the script that contains the function. I can then go to the immediate console window and call the function by name like I would do with a Windows PowerShell cmdlet. Indeed, tab expansion works, as does IntelliSense. When I have done this and press ENTER, and the function runs and returns my output:

Image of command output

DS, now you know the basics about using functions. To Script or Not to Script Week will continue tomorrow when I will talk about advanced functions.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find Status of Range of Services with PowerShell

0
0

Summary: Use Windows PowerShell to find the status of a range of services.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find the status of a range of services that have an initial letter that
           does not begin with V through Z?

Hey, Scripting Guy! Answer Use Get-Service with the –Exclude parameter, and supply a wildcard character set that represents
           the letters V through Z:

Get-Service -Exclude [V-Z]*

Understanding Advanced Functions in PowerShell

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about Windows PowerShell advanced functions.

Hey, Scripting Guy! Question Hey, Scripting Guy! I keep hearing about advanced functions, but to be honest, I am not really sure what they are talking about. I mean, I can do a function, but when does it become advanced? Only when it is really long? Or when it does complicated stuff? I don’t know if I have ever written an advanced function, do you?

—BB

Hey, Scripting Guy! Answer Hello BB,

Microsoft Scripting Guy, Ed Wilson, is here. Awesome day! I just received my copy of Blain Barton’s new book, Microsoft Public Cloud Services: Setting up your business in the cloud.  I wrote a couple of sidebars for the book, so I was able to score a free copy. It looks really awesome, and the couple of chapters I read this morning should help eliminate some of the confusion surrounding “the cloud.” In fact, the Scripting Wife and I are heading to the book launch at the Microsoft Office in a few days. It should be awesome.

You ask why some functions are advanced and others are not. After all, they are basically the same, right? Well, they are written the same way, and the both use the Function keyword, but advanced functions take advantage of the internal workings of Windows PowerShell that make Windows PowerShell cmdlets so cool.

For example, when I create an advanced function, I gain access to common Windows PowerShell parameters and other stuff that makes the function work like a Windows PowerShell cmdlet. The secret? It is the use of the [cmdletbinding] tag.

But I don’t need to know all of that because there is a Windows PowerShell code snippet called Cmdlet (advanced function). That is the one I use on a normal basis. There is also a code snippet called Cmdlet (advanced function) – complete, which offers every option available to add to a Windows PowerShell cmdlet. If I want to take complete advantage of Windows PowerShell, that is the snippet I use.

How do I do it?

I open a blank script page in the Windows PowerShell ISE, and I select Start Snippets from the Edit menu. It opens a page that offers all of the available snippets. This is shown in the following image:

Image of menu

When I have the template for the function, I edit it as required. I add information, for example, for the comment-based Help, and I change my parameter information.

Note The comment-based Help is outside the actual function in the templates, and that is pretty cool. This relies on a little known feature that if the comment-based Help has no lines (spaces) between the comment block and the function declaration, the comment block is interpreted as being associated with that function.

I normally move my comment-based Help section into the Function declaration. Because, to me, it makes the whole thing easier to move around as a unit.

Here is my really quick advanced function based on the script snippet template:

<#

.Synopsis

   Adds two numbers

.DESCRIPTION

   This function adds two numbers together and returns the sum

.EXAMPLE

   Add-TwoNumbers -a 2 -b 3

   Returns the number 5

.EXAMPLE

   Add-TwoNumbers 2 4

   Returns the number 6

#>

function Add-TwoNumbers

{

    [CmdletBinding()]

    [OutputType([int])]

    Param

    (

        # a is the first number

        [Parameter(Mandatory=$true,

                   ValueFromPipelineByPropertyName=$true,

                   Position=0)]

        [int]  

        $a,

        # b is the second number

        [Parameter(Mandatory=$true,

                   ValueFromPipelineByPropertyName=$true,

                   Position=1)]

        [int]

        $b

    )

    $a + $b

}

I copied the parameter declaration from the first parameter ($A) to the second parameter ($B) so that I would be able to pass two parameters to the function when I call it. This calling of the function is shown here:

Image of command output

BB, now you have a good understanding of advanced functions in Windows PowerShell. To Script or Not to Script Week will continue tomorrow when I will talk about Windows PowerShell modules.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Determine Name of PowerShell Host

0
0

Summary: Learn how to determine the name of the Windows PowerShell host.

Hey, Scripting Guy! Question How can I find the name of the Windows PowerShell host (such as the Windows PowerShell console or
           the Windows PowerShell ISE)?

Hey, Scripting Guy! Answer Use the Get-Host cmdlet and select the Name property:

(get-host).name

Understanding PowerShell Modules

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about Windows PowerShell modules.

Hey, Scripting Guy! Question Hey, Scripting Guy! I keep hearing about Windows PowerShell modules, but I do not know what they really mean. Is it something that comes with Windows PowerShell, or is it something I have to buy or download? I don’t get it. Can you shed some light?

—ST

Hey, Scripting Guy! Answer Hello ST,

Microsoft Scripting Guy, Ed Wilson, is here. Things are really exciting around the Scripting Household. I have been talking to Microsoft evangelist ,Blain Barton, about doing a PowerShell Saturday in Florida. Without giving any details away, it is something we are exploring. It will be way cool!

Windows PowerShell modules are a great way to share functions, and to be able to bring a group of functions into a script, or to a Windows PowerShell session, or even from computer to computer. The functions do not need to be advanced functions, but it sort of makes sense. I mean, if I am going to be writing something that I want to reuse, something I want to share from machine to machine, or something I want to with other users, it makes sense to use all of the Windows PowerShell technology that is available, including:

  • Comment-based Help
  • Parameter constraints
  • Error handling
  • Output streams (error, warning, and verbose)
  • WhatIf (if the function will change system state)
  • Confirm (if you want to ensure the user is aware of the potential action to take place, such as deleting a bunch of users)

All of these are features that can easily be implemented in advanced functions. Modules simply provide an easy way to ship related functions. Modules can include the following:

  • Functions
  • Variables
  • Aliases

The cool thing is that when I import a module, I can select if I want to import one or more functions, or one or more variables or alias. This provides a lot of flexibility. In addition, I can add versions to my module, so I can specify if I want to import a specific version of the module.

A module is simply a Windows PowerShell file with a .psm1 file extension. I can create it in the Windows PowerShell ISE, and when I save it, I specify that I want to save the .psm1 extension. After I have my module, I should create a module manifest for it.

A module manifest is a simple text file with a .psd1 file extension. I can create it manually, but the best way to create it is by using the New-ModuleManifest cmdlet. I must specify the path to the module, but there are also lots of other parameters that I can specify. Here is the syntax for New-ModuleManifest:

New-ModuleManifest [-Path] <String> [-AliasesToExport <String[]>] [-Author

    <String>] [-ClrVersion <Version>] [-CmdletsToExport <String[]>]

    [-CompanyName <String>] [-Copyright <String>] [-DefaultCommandPrefix

    <String>] [-Description <String>] [-DotNetFrameworkVersion <Version>]

    [-FileList <String[]>] [-FormatsToProcess <String[]>] [-FunctionsToExport

    <String[]>] [-Guid <Guid>] [-HelpInfoUri <String>] [-ModuleList

    <Object[]>] [-ModuleVersion <Version>] [-NestedModules <Object[]>]

    [-PassThru] [-PowerShellHostName <String>] [-PowerShellHostVersion

    <Version>] [-PowerShellVersion <Version>] [-PrivateData <Object>]

    [-ProcessorArchitecture <ProcessorArchitecture>] [-RequiredAssemblies

    <String[]>] [-RequiredModules <Object[]>] [-RootModule <String>]

    [-ScriptsToProcess <String[]>] [-TypesToProcess <String[]>]

    [-VariablesToExport <String[]>] [-Confirm] [-WhatIf] [<CommonParameters>]

When I am creating a module manifest for a new module, I can specify the aliases I want the module to export, the functions to export, and even the variables I want it to export. I can use the asterisk wildcard character ( * ), or I can enumerate exactly which items I want the module to export.

This is useful when a module may contain what I call "helper functions" that are used only by other functions within my module. If a function does not make sense to export, I can effectively hide it via my manifest.

When I use the Get-Module cmdlet, it returns information from the module manifest (which resides in the same folder as the module itself). This is shown here:

PS C:\> Get-Module ConversionModule

ModuleType Version    Name                          ExportedCommands

----------         -------       ----                                ----------------

Script     6.0        ConversionModule               {ConvertTo-celsius, ConvertT...

As shown here, I can pipe the output of the command to the Format-List cmdlet and see more information:

PS C:\> Get-Module ConversionModule | fl

Name              : ConversionModule

Path              : C:\Users\ed\Documents\WindowsPowerShell\Modules\ConversionModule\ConversionModule.psm1

Description       : a module that performs various unit conversions

ModuleType        : Script

Version           : 6.0

NestedModules     : {}

ExportedFunctions : {ConvertTo-celsius, ConvertTo-Fahrenheit, ConvertTo-Feet, ConvertTo-Kilometers...}

ExportedCmdlets   :

ExportedVariables :

ExportedAliases   : {CTCS, CTFH, CTFT, CTKM...}

ST, that is all there is to using Windows PowerShell modules. To Script or Not to Script Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Obtain Unique List of Process Names

0
0

Summary: Use Windows PowerShell to get a list of unique process names.

Hey, Scripting Guy! Question How can I use Windows PowerShell to obtain a list of all the unique process names running on my system?

Hey, Scripting Guy! Answer Use the Get-Process cmdlet, pipe the results to the Select-Object cmdlet, and specify the Name property and the –Unique switch:

Get-Process | select name -Unique


Weekend Scripter: The Big Decision about Scripts

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about if you should write Windows PowerShell scripts or do something else.

Microsoft Scripting Guy, Ed Wilson, is here. It is the weekend, and once again, it is a beautiful sunny morning in central Florida. I am sitting outside with my Windows Surface Pro 3, and taking the time to do a little writing. I picked up some fresh bagels, and I am sipping a nice cup of English Breakfast tea with a bit of lemon in it.

As I reflect back over this week’s blog posts, I think I need to clarify one thing: the whole point of scripting is to make things easier. If it is easier to not write a script, then don’t. If it is easier to use the GUI to accomplish a task, then do it. Hey, with Nano-Server, we have a greatly enhanced server manager tool that is web based, and it is a graphical tool that can accomplish some powerful tasks in a simple and low impact manner. So writing a script, or even firing up the Windows PowerShell console, is not always the easiest thing to do.

However, I think that often Windows PowerShell is the solution. In addition, I also predict that for every minute you spend learning Windows PowerShell, you will gain 10 hours of additional productivity over your career as an IT pro. No, I don’t have any hard statistics to back that up, but here are the assumptions that I base this on…

Back in the old-fashioned VBScript days, I was a consultant for a boutique consulting firm. Before I learned VBScript, when I faced a task on a server, I would think:

“This task will take me four hours to accomplish. If I knew VBScript, I could write a script and it would accomplish the task in about 10 seconds. But because I do not know VBScript, it would take me at least 8 hours to find a sample script, modify the sample script, test the new script, and then run it. So in the long run, it is cheaper for the customer if I do this task manually.”

If I knew VBScript, I could have written the script in about an hour and saved the customer three hours of labor on the task. So one day, I decided to learn VBScript—and as they say, the rest is history.

If one does not know scripting, Windows PowerShell or anything else, there is always a huge amount of entropy to overcome. For most common, daily tasks, it will always be quicker to use some sort of GUI tool, or to cobble together a batch file by using various Sysinternals utilities and other tools downloaded from TechNet to accomplish the task.

But eventually, you will become confronted with a task that simply cannot be solved in the old manner, using the old tools and techniques, and then you will be forced to learn Windows PowerShell. And, if following Murphy ’s Law, it will always happen at the most inconvenient time, at the time when the staff is stretched thin, and you will have no other choice. That is why one of my video series was titled PowerShell: Learn it now before it is an emergency.

The key thing is to focus on the task. Don’t let the discussions of console, ISE, inline script, saved Windows PowerShell commands, functions, advanced functions, or modules side track you into a state of inertia. Windows PowerShell is a tool. Sure, for some, it is also a hobby. For others, it nearly borders on an obsession. But to the majority of Windows PowerShell users, it is a tool—a powerful tool, but a tool nonetheless. In fact, it is one tool among many potential tools.

I need to look at the task to determine if Windows PowerShell is the best potential tool. For example, I am sitting here this morning, sipping tea, and writing today’s post. I am using the GUI tool, Word, to do this. Sure, I could write today’s post “in PowerShell” by using the powerful automation API in Word, but it is not the best tool for the job of writing a single article.

However, when it comes time to create template documents for six months of Hey, Scripting Guy! Blog posts, you better believe that I am using Windows PowerShell to do that. I saw a script awhile back that uses Windows PowerShell to create blog posts. The text content was added in as Here-Strings.

Dude! To me, that was cool. But at the same time, it was rather silly. I prefer to use Live Writer when I am doing ad-hoc blogging. Could I use the Windows PowerShell script my friend wrote? Sure, but to me, it is easier to use the best tool for the job, which happens to be Live Writer at this stage of the game.

I have seen Windows PowerShell scripts that replicate the old Asteroids game, and the old Space Invaders game, but if I want to write a game, I will use Visual Studio and some of the powerful gaming engines that are available. To me that is more fun than trying to monkey around with Windows PowerShell to do something it really wasn’t designed to do.

Will all this change in the future? I think perhaps so, because Windows PowerShell 5.0 will have classes. I think that will simplify some aspects of Windows PowerShell. Windows PowerShell becomes more like a real programing language with each new version. So who knows…

As I learned when I was a kid, use the best tool for the job. For example, when I was a kid I used a hammer to crack open walnuts. What I ended up with was more like a rather flat, small, walnut pancake. After that, I looked around for the nut cracker, which I found in the kitchen instead of in my dad’s tool box. Yeah, it was fun smashing walnuts with a hammer, but it did not really help me meet my goal of a healthy snack.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Get Disk Drive Overview

0
0

Summary: Use Windows PowerShell to obtain a disk drive overview.

Hey, Scripting Guy! Question How can I use Windows PowerShell to get a quick overview of my disk drives?

Hey, Scripting Guy! Answer Open Windows PowerShell with Admin rights, and use the Get-Disk function to retrieve
           the disk number, operational status, health status, friendly name, and size, for example:

Get-Disk | select number, operation*, health*, friendly*, size

Weekend Scripter: Debug, Boss...Debug

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about debugging Windows PowerShell scripts.

Microsoft Scripting Guy, Ed Wilson, is here. One of the cool things about central Florida is there are lots of farmers markets… especially (I am told) this time of the year. This is great, because I prefer organically grown, locally sourced food. I mean, I like my food to be simply food—not food and a whole lot of additives and other things. My simple rule is this: If I cannot read and pronounce it, then I won’t eat it. Although I have taken many science classes at the university, I have not had a chemistry class—so maybe that is part of my problem. Don’t know.

I need to read and understand my script

Scripting, for me, is a lot like my tastes in food. If I can read and understand my script, I am happy. If not, I try to do something about that. As a result, I seldom need to use the debugger on my own scripts. But from time-to-time, I get roped into someone else’s script project or I get sucked in to troubleshooting someone’s script. For whatever reason, I am confronted with code that I didn’t write. So all this week, I am talking about debugging Windows PowerShell scripts.

Often my first step is to simply reformat

I am not talking about reformatting my hard disk drive, although that is often helpful. No. Quite often if I cannot read someone’s script, I will start by reformatting the code so that it at least looks more like a Max Klinger than a Pablo Picasso.

I like to indent subordinate clauses and not indent major statements that are not dependent on anything else. So it is sort of like an outline. I start with a major heading, and then I indent things that are subordinate to the major heading. When I come back to things that are not subordinate, I go back to the unindented lines.

I like to group things together. For example, I like to have variable assignments and constants at the beginning of a script if they are part of setting up the environment for running the script. Obviously, if they are locally scoped to a function, the variables are in the function itself.

I like to initialize variables, even to $null, if they are used as counters or otherwise dependent on running of the script. In this way, I do not have to rely on the variables being created and initialized because they could pick up something that may be left over. This is especially important when using the Windows PowerShell ISE, and running a script multiple times or when leaving the Windows PowerShell console open for long periods of time and doing a lot of interactive stuff.

Next up…

If simple formatting does not do the trick, I begin to reach into my bag of tricks. For example, I may use Write-Debug and print debug statements that tell me what variable values are at different parts of the script. I will also print statements about making connections to a remote server, attempting authentication, and other aspects of the script as it runs.

If that doesn’t work, I will probably use the Set-PSDebug cmdlet and set a trace level of 1 or 2 to see how the script is running, to get an idea of the flow, and to see if I can catch any errors that arise from the flow of the script.

Depending on what happened with Set-PSDebug, I may turn on strict mode. To do this, I use the Set-StrictMode cmdlet and specify either version 1 or version 2. Version 1 is useful for finding problems with variable assignments and values, and version 2 is helpful in picking up some scripting best practices (such as calling a function like a method).

And if that doesn't work…

I will break out the debugger. To be honest, I like using the debugger in the Windows PowerShell console. For me, it is easy and intuitive, and it works very fast. But I can do the same thing in the Windows PowerShell ISE.

The easiest thing in the world is to set a breakpoint on line one for the script, run the script—and Bim!  Bam! Boom! I am in the Windows PowerShell debugger. I can then do things such as step through the script line-by-line, look at code blocks, and change variable assignments. It’s a very powerful tool, and it is best to learn how to use before tackling serious problems.

So…

Debugging Week will continue tomorrow, so come back when I will begin by talking a bit about using the Write-Debug cmdlet. 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find All Breakpoints in PowerShell Session

0
0

Summary: Find all breakpoints for a Windows PowerShell script.

Hey, Scripting Guy! Question How can I see the debugging breakpoints that are set in my current Windows PowerShell session?

Hey, Scripting Guy! Answer Use the Get-PSBreakpoint cmdlet.

Tracing the Execution of a PowerShell Script

0
0

Summary: Ed Wilson, Microsoft Scripting Guy, talks about using a cmdlet to trace the execution of a Windows PowerShell script.

Hey, Scripting Guy! Question Hey, Scripting Guy! I am having a problem with a script. It does not generate any errors, but dude, it does not seem to work either. Can you help me debug it?

—DR

Hey, Scripting Guy! Answer Hello DR,

Microsoft Scripting Guy, Ed Wilson, is here. When I see a script that doesn’t work, I think, "Cool…it is easy to troubleshoot." Often this is the case because the error message helps locate the source of the error. But if a script simply doesn’t work, it can be more difficult to troubleshoot. If the error is a logic error, it can be very difficult to troubleshoot.

Most of the time, examining the values of variables does not solve the problem because the code itself works fine. The problem often lies in what are called "the business rules" of the script. These are decisions the code makes that have nothing to do with the correct operation of, for example, a switch statement. At times, it may appear that the switch statement is not working correctly because the wrong value is displayed at the end of the code. But quite often the business rules themselves are causing the problem.

The problem with logic errors

For a simple example of a logic error, consider the function called My-function that is shown here:

My-Function.ps1

Function my-function

{

 Param(

  [int]$a,

  [int]$b)

  "$a plus $b equals four"

}

The My-function function accepts two command-line parameters: a and b. It then combines the two values and outputs a string that states the value is four. The tester performs four different tests, and each time the function performs as expected. These tests and the associated output are shown here:

PS C:\> C:\fso\my-function.ps1

PS C:\> my-function -a 2 -b 2

  2 plus 2 equals four

PS C:\> my-function -a 1 -b 3

  1 plus 3 equals four

PS C:\> my-function -a 0 -b 4

  0 plus 4 equals four 

PS C:\> my-function -a 3 -b 1

  3 plus 1 equals four

When the function goes into production, however, users begin to complain. Most of the time, the function displays incorrect output. However, the users also report that no errors are generated when the function runs.

What is the best way to solve the logic problem? Simply adding a couple of Write-Debug commands to display the values of the variables a and b will more than likely not lead to the correct solution. A better way is to step through the code one line at a time and examine the associated output. The easy way to do this is to use the Set-PSDebug cmdlet.

Using the Set-PSDebug cmdlet

The Set-PSDebug cmdlet has been around since Windows PowerShell 1.0. This does not mean it is a neglected feature, but rather, that it does what it needs to do. The Set-PSDebug cmdlet is not designed to do heavy debugging; it is a lightweight tool that is useful when you want to produce a quick trace or rapidly step through a script.

For performing basic debugging quickly and easily, you cannot beat the combination of features that are available. There are three things you can do with the Set-PSDebug cmdlet:

  • Trace script execution in an automated fashion
  • Step through the script interactively
  • Enable strict mode to force good Windows PowerShell coding practices.

Today, I'll begin to examine tracing the script...

Tracing the script

One of the simplest ways to debug a script is to turn on script-level tracing. When you turn on script-level tracing, each command that is executed is displayed in the Windows PowerShell console. By watching the commands as they are displayed, you can determine if a line of code in your script executes or if it is being skipped.

To enable script tracing, you use the Set-PSDebug cmdlet and specify one of three levels for the -trace parameter:

     Trace level

Meaning

0

Turns off script tracing.

1

Traces each line of the script as it is executed. Lines in the script that are not executed are not traced. Does not display variable assignments, function calls, or external scripts.

2

Traces each line of the script as it is executed. Lines in the script that are not executed are not traced. Displays variable assignments, function calls, and external scripts.

To understand the process of tracing a script and the differences between the trace levels, examine the CreateRegistryKey.ps1 script. It contains a single function called Add-RegistryValue. In the Add-RegistryValue function, the Test-Path cmdlet is used to determine if the registry key exists.

If the registry key exists, a property value is set. If the registry key does not exist, the registry key is created and a property value is set. The Add-RegistryValue function is called when the script executes. The complete CreateRegistryKey.ps1 script is shown here:

CreateRegistryKey.ps1

Function Add-RegistryValue
{
 Param ($key,$value)
 $scriptRoot = "HKCU:\software\ForScripting"
 if(-not (Test-Path -path $scriptRoot))
   {
    New-Item -Path HKCU:\Software\ForScripting | Out-Null
    New-ItemProperty -Path $scriptRoot -Name $key -Value $value `
    -PropertyType String | Out-Null
    }
  Else
  {
   Set-ItemProperty -Path $scriptRoot -Name $key -Value $value | `
   Out-Null
  }
 
} #end function Add-RegistryValue

# *** Entry Point to Script ***
Add-RegistryValue -key forscripting -value test

Working with trace level 1

When the trace level is set to 1, each line in the script that executes is displayed to the Windows PowerShell console. To set the trace level to 1, you use the Set-PSDebugcmdlet and assign a value of 1 to the -trace parameter.

When the trace level has been set, it applies to everything that is typed in the Windows PowerShell console. If you run an interactive command, a cmdlet, or a script, it will be traced. When the CreateRegistryKey.ps1 script is run and there is no registry key present, the first debug line in the command displays the path to the script that is being executed.

Because Windows PowerShell parses from the top down, the next line that is executed is the line that creates the Add-RegistryValue function. This command is on line 7 of the script because the actual script that executed contains six lines that are commented out.

After the function is created, the next line of the script that executes is line 30. Line 30 of the CreateRegistryKey.ps1 script follows the comment that points to the entry point of the script (this is the last line), and it calls the Add-RegistryValue function by passing two values for the -key and -value parameters. This is shown here:

PS C:\> Set-PSDebug -Trace 1

PS C:\> C:\fso\CreateRegistryKey.ps1

DEBUG:    1+  >>>> C:\fso\CreateRegistryKey.ps1

DEBUG:   30+  >>>> Add-RegistryValue -key forscripting -value test

After control of script execution is inside the Add-RegistryValue function, the HKCU:\software\ForScripting string is assigned to the $scriptRoot variable:

DEBUG:   12+  >>>> {
DEBUG:   14+   >>>> $scriptRoot = "HKCU:\software\ForScripting"

The ifstatement is now evaluated. If the Test-Path cmdlet is unable to find the $scriptRoot location in the registry, the ifstatement is entered, and the commands inside the associated script block will be executed.

In this example, $scriptRoot is located, and the commands inside the script block are not executed:

DEBUG:   15+  if( >>>> -not (Test-Path -path $scriptRoot))

As you see here, the Set-ItemProperty cmdlet is called on line 23 of the CreateRegistryKey.ps1 script:

DEBUG:   23+     >>>> Set-ItemProperty -Path $scriptRoot -Name $key -Value

$value | `

After the Set-ItemProperty cmdlet has executed, the script ends. The Windows PowerShell console parser now enters, with the same two lines of feedback that were shown when the tracing was first enabled:

DEBUG:   27+  >>>> } #end function Add-RegistryValue

PS C:\>

When you set the debug trace level to 1, a basic outline of the execution plan of the script is produced. This technique is good for quickly determining the outcome of branching statements (such as the ifstatement) to see if a script block is being entered. This is shown here.

Image of command output

DR, that is all there is to using script tracing to help debug a script. Debugging Week will continue tomorrow when I will talk about working with trace level 2.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Viewing all 3333 articles
Browse latest View live




Latest Images