Articles

PowerShell articles, tutorials, and guides from community experts.

Don Jones
PowerShell for Admins

Why Doesn't My ValidateScript() work correctly?

I’ve received a few comments from folks after my observations on the Scripting Games Event 1. In those observations, I noted how much I loved:
[ValidateScript({Test-Path $_})][string]$path
As a way of testing to make sure your -Path parameter got a valid value, I love this. I’d never thought of it, and I plan to use it in classes. I may write a book about it someday, or maybe even an ode. Seriously good logic. But… I also bemoaned some scripts that provided an additional Test-Path, in the script’s main body of code. Why have a redundant check?
So, first, thanks for the e-mails you all sent. Second… please understand that I can’t respond to you all. I’ve got this full-time job thing, and I’ve got to do it or the grocery store will stop taking our checks. You’re welcome to drop comments here, and I really appreciate when you say stuff like, “can you explain ___ in a future post?” because it gives me ideas to write about. I just can’t get into private e-mail based education for a dozen folks. Teaching is kinda what I do for my job, so most of my time has to go to that.
But - there’s a great teaching point here. Let’s take this example:
valid-default-path
This works as you would hopefully expect. When given a valid path, it’s fine. When allowed to use a valid default, it’s fine. When given an invalid path, it barfs in the ValidateScript. Now look at the next example - which more closely approximates what people have been seeing in their Scripting Games scripts:
invalid-default-path
In the Games, you were given a default path that wasn’t valid on your computer. So folks allowed their script to run with that default, and got errors, and were annoyed that ValidateScript() didn’t catch the problem.
It never will.
When you run a command, PowerShell goes through a process called parameter binding, wherein it attaches values to parameters and runs any declarative validation - like ValidateScript(). That validation will always catch invalid incoming data that’s been manually specified or sent in via the pipeline (for parameters that accept pipeline input). Because my -Path parameter wasn’t declared as mandatory, the validation routine will let me run the script and not specify -path.
Then the shell actually runs my code - and that’s when it assigns the default value to $path if one wasn’t specified on -path. Validation is over by this point, so an invalid default value will sneak by. The assumption by the shell is that you’re providing the default value, so you’re smart enough to provide a valid one. If you don’t, it’s your problem.
So do you just add a second, in-code check for the parameter? I’d still say no. I really dislike redundancy. If you know, because of your situation, that you can’t rely on ValidateScript(), then don’t use it at all - one check should suffice, and if it needs to be in-code instead of declarative, that’s fine. What’d be nice is if there was a declarative way of specifying a default, like [Default(‘whatever’)] that ran before the validation checks, but such a thing doesn’t exist. Frankly, you could probably argue that if you can’t guarantee the validity of a default, then you shouldn’t provide one - and I’d probably buy into that argument, and subscribe to your newsletter.
In this case, the problem is entirely artificial. The default path value given to you in the Games scenario is valid in the context of the Games; it’s just when you test it on your system, outside that context, that a problem crops up.
Hopefully this helps explain how the ValidateXXX() attributes work, and how they interact with other features, like a default value.
Now explain why this will never assign C:\ as a default value:
[Parameter(Mandatory=$True)][string]$path = ‘c:'

Don Jones
Scripting Games

Thoughts on Event 1 – and, frankly, a rant.

