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:

# Validate that the source/log path provided is valid 
if (-not (Test-Path $LogDirectory)) { 
  Read-Host -Prompt 'Please provide a valid log directory'; 
}

I had honestly never thought of that. I'm not sure how I feel about it. Generally, PowerShell commands throw errors - they don't prompt you to retry, and I'm a big fan of consistency with the native commands. Right now I think this is a 1/8th point off for me... but I appreciate the approach and I'm still thinking about it.

I've seen this a lot:

Get-ChildItem -Path $LogDirectory -Filter $Filter | 
Where-Object { 
  $_.PSIsContainer -eq $false 
  -and 
  $_.LastWriteTime -le (Get-Date).AddDays(-($RetentionPeriod)) } | 
ForEach-Object { 
  $RelativePath = $_.FullName.Substring($LogDirectory.Length);
  # (truncated)

Personally, dislike. That's command-line, console-host approach - not a script. I think these massive pipeline blocks, in a script, are harder to read. Are they wrong? No. Will someone disagree with me? Yes. Again, vehemently. But I'm entitled to my opinion, and my opinion is that I'd rather see a scripting construct (ForEach) than a massive pipeline construct. Not in every scenario ever, perhaps, but... I'm biased against this approach. Understand that Where-Object is really just a ForEach loop in sheep's clothing... I suspect a single ForEach scripting construct could accomplish this block of logic in less time. As-is, you're looping through each object at least once... and many of them twice. That could be tighter.

Write-Warning $_.Exception.Message

This bums me out a little and I've seen it a lot. $_ can get hijacked a little easily, depending on your code... and frankly, it's hard to read. Why not take one extra step and use -ErrorVariable to capture the error into an easy-to-read variable name, and work with that? There are some arguments why not... but, in a broad sense, I prefer declarative, explicit stuff vs. weird built-in variables. I hate $_ even though it's used bloody everywhere.

Another aside: I've gotten several support e-mails from folks who missed the cutoff time. The site clearly indicates that all times are GMT. This is a global competition, and your local time zone isn't the only one out there. We can't provide exceptions to the cutoff - I'm truly sorry about that, but you can continue to participate in the next event. All times are GMT. The Competitor Guide also clearly states that all ties will be given as GMT, and if you've any confusion, the menu bar of the Games Web site lists the current time in GMT, which is what the server uses to make all scheduling decisions.

[ValidateScript({Test-Path $_})]

I freaking love that. Points off if you've included that and you've coded a manual check for the path. Redundancy doesn't pay, unless it's a server cluster.

if (!(Get-PSDrive -Name "dest" -ErrorAction:SilentlyContinue)){ 
  try { 
    New-PSDrive -Name "dest" -PSProvider FileSystem -Root $Destination -ErrorAction:Stop | Out-Null } 
  catch { throw "Cannot establish PS Drive for destination: $Destination. Check the path and try again." } }

I am at a bit of a loss as to why this solution needed a PSDrive. I mean... not wrong, but befuddling. I do tend to down-vote code I regard as unnecessary (and a lengthy comment explaining why you feel it's necessary won't help, if I disagree). In this case... I was just confused as to the need. Oh, and -ErrorAction:SilentlyContinue looks plain weird. Why would you include the colon? You didn't for any other parameter. Minus 1/8th point for style - just because I'm a stickler for consistency, and using the colon breaks consistency. Some poor slob in the future is going to look at this and wonder, "when do I use a colon and when don't I? Aggh!" and I'm going to have to write a book about it. Argh. <grin>.

Look at http://scriptinggames.org/entrylist.php?entryid=16 and tell me why I love it. Man, I hope that link works. If it doesn't don't yell - I'll fix it.

Oh:

param( 
[Parameter(Position=0)] 
[string]$Source = "C:\Application\Log", 

[Parameter(Position=1)] 
[string]$Destination = "\\NASServer\Archives", 

[int]$MaxAge = 90
)

I don't downvote for this, but I'm curious: Why declare a position for every parameter, when what you've declared is the default? Without those Position=x statements, you'd get exactly the same thing, right? Seems unnecessary?

Want more feedback? http://scriptinggames.org/entrylist.php?entryid=165. That's the Scripting Wife's entry. She's an accountant. But she's taken the time to be loved, so everyone votes on her entry. And I'll point out she's not getting a 5.0 score - so folks are clearly willing to be critical, even in spite of love.

Go, and be loved <grin>.

Posted in:
About the Author

Don Jones

Don Jones is a Windows PowerShell MVP, author of several Windows PowerShell books (and other IT books), Co-founder and President/CEO of PowerShell.org, PowerShell columnist for Microsoft TechNet Magazine, PowerShell educator, and designer/author of several Windows PowerShell courses (including Microsoft’s). Power to the shell!

8 Comments

  1. Nice post Don. This is my second Scripting Games and my favorite part is when an event opens up for voting, so I can go see all the other probably more clever ways that others solved the same problem. I learn something every time.

    • Awesome to hear! I learn a lot too - and my hope after these Games is that we'll be able to mine the entries, the votes, and the comments, and start constructing some community standards around what folks seem to like and not like. There's no reason this can't be the start of an ongoing conversation - and frankly, there's a ton of value for the product team seeing what people do, too, because it helps them move the product forward.

  2. As I understand it, SupportsShouldProcess does behave as intended with no other needed work with New-Item and Move-Item cmdlets, assuming the $ConfirmPreference (default High) is set to the correct level to trigger a confirm, or you can just override it with -Confirm if you would like to be prompted no matter the preference level (Low/Medium < < default/High). Anyway, <3 the event so far, have learned a few things so far - in just one day! (http://www.iheartpowershell.com/2013/04/powershell-scripting-games-2013_30.html)

    • I agree. I was coming back to add a comment about that. Take the following function:
      function test-confirm{
      Param()
      new-item -itemtype Directory -path C:\temp\test | out-null
      move-item c:\temp\test1 c:\temp\test\
      }

      Pretty simple function which has the "impactful" cmdlets from the first event in it.

      If you add [CmdletBinding(SupportsShouldProcess=$true)], then -confirm will automatically "flow down" to those cmdlets. This makes using SupportsShouldProcess almost a no-brainer. It's powerful and you don't have to do much to get that level of functionality.

      I think what Don was saying, though, is that it doesn't automatically wrap your "impactful" sections for you. You might want to consider a whole block of code as something that would get confirmed, and you'd have to do the whole $PSCmdlet.ShouldProcess() thing in an if-then around the block.

      • Yup, dead-on. You get what I call "hand me down" -confirm (this works for -verbose, too, for example) and -whatif. I tend to prefer explicit support, because I'm a huge fan of more readable code. I like to have more control over what's considered "impactful" than just relying on the hand-me-down support, because I also don't always know what Impact Level will trigger them.

  3. I appreciate your comments. I've been trying to include lots of comments on the entries I've scored and like you I've seen a lot of things that I hadn't thought of. I'm planning on writing a post on my thoughts (and common comments) on the first event. I hadn't paid much attention to the scripting games prior to this year and I see now what a huge mistake that was. Where else can you get a glimpse of how 150-ish people approach the same problem. Even if you don't agree with any of the other scripts you're bound to learn something.

    • Welcome - and thanks for those comments, because I know folks will appreciate them! And you're totally right... every year, I learn more about the shell and how to teach the shell based on what I see in the Games!

  4. Thank you so much for expanding the comment chars!

    I've learned several tricks already by reviewing entries, and find that putting my reactions to words helps me to internalize WHY something is a good or bad idea.

    For my personal strategy of scoring I've developed a core scoring strategy "If we wired big banana-flavored buttons to this script... would it accomplish the scenerio objectives every time the monkey hits a button?"

    Some of the scripts don't meet this test, and I would fear my coworkers getting ahold of them, yet they've had some generous votes.

    Anyone else have a scoring strategy that they feel more people should apply?

    ( in case anyone else has become a games addict here's some exanded observations and rants http://wp.me/p3r8nU-1S no one I know IRL cares so I'm starved for conversation about this stuff )