There’s been a lot of dismay floating around the community about the state of “community voting” in the Scripting Games. Some folks are voting without leaving comments (we’ve expanded the comment field to 2000 characters, hopefully that’ll help), and some disagreement about scores.
Disagreement is natural. For example, stick a Write-Host in your script and I’m likely to score you lower. You may disagree, but it’s how I feel in many situations… and I’m seeing a distressing amount of it.
Did you know that using [CmdletBinding(SupportsShouldProcess=$True)] doesn’t automatically and universally make the -confirm switch work? You have to do a bit more.
Did you know that if you put $DebugPreference=‘SilentlyContinue’ in your BEGIN{} block, that you disable the built in -Debug switch’s functionality? Yep, seen this one a few times also.
The community is showing a distinct lack of love for scripts that look like VBScript scripts. Does that mean your script is wrong? No - but it means you’re not approaching the problem in a way that the world in general feels is best. It doesn’t mean your script won’t work - but it means it wouldn’t be widely accepted.
If you’re not happy with your score, look at some higher-scoring scripts. See what they’re doing differently. If you can’t figure it out, post in the forums on PowerShell.org (there’s a Scripting Games forum). Provide the permalink to your script, and solicit some feedback from the community. Tweet people and ask them to take a look. You can ask for more feedback, if you want it and aren’t getting enough.
As our judges begin to post their notes, look at what they’re writing. Maybe they didn’t pick your script to write about - but are they writing about things that you also did in your script?
I’m seeing a lot of good scripts. But I’m also seeing some misunderstandings of some core, advanced features, like error handling, use of Verbose output, and so on. Each of those is a star to a half-star off, for me… some of these things, in my opinion, are severe, and I score accordingly. I haven’t seen a perfect, un-improve-able script, yet (I’m not even halfway through, yet). So no 5-stars yet. But I am trying to leave comments, and I know others are, too, so hopefully folks can improve. But be patient - it takes time.
And opinions differ. Let me offer an example:
Write-Verbose (“Script: {0} ended at {1}” -f $MyInvocation.ScriptName, (get-date) )
****Dislike. Not saying it’s wrong at all - and some people will disagree, vehemently, with me. But I find -f strings hard to read.
Write-Verbose “Script $($MyInvocation.ScriptName) ended at $(Get-Date)”
****For me, that’s easier to read. Not any more “right,” but in my company that’s the standard we adopted and that we use. Now, hopefully my opinion is being balanced by others’ opinions. But, if a substantial number of people share my opinion, this code would get a low score, and a community standard practice would emerge - something we can learn from after the Games are complete. Because yes, I’m going to harvest the Games entries and comments long after the Games are over to help keep the conversation and education going.
My point of this is that none of us are as awesome as we think. Others will always have points of disagreement. What’s really exciting here is the opportunity to create a community consensus of what’s best. That won’t come for several weeks, yet… but it will come. There is zero immediate benefit in getting a high score in the Games, and zero immediate detriment to a low score. This is going to seem harsh, but the Games are not about you. They’re about all of us. They’re about us developing a sense of community involvement and standards in an industry that doesn’t supply many of its own. This will happen over time, and with a lot of effort. But it’s worth it.
Let’s continue.
[ValidateScript({(Test-Path $_ -PathType Container)})]
I love that. I never thought to do that, and I love it. I’ve seen a few people do it. Bless them. I learned something!
An aside: There’s this general undercurrent of, “I wish ’expert’ judges were scoring me instead of the great unwashed masses.” Let me point out some practical realities. One, every entry in the Games at this point has at least 4 votes; many have double that. The last event, most had 1, 2 at most. And yes, while ’expert’ judges are allegedly well-qualified to render judgment, I’m not seeing a ton of scores I completely disagree with, yet. A few. Not a ton. And you want to know a dirty secret? How many entries do you think an ’expert’ can look at, in the evening, after working all day (we’re all volunteers), before he just starts getting a little arbitrary and inconsistent? The number is not “infinite.” I know I got a little arbitrary last year before I caught myself and stopped for the night. So… don’t discount the value of your peers’ opinions. If you’re getting a low score and don’t know why, seek out answers. Yes, people should leave comments with their votes. If they don’t, take charge and seek out answers yourself.
I love that I’m seeing so many divergent approaches to a single (admittedly open-ended) problem. Frankly, the value here is in browsing others’ approaches and picking up some tips from them. Or just seeing something different. You shouldn’t care about your score. You should care about what other people are doing, and about why you think their way might be better, worse, or just different. Make a learning opportunity. Don’t wait for someone to come to you with a free, written analysis of your code. Analyze other people’s entries and judge yourself against their work.
I’ve seen this a few times:

June Blender

How to Name Your Help Files

The first challenge of Scripting Games 2013 is complete! Honestly, you win by getting the experience of playing. I hope everyone is in there voting and writing really constructive comments. I’ll get over there in a minute, but I wanted to make sure that I got this information out to everyone before I get involved in voting.
Everyone who writes shared Windows PowerShell cmdlets, functions, scripts, CIM commands, and workflows also writes help topics ““ or gets a friend or colleague to do it.
For scripts and functions, you can write comment-based help (aka “inline help”).  All parameters of the Get-Help cmdlet support comment-based help, including the new ShowWindow parameter, and by adding a URL to the first related link, you can support the Online parameter in comment-based help.
But XML help files are required to document cmdlets (C#), CIM commands, and workflows, and to support Updatable Help. If you’re delivering your content in a module, you typically want to use XML-based help topics.
When you create XML-based help topics, you need to put them where Get-Help looks and give them the name that Get-Help expects. Otherwise, Get-Help will not find the help topic.
Get-Help looks for the XML-based help topics for the commands in a module in language-specific subdirectories of the module’s installation directory.  This is generally well-known and an easy instruction to follow.
The naming guidelines are a bit trickier. In general (specifics follow), Get-Help expects the help topic for a command to be in a help file that is named for the file in which the command is defined, including the file name extension. When the commands in a module are defined in multiple assemblies or multiple CDXML files, the module must include a separate help file for each assembly or CDXML file.
The help file name format is: -help.xml
For example:

Kirk Munro

New Technical Product Manager at Provance Technologies

Today is my first day working in my new role as Technical Product Manager at Provance Technologies.  A little while back Provance approached me to talk about this position, and it seemed like a very natural fit.  Rarely have I felt such a positive vibe from a company through the interview process, so I was really happy to accept the position of Technical Product Manager with them and I have been looking forward to starting work with them.

Don Jones
Scripting Games

Scripting Games Voting Continues!

As of right now, we’ve got almost 1900 votes on entries in the Scripting Games. Remember that each vote is a “pointlet” (see the PowerShell tie-in we did there?), which is basically a raffle ticket in our prize lottery.
But… there’s a secret about the lottery. It’s weighted based on how many entries you’ve voted on.
The algorithm is a bit complex, but for example, if you’ve voted on 90% of the available entries, you’re something like 30% more likely to win a prize. Vote on 50%, and you’re about 12% more likely to win… and so on. It’s a bit logarithmic… as you get closer to 100% your chances of winning increase more and more, with about a 39% advantage if you’ve voted on 100% of the events.
Of course, you can’t just abuse the system. We’ve got automated and manual checks in place for people who are just randomly voting - clicking all the same vote, voting in patterns, or voting with very little time separation between votes. All of those things will trigger a manual review, and you can be banned for life for attempting to game the system. We’re also tracking IP addresses and whatnot, so if you’re voting from multiple accounts, or trying to upvote your own entries… we’re going to just shut you out. You won’t even necessarily be notified, because we’re not confrontational folks.
But I know nobody’d do all that - we’re all in this to make the Games fun and educational! So get in there and vote. And leave comments. If you vote 1-star, tell the author why, so they can improve. Hey, it’s what YOU would want if someone 1-starred YOUR code, right? Right!
So vote! http://ScriptingGames.org!
(PS - please don’t report any tech problems in the comments here. The Games Web site has a feedback link)

Don Jones
Scripting Games

Meet the Scripting Games Judges: June Blender

June Blender is was a senior programming writer on the Windows PowerShell team at Microsoft from Windows PowerShell 1.0 ““ 3.0. You see her work every time you type Get-Help for the core modules. She’s now working on the Windows Azure Active Directory SDK team, and she remains an avid Windows PowerShell user and a passionate user advocate. She’s a guest blogger for the Scripting Guys and she tweets Windows PowerShell tips on Twitter at @juneb_get_help.
An engineering type by disposition, June was attracted to Windows PowerShell by the efficiency, productivity, and uniformity of automation. As a full-time working mom of three sons (now adults!), the idea of doing anything twice, unless it’s fun, is appalling. When evaluating scripts, she looks for elegance, but prefers scripts that inspire to those that intimidate. If saving a line of code makes your script difficult to understand and maintain, it’s not worth it. The scripts that get a thumbs-up from June are those that reveal a new way of performing a task and can be used as a template for scripts to come. Oh, and they must have Help!
June’s philosophy about Help is pretty simple. It’s supposed to make the task easier ““ clear, complete, and accurate. A parameter description that says that ServerName is the name of the server isn’t worth the characters you use to type it, but neither is the one that says that a parameter retrieves the modification of the nth cell in the hierarchically rarified data structure. She hates passive voice, too, because you don’t know who is supposed to act. About topics are critical. A whole mess of disjointed cmdlet help without an explanation of how they are intended to be used is not really helpful. And the best part of help is the examples. You really can’t have too many (see “Get-Help Invoke-Command”).
Community is the secret sauce in Windows PowerShell, so the best scripts contribute to our shared knowledge, productivity, and fun. June much prefer scripts and functions that you can open, read, and model to compiled anything.
A 16-year veteran of Microsoft, June lives in magnificent Escalante, Utah, where she works remotely when she’s not out hiking, canyoneering, taking Coursera classes, or convincing lost tourists to try Windows PowerShell. She believes that outstanding documentation is a collaborative effort, and she welcomes your comments and contributions to Windows PowerShell and Windows Azure Help.

Bartek Bielawski

Event 1: My way…

Looking for not-so-expert solution for Event 1 in both categories? Wonder how one of the judges would do it, if he had a chance? Want to return favor and tell me what I could do better and what I’m doing wrong? Don’t hesitate. 🙂 I decided it may be helpful to post my solutions before I ever see yours. Please find full article with lots of code on my blog. If you want to tell me you like/ hate this idea - please don’t hesitate either. And now I move on to your work. Can’t wait!

Richard Siddaway

CIM vs WMI cmdlets-remote execution speed

Following on from my previous post we"™ll look at how the two types of cmdlets compare for accessing remote machines.

I used a similar format to the previous tests but was accessing a remote machine.

First off was the WMI cmdlet ““ using DCOM to access the remote Windows 2012 server

PS> 1..100 |
foreach {
Measure-Command -Expression{1..100 | foreach {Get-WmiObject -Class Win32_ComputerSystem -ComputerName W12SUS }}
} |
Measure-Object -Average TotalMilliseconds

June Blender

Name that Property

Challenge #1 of Scripting Games 2013 is coming to a close. I can’t wait to see the results! I solved both the Beginner and Advanced versions just for practice and I learned a lot along the way. They’re not easy, but if you haven’t yet tried them, go for it. And be sure to review the candidate solutions for new techniques.
In my last post, I showed a very easy way to create a custom object in Windows PowerShell 3.0 and I argued that returning a custom object is far better than returning formatted objects. But, when you are formatting or selecting properties from an existing object, you can customize the names of the properties and their values. This techique isn’t new to Windows PowerShell 3.0 ““ it works in all versions – but it’s really handy, and I’ve noticed that not a lot of people use it.
Let’s start by changing the name of a table column. In this case, the big boss wants a list of files and their attributes. Get-ChildItem (“dir”) just about does it, but the property name is “Mode,” not “Atrributes,” and the big boss is a picky dude.