More on output…

It could probably be just yet another comment under “What you see is NOT what you get” post. But I’ve decided I would give it more space and make code more readable than it’s possible in comments.

As I said before: for me nice output is less important than data itself. If I can keep data and make it look nice – I’m more than OK with that. I spent most of my time in PowerShell window so nice output make me happy camper. Winking smile That’s why whenever I write a module I spent some extra time on it to add ps1xml files to it and decide how both Format-List and Format-Table should behave with objects I create. Obviously, objects also have some custom names, usually they have some pseudo-type tattoo rather than type wrote in C# and added to PowerShell with Add-Type.

Problem with more ad-hoc scripting (or scripting in general if module is not an option) in version 2 of PowerShell is that you can’t easily create this custom formatting on the fly. Building ps1xml file is overkill in such scenario, and sending strings to the pipe is something I would rather avoid if original data is something of a different nature (numeric, DateTime, etc.). So, what I would do?

Function to polish object data.

When you or PowerShell formats data using any of custom formatters (both Format-Table, and Format- List) it will, this way or the other, convert your data to strings.

This solution is based fully on the feedback and observations during Scripting Games. I decided to go with ToString() method replacement because it’s both advanced and pretty easy to port on any object that exists. There are two parts of this solution. First – good enough ScriptBlock that will be used as methods value. Than – logic to either replace ToString method, or whole property (I decided to do that for “normal” objects, to avoid issues with read-only properties, like Length on files). This logic will also try to “fix” properties that look like numbers, but are strings instead (e.g. stuff from Import-Csv).

ScriptBlock on the fly

Because our function will in the end format data we may want to give user ability to tweak formatting. With numeric it means moving decimal point. For that to work smoothly it’s bests to create ScriptBlock once we know –DecimalPoint value with [ScriptBlock]::Create() method:

begin {            
    $MethodOptions = @{            
        Name = 'ToString'            
        MemberType = 'ScriptMethod'            
        PassThru = $true            
        Force = $true            
        Value = [ScriptBlock]::Create(@"
            "{0:N$DecimalPoint} {1}" -f @(
                switch -Regex ([math]::Log(`$this,1024)) {
                    ^0 {
                        (`$this / 1), ' B'
                    }
                    ^1 {
                        (`$this / 1KB), 'KB'
                    }
                    ^2 {
                        (`$this / 1MB), 'MB'
                    }
                    ^3 {
                        (`$this / 1GB), 'GB'
                    }
                    ^4 {
                        (`$this / 1TB), 'TB'
                    }
                    default {
                        (`$this / 1PB), 'PB'
                    }
                }
            )
"@            
        )            
                    
    }            
}            

To add or not to add

Now that we have code prepared all we need to do is to inject it. But we will try to be smart about it. Few things I’ve tried to cover:

  • property may not exist on the input object
if (!$SelectedProperty) {            
    Write-Verbose "No such property: $Prop"            
    continue            
                        
}            
  • property can be of type System.String, so adding ToString() won’t effect way it displays
if ($SelectedProperty -is [System.String]) {            
    [Int64]$InputObject.$Prop = $SelectedProperty            
}            
  • property can’t be converted into number
if ( ! ([double]$InputObject.$Prop) ) {            
    Write-Verbose "Can't be casted into double: $Prop"            
    continue            
}            
  • type is not PSCustomObject so we risk issues with ReadOnly properties
if (!$InputObject.PSTypeNames.Contains('System.Management.Automation.PSCustomObject')) {            
    try {            
        $Member = @{            
            MemberType = 'NoteProperty'            
            Name = $Prop            
            Force = $true            
            Value = $SelectedProperty            
        }            
        $InputObject | Add-Member @Member            
    } catch {            
        Write-Verbose "Not able to replace property on this type: $($InputObject.GetType().FullName)"            
        continue            
    }            
}            

If nothing is preventing as from adding ToString – we eventually do it for each property selected by user:

process {            
                
    foreach ($Prop in $Property) {            
            
        $SelectedProperty = $InputObject.$Prop            
            
        # Tests using $SelectedProperty...            
            
        $InputObject.$Prop = $InputObject.$Prop |             
            Add-Member @MethodOptions            
            
    }            
    $InputObject            
}            

I uploaded this function both to poshcode and TechNet library (once I finished with help and stuff). Hope it will be somewhat useful for people like me: who like it useful and pretty. Winking smile

Credits

This solution would not come about if not two people who’s ideas I’ve used.

First – Rob Campbell (@mjolinor), with his brilliant use of [math]::log to decide which unit fits best for given numeric.

Next – Robert Eder who’s trick with custom ToString method from Scripting Games entry I’ve used in this solution.

Thanks you guys for inspiration! Smile That’s the beauty of Scripting Games: you never stop learning new things!

What you see is NOT what you get.

While grading scripts in advanced category event 4 I noticed that most people assume that it’s necessary to change number into string to format it nicely. The problem with this approach: once you changed number into string you kind of kill PowerShell ability to sort, filter and group objects based on properties that are numbers. If you ever decide to use it for something else than showing to the user – you will probably have to parse results and reverse whole process. And because it’s PowerShell that you use – you do not really have to. You can get both. As advanced scripter – you should know that already. Smile Let’s take a look at some practical examples, to make it more clear when problems start to show up. If I will sort two objects:

2,10 | foreach {            
    New-Object PSObject -Property @{            
        Name = "Foo $_"            
        Size = "$_ Bars"            
    }            
} | Sort-Object -Property Size            

… PowerShell will try to convince me, that 2 Bars are greater than 10. In world of strings that’s true. In world of numbers – not so much. To be honest – for me that’s huge flaw of that approach. It looks nice, but that’s not usually what I’m after. I want PowerShell to give me information first, look nice later. So what could one do?

First approach: usability over visuals

I’ve seen several scripts, that would be better if authors would not focus so much on making output exactly the same as the one they’ve seen on screenshot attached to this task. Obviously, best approach was to get it done exactly the same. But if you had no idea how – it was better to keep important bits in output too. In other words: if you can’t make it look the same and give full functionality – focus on functionality rather than “look”. Back to our fictional objects:

2,10 | foreach {            
    New-Object PSObject -Property @{            
        Name = "Foo $_"            
        Size = $_            
        SizeFormatted = "$_ Bars"            
    }            
} | Sort-Object -Property Size            

We get formatted output and ability to process data with real values kept. It won’t look perfect, but we won’t loose important bits “in translation”. Winking smile

Second approach: nice by default, optionally functional too.

Second approach is smart way to work around issue of loosing important information during process of making data look pretty. PowerShell has very strong parameter support. You can name parameters, you can have flags (parameters of type [switch]) to easily enable/ disable some options. That’s a perfect use case for that kind of parameters. If you want to display it nicely without “polluting” output with raw data – make your script aware of situations, were raw data is more important than nice view. If you name parameter wisely and for even better user experience – explain why would you want to use it in your comment based help and show use case in examples, than you have little of both worlds. Several contestants actually used it for their entries. It could be as simple as that:

function Get-Foo {            
param (            
    [switch]$IncludeRaw)            
    2, 10 | foreach {            
        $PropertyHash = @{            
            Name = "Foo $_"            
            SizeFormatted = "$_ Bars"            
        }            
        if ($IncludeRaw) {            
            $PropertyHash.Size = $_            
        }            
        New-Object PSObject -Property $PropertyHash            
    }            
}            

It will remove numbers by default, but if I ever decided to use them – all I need to do is use switch to get them back.

Third approach: customize ToString.

This is another pretty smart idea I picked up from one of contestants. If you understand how PowerShell formatting works, you may trick it pretty easily. Data will be kept intact but output will be more human-readable. How it works? Let’s take a look:

$AddMember = @{            
    MemberType = 'ScriptMethod'            
    Name = 'ToString'            
    Force = $true            
}            
            
2, 10 | foreach {            
    $Out = New-Object PSObject -Property @{            
        Size = $_            
        Name = "Foo $_"            
    }            
    $Out.Size | Add-Member @AddMember -Value { "$this Bars" }            
    $Out            
} | Sort Size

ToString() method is what PowerShell will usually use to display data “for humans”. But value will remain untouched, so you won’t loose anything. IMO that’s the best way to solve this task. Not the one I would choose however before I’ve seen this approach. My solution would involve ps1xml file, probably because I like this concept so much. Winking smile

Fourth way: temporary px1xml.

This is more complicated approach than the one we had used before. Maybe some people would say – too complicated for the task of that importance. But I would like to show you how to do that anyway: get ps1xml file created on-the-fly and use it to create decent output without loosing important information. It may be helpful in some other applications.

There are two parts of that solution: first you need to create and use ps1xml format file for pseudo-type that you create. Than – tattoo your objects using this pseudo-type name.

First one is pretty complex, mainly due to complexity of ps1xml files:

$FormatFile = [System.IO.Path]::GetTempFileName() |

    Rename-Item -NewName { $_ -replace ‘$’, ‘.ps1xml’ } -PassThru

$FormatXml = @’

<?xml version="1.0" encoding="utf-8"?>

<Configuration>

  <ViewDefinitions>

    <View>

      <Name>Foo</Name>

      <ViewSelectedBy>

        <TypeName>Foo.Bar</TypeName>

      </ViewSelectedBy>

      <TableControl>

        <TableHeaders>

          <TableColumnHeader>

            <Label>Name</Label>

            <Width>20</Width>

          </TableColumnHeader>

          <TableColumnHeader>

            <Label>Formatted Size</Label>

            <Width>20</Width>

          </TableColumnHeader>

        </TableHeaders>

        <TableRowEntries>

          <TableRowEntry>

            <TableColumnItems>

              <TableColumnItem>

                <PropertyName>Name</PropertyName>

              </TableColumnItem>

              <TableColumnItem>

                <ScriptBlock>

                  "$($_.Size) Bars"

                </ScriptBlock>

              </TableColumnItem>

            </TableColumnItems>

          </TableRowEntry>

        </TableRowEntries>

      </TableControl>

    </View>

  </ViewDefinitions>

</Configuration>

‘@

 

Set-Content -Path $FormatFile.FullName -Value $FormatXml

Update-FormatData -PrependPath $FormatFile.FullName

Once we have our pseudo-type’s formatting set up – we can create object and add this types to $Object.PSTypeNames:

2, 10 | foreach {            
    $Out = New-Object PSObject -Property @{            
        Size = $_            
        Name = "Foo $_"            
    }            
    $Out.PSTypeNames.Insert(0,'Foo.Bar')            
    $Out            
} | sort Size            

Output will look like that:

FormattedSize

It gives us full control over object’s formatting, and obviously show it’s value mainly in more complex applications. Here – adding optional parameter to show numbers would be enough IMO. What is not enough – is leaving data nice, pretty and – frankly speaking – useless. So if you don’t want to dig into solutions that require some extra work – leave all information you have for future user. If he won’t need raw data, he can always cut it later. No need for you to do that for him. Smile

“Format-{0}”–f ‘List’

Today I would like to write few words about why you shouldn’t work too hard with creating output when PowerShell can do the work for you.

Scripting, as I see it, is a way of taking stuff that “is there” and force it to do my job in a way I want it to be done. If there is something that will do job for me – I will use it. If not – I will create it. So my role is just to build the bridges, not whole road next to the old one.

Obviously, at times you do not know that road already exists. That’s where stuff like Scripting Games help a lot. I for one learned few neat tricks already. But if you fail to see highway and claim to be advanced scripter – be warned, I won’t praise your rocky road that you’ve created next to it. To the point.

Old habits die hard

In VBScript days (but also in cmd days) we, scripters, had to work hard to create decent output. Create tabs, newlines and pray for string in variables to be short/ long enough to get what we expected. One exception to what we seen in tests and we were doomed. OK, maybe not doomed, but not happy with end result either.

We also had to use some fancy techniques to merge output with variables. No way to easily “inject” variable into pre-formatted string. Nightmare.

So it probably should not be a surprise to see the same patterns in PowerShell scripts. I’ve seen that a lot during last few days when reading script both from beginner and advanced category. Luckily – most people know already, that PowerShell is not only powerful in getting data – it’s pretty strong in formatting it. But I’ve seen enough of VBScript-style work to feel that some broader comment on this topic may be needed/ helpful. First – lets talk a little bit about data injection.

Magic of –f operator

PowerShell is based on .NET. What it means? It means we can format data pretty easily. It can be DateTime, integer, regular string – not important. We can move things around, fix width, align left of right – you name it. So if you creating some output message like that:

"Foo is: " + $foo + " and bar is " + $bar            

… you are – in my opinion – doing it wrong. Even if you use put variables in the middle of the string (including subexpression syntax for accessing variable properties), you still not taking full advantage of what PowerShell has to offer.

OK, critics are valuable only if they are constructive. So what alternative do I have for you? Take a look at this line:

"{0:G}.$.$.{1:P2}.'.'|{2,-10}|{3,10}|" -f (Get-Date), (1/3), 'Alfa','Beta'

Would it be hard to guess output? Well, things we have in {} are anchors, they will position things in our output string. Number inside anchor – is index in parameter list. After colon we choose format (‘G’, ‘P2’) and after comma – position (‘10’, ‘-10’) of data. And where is data? Well, it’s outside our string. So if you ever decide to change it – great – just apply new variable! It’s even cooler than that: you can save this template and apply it as many times as you wish. Well… maybe not this particular, but something like that:

# Somewhere at the start of script/ function we define template...            
$AddColumn = "ALTER Table TableName Add Column {0} {1}"            
            
# And in the middle of process block/ foreach statement:            
Invoke-SqlCommand ($AddColumn -f $Name, $Type)

Easy! Smile  And as you can see you can have whole expressions there. Things like $variable.property just work, commands require extra step. Still: I think this separation makes message like that easier to create, read and maintain.

Format-* to make your objects shine

OK, so we are done with creating single message. But single message is not always what we are after. Most often you have more data to show, and you would like to format it nicely. Obviously, you can use what I mentioned above, or just move your data around to get proper number of spaces here… or [tab][tab][tab] there… Stop!

Really, PowerShell is there to help. But it understands objects. So, what you have to do? Create one. I know at least four ways of creating objects out of the blue, pick one that suits you most. I may comment on it, or don’t like it. But that’s just a matter of taste. End result is the same: you build object, PowerShell will format it for you. One object looks perfect when listed. Dozen – in a table. It’s up to you which you should choose. But don’t rewrite PowerShell formatter. And remember: if you create objects and decide that you want to do something useful with them before formatting (like sort, or select) – you can. If you just generate some strings – you end up with something you will use once. So how would I create object? My favourite technique is to use hashtable:

New-Object -TypeName PSObject -Property @{            
    Alfa = 1            
    Beta = 2            
    Gamma = 'Some data here'            
    Delta = Get-Date            
}

It got even better in v3:

[PSCustomObject]@{            
    Alfa = 1            
    Beta = 2            
    Gamma = 'Some data here'            
    Delta = Get-Date            
    Five = 'So I get a list'            
}            

It has advantage over v2 method: hashtables do not keep order, so objects in v2 are kind of random. As you can see default display changes depending on number of properties, but that just default, you can change end result with Format-* whenever you want. You don’t have to worry too much about lining things correctly: all that will be done by PowerShell in background. You can even take it to the next level with formatting files. Still: first step is to create object. And because there are so many ways to skin the cat – you are not forced to use mine. Smile And if you ever decide you’d rather have table instead of list – you do not have to rewrite whole block of code. Just replace –List with –Table, or other way around. Remember: bridges, not new roads.

Hey! Don’t *break* my pipe!

I’m still pretty overwhelmed with number of scripts this year in Scripting Games. While I’m on my “Mission Impossible” I noticed extensive use of break keyword. I commented on it a lot in Beginner 3, but would like to show you why I do not like this as a way of ending your functions and/ or scripts.

I mean, it’s perfectly fine if you use it with what I will show you today in mind, that is: if you want your function/ script to be destructive and break things when you see an error. But if your function/ script is only getting some info from my system and I won’t get full information (like in Advanced Event 2) without admin rights – why do you break things? Isn’t exit/ return enough in such a case…? Smile

Why it matters?

For me – break is mainly looping construct. It makes sense there, because it will let you specify label for loop that you want to leave to. Meaning: if you have several nested loops and you want to get far out rather than leave current one – break makes perfect sense. If my script will however run another script or function that finishes with break – I’m screwed. Literally: I asked this other guy to check some information, he decided I’m not worthy and killed me in a blink of an eye. Ouch!

Let see it in action.

Function of destruction

Let’s consider two very similar functions: one that breaks things, and another one, that just leaves early if some condition is met. I do not include any condition here, so you have to use your imagination. Winking smile

function Test-Break {            
param (            
    [Parameter(            
        ValueFromPipeline = $true            
    )]            
    [string]$Foo            
)            
process {            
    $Foo            
    break            
    "Not going to happen..."            
}            
}            
            
function Test-Return {            
param (            
    [Parameter(            
        ValueFromPipeline = $true            
    )]            
    [string]$Bar            
)            
process {            
    $Bar            
    return            
    "Not going to happen..."            
}            
}            

OK, we have our two suspects. Now let’s launch some pipeline. As you see – both function support using in a pipe… First, let’s test return:

echo One, Two, Three | Test-Return            

Our results come back as expected. Result of code that should not run are not there… Now let’s do the same with other guy:

echo One, Two, Three | Test-Break            

See difference? But that’s kind of OK: I’ve used your function as the only pipeline consumer, you broke it for me – who cares. But what happens if I put your function as yet another chain element?

echo One, Two, Three | Test-Return | Test-Break            

So you broke my Test-Return too with your code. I hope it was not on purpose? Winking smile But I do not need a pipe for that – if I run your function within mine – it will break too…

Script killers

Scripts are as vulnerable to this as functions: if script runs another script that ends with break – it will simply stop there. You can test it easily with three simple scripts created on the fly with this code:

@'
break
"I did not get here..."
'@ | Out-File BreakMe.ps1            
            
@'
exit 1
"I did not get here..."
'@ | Out-File DoNotBreakMe.ps1            
            
@'
"Start..."
.\DoNotBreakMe.ps1
if (!$?) {
    "Some errors in DoNotBreakMe..."
}
"My script is polite, does not break things. But yours...:"
.\BreakMe.ps1
"That won't run, because you BROKE my script! :( "
'@ | Out-File TestBreaking.ps1            

Run TestBreaking and look at results. As you can see – script flow will stop after BreakMe script. This code shows another advantage of using exit over break: it gives you option to let caller know, that something bad happened (exit 0 –> good, exit 1+ –> bad). Our functions will do the same: if we run them in context of script, it will listen. You tell it to break – it will… Try to run this code and the script it creates and see for yourself:

@'
"Functions will break script too. Not when they politely return:"
Test-Return -Bar 'Foo'
"But when you tell them to break stuff..."
Test-Break -Foo 'Bar'
"Again, I won't get here... :( "
'@ | Out-File TestFunBreak.ps1            

Same applies to breaking pipe: if your script supports it and exits with break – pipeline will stop, if not – it will just continue to work:

@'
param (
    [Parameter(
        ValueFromPipeline = $true
    )]
    [string]$Piped
)
process {
    $Piped
    break
}
'@ | Out-File BreakPipe.ps1            
echo One, Two, Three | .\BreakPipe.ps1

But here exit is as destructive as break: you need to use return if you want to keep things flowing thru your script.

Unbreakable script or how it works…?

The reason why break works as we see here is the fact, that break will go out of boundaries of current caller and look for loop that it could break. We can use it both ways: to avoid being killed by code we do not have control over, or to have a script/ function that will be capable of getting out of loop in totally different script/ function. Examples will make that more clear. First: our unbreakable script:

@'
"Try to break me now...!"
do {
    .\BreakMe.ps1
} until ($true)
"HA! You won't stop me NOW!"
'@ | Out-File Unbreakable.ps1            

Break in BreakMe will break do {} until – and we could not care less: it would stop anyways after first run because of used condition. Winking smile

Next: when it makes sense. Let’s create smarter break-script that will use label to break loop. Next we will see how both BreakMe and BreakTopMost will work together for our cause:

@'
break TopMost
'@ | Out-File BreakTopMost.ps1            
            
@'
"We have few loops..."
:TopMost do {
    "Inner 'do'"
    do {
        .\BreakMe.ps1
    } until ($false)
    "Old script will get out of first do..."
    do {
        .\BreakTopMost.ps1
    } until ($false)
} until ($false)
"And got here, although no break in TopMost loop..."
'@ | Out-File BreakBreakBreak.ps1            

Run BreakBreakBreak – see? Our BreakTopMost looked for :TopMost label, got out of that loop and made it possible to reach end of our script. But that’s on purpose: kind of feel that’s not the case with breaking scripts/ function I’ve seen in Scripting Games… Thus – this post. Smile

1… 2… 3… Testing…

Scripting Games are in more or less middle. They have been huge success  this year – much more scripts that last year, which is awesome! I was hoping I will be able to grade every script submitted, but at the moment it looks like mission impossible… Winking smile

Anyway one thing that I would like to highlight today is testing. Seen many entries where single typo made huge difference, including turning 5/4* script into 1* script. And because with PowerShell we got huge power, and with power comes responsibility – testing is more important than ever.

New shiny toy! Broken!?

Imagine you just bought great new shiny toy. Depending on your interests: it can be new title on XBOX that you were looking for. Or new image processing program. Or script editor. You name it. You start it, your hands are shaking and… boom!

Unexpected token ‘)’ in expression or statement.

Feel that frustration? But let go further. It kind of works, but suddenly your computer turns black and everything stops. Next day you open your… search engine of choice Winking smile to look for the problem and see people that had the same issue. You know, somebody forgot to take off some code that was there to clean one partition. Sadly – it was C:. Oops? Developer had OS on D: and…We are sorry? Terribly Sorry? Hello…?

They test, why can’t you?

Companies that live from developing and selling software test it. Don’t have the numbers, but suspect testing is comparable amount of work and resources as developing is. Microsoft probably tests Word for things like: if it doesn’t start to smell differently if it’s open for too long. Winking smile

Obviously, when you write simple script there is no need to test very long. But you should do a bare minimum: make sure it works, make sure that parameter work as you expect them to. And what is also important: test any component you’ve added to you script. Have GUI? Test how it behaves. Have help included? Run get-help against your function/ script, make sure help displays and all information is included.

But that’s not enough! Also: make sure your script does what it suppose to! Read requirement carefully, not all of them will be mentioned in design points! If you add all bells and whistles but fail to do the job – don’t be surprised to get 1* grade. Coming back to our Word example: imagine word would have Wingding font hardcoded, without option to change it, no option to copy stuff from it. And would work with speech recognition, read your mind and would record your dreams when you are asleep. Perfect tool? Not really, right?

Few last word on comment based help…

PowerShell version 2 added great functionality: comment based help. With minimal work you can add help to your function or script. It would be fair to say probably that writing help for functions is easier than writing it for cmdlet… But it has some limitations to it. Remember – it’s a key to test it because it may look fine, but minor typo in a keyword – and you are doomed. Your great help suddenly turns into yet another comment. Pretty lengthy and helpful for reviewer, not so for user.

Two years ago I had some issues, and because I have tendency to forget things and make typos everywhere – I wrote myself a function to test-help for functions I was creating. It’s not best tool on Earth and I should probably rewrite it, but it should help you find your sensitive spot when you help will fail to work as expected. But you know, you won’t find out that it fails unless you test… Winking smile

Three steps…

OK, now for testing procedure I would suggest. It requires only three steps from you, third one is probably optional.

First – run your code where you are developing it. I won’t convince you to one script editor or the other – you choose your tools. But whenever you change things – test it. That means you really shouldn’t change anything just before you submit your code – making changes in online form is always asking for trouble…

Second step – start powershell.exe –noprofile. If you have v3 installed and even if you assume you are not depending on it in your code – include –version 2 parameter. Really, you would be surprised how many tiny things were changed/ improved in v3 that can cause your code to work here – but maybe not there, on judges PC. Now you are free from modules, variables and other handy tools that your script may depend on without you even realizing it.

Last step – just in case – run it on another computer. Preferably one with clean OS without any tools added. Maybe virtual machine? If it works there, it will probably work everywhere.

Scripting Games are only iceberg peak

Remember – I mentioned all that in context of Scripting Games. But it does not mean you should stop test your code once this event is due. If you ever plan to publish your code – really, include testing in your development cycle. It doubles the work, but triples satisfaction. Not only on your side, but mainly on side of your future users. And remember: your future user includes yourself in few months. So even if you write for your own good – test. It’s just simple as that. Power equals responsibility. Powerful tool – damaging/ critical outcomes of mistakes. You can mitigate them with testing and keep both power, and peaceful dreams. Winking smile

Lights and shades of Scripting Games.

First week of Scripting Games is behind. Well, technically there will be three weeks, but because half of events where revealed, and I’ve completed most of them – I feel almost like at half of ‘active’ part. What comes next is ‘passive’ part – get grades, read contribution from others (can’t wait!), read experts solutions (that should be even better!). At the moment I have mixed feeling about Scripting Games. Today I would like to write more what and why I like so far, and what and why I do not like.

1. Always look on the bright side…

Events so far where just great. I mean they were great last year too, but I really had fun playing with some concepts. And even though I’m always for objects, I managed to get it ‘my-way’ even for events that required me to produce text. This is the brightest part so far.

Another cool thing was the interaction with others – when I competed last year I was not really social. No twitter account, no facebook account. I can’t even recall any interaction on IRC channel (but that I’m not sure – it’s possible I was already common visitor there already). This year it is different story. I still do not have facebook account, but Twitter + IRC is more than enough for me.

Another thing I like about this games is confidence in what I do. I really know how. Judges may disagree (we get to that) but I really see big improvement over last year contributions. I see clearly that there is very little things I can not do. And Scripting Games are also here to help: I see those gaps more clearly and maybe one day I will be able to get rid of those too.

Last but not least: chance to work without being directly influenced by script from others. I really thing it was great idea. I mean if I can not find a way – it always helps to see hot others did it. I did it like that last year for few events. But being forced to ask, and dig, and google, and Technet-things really makes it more… memorable? I forgot some things last year soon after SG was over. I do not expect it to happen this year though. Took me quite some time to find a ways for some tasks assigned by Ed.

2. If life seems jolly rotten…

No to the dark side. Judging. I’m really confused, because of it. I mean I look at list of judges and I really see only smart people, devoted to community and such. But I really can’t resist impression that at least few don’t know rules for the game they are taking part in. We (contestants) were told to read rules if we disagree with notes. But 2nd event, I got 1 star for, is in my opinion proof, that this goes in both directions. Basically 1 star means I submitted script that does not do the job. Is it the case? Let see, my grade:

SG-Fail_1

So what result will you get if you simply run my script? Error? Some bogus info that has nothing to do with assigned task? Take a look:

SG-Fail_2

I was worried that it worked fine because I had my laptop fine-tuned. Than I thought I simply made mistake when I was copying it to PoshCode, so I’ve downloaded it to ‘clean’ machine, saved it, run it from PowerShell.exe –NoProfile –ExecutionPolicy Bypass (had to, cause this computer had default execution policy). And what I see is what I would expect to. So what’s up? And there is more than that. With my script you can query excel, AD, SQL, use local file – we were required to do only one, but with used technology (ADO.NET) I could connect all. I made it as reusable as I could. I wrote this script in a way that insures that I get only servers from AD (+1 design point). I would expect at least 3 points, maybe more (comment based help, parameter sets, error handling). But judge thinks I submitted something that does not work. Great. I would expect at least some comment for such low grade, but it was probably too much work…

3. Just purse your lips and whistle – that’s the thing.

Boe Prox wrote very wise sentence regarding issues like this one on Twitter:

“Remember that as long as you did your best on your script and are happy with what you did, then grading should be secondary.”

Last year I was green and was happy with any grade higher than 2. This year I feel I’m good and everything less than 5 is probably reason to be disappointed. But the grades are not that important. Sure, it probably means I won’t be able to repeat my wonderful score, and be 3rd. But the most important part is fun, learn and improve. If you are upset with grades – do as I did – ignore them! If you feel it’s time to quit and you are forced to by 2* for script that does it all and is just pure PowerShell orgy of parameter sets and well written and pipeline friendly functions – ignore 2*, go on and write next script that will be as good as this one. It’s always in eye of beholder, and just because you feel that judge should give you at least 4 – don’t stop rockin! ;) I jumped in again and re-written my profile to remind me of time remaining until end of each event. For ISE – it will show me only first one that is not yet done in the title. In PowerShell.exe (where I test it all, because ISE sometimes loads some additional assemblies on-the-fly and script tested there may fail in PowerShell.exe) I do even more – header with all ‘active’ events. Some code at the end of this long post – that’s how I whistle, I whistle Verb-Noun. :)

$2011sg = @"
"EventDeadLine","Event","Status"
"11 April 2011 12:15 AM","1","DONE"
"12 April 2011 12:15 AM","2","DONE"
"13 April 2011 12:15 AM","3","DONE"
"14 April 2011 12:15 AM","4","DONE"
"15 April 2011 12:15 AM","5","WAIT"
"@              
            
function Measure-TimeRemaining {            
param (            
    [Parameter(ValueFromPipeLineByPropertyName = $true)]            
    [datetime]$EventDeadLine,            
    [datetime]$Time = $(Get-Date),            
    [Parameter(ValueFromPipeLineByPropertyName = $true)]            
    [int]$Event,            
    [Parameter(ValueFromPipeLineByPropertyName = $true)]            
    [string]$Status            
)            
process {            
    $Span = New-TimeSpan $Time.ToUniversalTime() $EventDeadLine.AddHours(8)            
    if ($Span -gt 0) {            
        "Left: {0} days, {1} hours, {2} minutes to the end of Event {3}! <== {4}" -f             
        $Span.Days, $Span.Hours, $Span.Minutes, $Event, $Status            
    }            
}            
}            

And part of prompt that will always show me info about deadlines at the top of PowerShell.exe window:

function prompt {            
    $FillSpaces = $Host.UI.RawUI.WindowSize.Width -1            
    $OldPosition = $Host.UI.RawUI.CursorPosition            
    if ($OldPosition.Y -le 5) {            
        $OldPosition.Y = 6            
    }            
    $FromTop = $OldPosition.Y - $Host.UI.RawUI.WindowSize.Height + 1            
    $Y = [math]::Max(0,$FromTop)            
    $host.UI.RawUI.CursorPosition = New-Object Management.Automation.Host.Coordinates 0,$Y            
    $2011sg | ConvertFrom-Csv | Measure-TimeRemaining | ForEach-Object -begin {            
        $i = 0            
    } -process {             
        Write-Host $("$_" + " " * $($FillSpaces - $_.Length))            
        $i++            
    } -end {            
        $i..5 | ForEach-Object { Write-Host $(" " * $FillSpaces) }            
    }            
    $host.UI.RawUI.CursorPosition = $OldPosition            
    $host.UI.RawUI.CursorPosition.X = 0            
    <# The rest of profile goes here... #>            
}

And that how it looks like:

SG-WhistleSo – last quote from Monty Python’s song:

You know, you come from nothing – you’re going back to nothing.

What have you lost? Nothing!

And there is really A LOT you can gain from Scripting Games. Even if you disagree by far with number of stars drawn by the judges on the sky of your scripting excellence. ;)

Scripting Games 2011 – be prepared! :)

Only 12 days to Scripting Games 2011! Be prepared!

Why would I care?

If you like PowerShell, and like to learn, and like to have fun doing both – Scripting Games are there for you. If you are just starting – read awesome posts co-authored by Scripting Wife and try it with beginner division. If you are scripting a while already and feel that you can do more than solve simple tasks – there is division for you (us… :D ) as well! If you are worried what good can you get from solving some fictional problems – take a look at last year’s scripting games. Do you see something that will never-ever happen to you? If you are admin you probably had such and/ or similar problems on your plate in the past. Wouldn’t it be great to have skills required to automate solution next time they will come? And trust me, knowing techniques when you need a prompt solution is good thing. Learning new things while your head is on fire is straight way to heart attack or something worse than that… ;)

Where do I start?

The best place to start is 2011 Scripting Games: All Links on One Page article on Hey, Scripting Guys! blog. You will get there from any other blog that is supporting Scripting Games. All you need is click on Mr Scripto. Suspect looks like that and is wanted alive:

2011 Scripting Games

Grab this badge here!

You will see all articles tagged for Scripting Games there. :) I would suggest starting with study guide, and don’t miss any of ‘Scripting Wife’ articles. Even if you knew ‘all that’ already, it’s really fun to read.

But you see… I’m busy around here?

If you reading this you probably know that PowerShell is there to make your life easier. So… First of all you can make title of your PowerShell window remind you about days left till Scripting Games will start:

$Host.UI.RawUI.WindowTitle = "Only {0} days to Scripting Games!" -f (New-TimeSpan -End '4/4/11').Days

If you live in a PowerShell.exe you may want to have it your prompt, so you won’t miss it:

function prompt {            
<#
    Whatever you need goes here, eg:
#>            
    Write-Host "$pwd To SG: " -NoNewline            
# piece of code to produce info about days to SG with proper colour. ;)             
    $DaysToSG = (New-TimeSpan -End '4/4/11').Days            
    switch ($DaysToSG) {            
        { $_ -lt 3 } { $Fore = 'Red'; break }            
        { $_ -lt 7 } { $Fore = 'Yellow'; break }            
        { $_ -lt 12} { $Fore = 'Green'; break }            
        default { $Fore = 'Gray' }            
    }            
            
    Write-Host $DaysToSG -Fore $fore -NoNewline            
# and close the prompt in a way you want it to be closed, such as '> '            
    return ' > '            
}

ScriptingGames

As you can see mine is a bit different (that’s because I’m using Jaykuls prompt function) – but it tells me how much time left. I could use calendar for that too, but well… I prefer to see every day how this number decreases. The reason is simple – I can’t wait when the Scripting Games will start! :)

Episode 117 of PowerScripting Podcast.

Friday, middle of the night. Got to work, got fresh cofee, write down my questions I was thinking about for about month. And then it all started. Yes, I’ve enjoyed it. Every single minute of it. :) Maybe didn’t asked everything I wanted to, but that was not the point. I had a chance to speak to Jeffrey, Ed, Hal and Jonathan. It was surely grand prize for me. If I would get TechEd pass I would not use it – price of the trip to US, hotel, week off… I would be sad and sorry. But 1 hour call to US is totally different story.

I hope Polish listeners of the Podcast won’t hunt me for calling us (Polish PowerShell users) mutants. ;) Forgive me, it was not exactly what I was going to say… :D And for those who listened to the podcast and have no idea who this Witcher is, two links:

English version of book on Amazon.com

The Witcher (game) official website

Back to the podcast: I’m glad that I mentioned few things: challenges (I guess Scripting Wife is somewhat right that answering peoples questions on forum is something like that, but I would prefer some spirit of competition that such forum answers should not bring). Naming – I’m not all that sure that scripts should use verb-noun, but I somehow like the idea, and I think that Jeffrey was closer to the point in that area. BTW: there is a way to suppress warning about names when you load a module:

PowerShell, using GeSHi 1.0.8.8
  1. PS C:UsersBartekB> Import-Module .Test.psm1
  2. WARNING: Some imported command names include unapproved verbs which might make them less discoverable.  Use the
  3. Verbose parameter for more detail or type Get-Verb to see the list of approved verbs.
  4. PS C:UsersBartekB> Import-Module .Test.psm1 -DisableNameChecking
  5. PS C:UsersBartekB>

But you can not be sure that everybody will use that parameter, so you better watch out and name your functions with the –verbs you get-

And that leads me to last thought I would like to share: it would actually help to add one more property to get-verb results: alias prefix. I’m almost sure that those are common, and all imports aliases are ip(noun-part), exports are ep(noun-part) and gets are g(noun-part), and so long, and so forth.

And last but not least: hearing Jeffrey’s passion about the product is almost like listening to the parent, so without any doubt you can call Powershell “his baby”. It was a real fun to listen to it live, to interact with it in a way I had never chance before (and probably will not have in future). Definitely a day to remember. Now I wait for final version of this episode so that I can download it and save it somewhere for my descendants… ;)

CMD and SG 2010 – Part 5.

This is today… Today I will have a chance to speak to THEM. Good day to finalize my series. Not the best day to do shopping, since my bank card expired. ;) So no real breakfast today.

Last two events were not very hard, but I had two problems to move them to CMD.

Event 9 required array manipulation but… there is no array in CMD! So what should I do? Well, I tried to ‘pretend’ I was playing with arrays. So it’s not a script I could easily defend. Probably one star only. ;)

CMD, using GeSHi 1.0.8.8 – Beginner Event 9
  1. @echo off
  2. SET Arr1=a b c d
  3. SET Arr2=d e f g
  4.  
  5. echo Array 1 = %Arr1%
  6. echo Array 2 = %Arr2%
  7. set Arr3=
  8.  
  9. call :Conc %Arr1%
  10. call :Conc %Arr2%
  11.  
  12. echo Final Array = %Arr3%
  13. goto :EOF
  14.  
  15.   :Conc
  16.   if [%1]==[] goto :EOF
  17.   echo %Arr3% | findstr /r "%1," > nul || (SET Arr3=%Arr3%%1, & echo %1)
  18.   goto :Conc
  19.  

Second was even harder: how to debug .vbs or .ps1 when I use cmd only? I decided to take other route: OK boss, I’m not fluent in either, I will get your message box in cmd, and leave those broken scripts alone. ;) There is no ‘silentlycontinue’ in cmd (unless you redirect 2> nul) so if I hit error – I will know it. So that’s what I came up with:

CMD, using GeSHi 1.0.8.8 – Beginner Event 10
  1. @echo off
  2. for /f %%M in (‘wmic ComputerSystem Get UserName ^| findstr /r ".*\.*"’) do @SET msg=%%M
  3. msg %USERNAME% %msg%

See? Message box as you expected. Title may be a little confusing, but who would read title in a window like that? ;) So again: not exactly what Scripting Guys asked for, but I had to limit my self to command line tools only.

And now I have few long hours ahead. I plan to get to bed early and today (tomorrow my time) wake up in the middle of the night, drive to work (so that I would not wake up my family while recording podcast). So two big issues ahead of me: how to concentrate on what I’m doing when at work, and how to fall asleep when at home. ;) I usually go to bed around 1-2, so it may be a real problem. So plan B is stay at home, and call podcast team from bathroom ;) Will see how it all works out for me.

CMD and SG 2010 – Part 4.

Monday at my door and I’m really worried about it. Deadline is approaching and we have no chance to meet the goal. I hate it when somebody is leading a project in a way, that prevents members from doing things in a proposed schedule. Anyway, Thursday is pretty close so I’m slowly getting excited. And still 4 scripts to go in my cmd series. So here is the one that took me most of time to figure out, mainly because both in VBS and in Powershell it was usually done with COM object, and I have no idea how to use those in CMD. But then I thought, that this type of information has to be in the registry somewhere, looked for it a while, and – there it was. :)

CMD, using GeSHi 1.0.8.8 – Beginner Event 7
  1. @echo off
  2. set /a Counter=0
  3. set AdminPath=Empty
  4. for /f "delims=" %%A in (‘reg query "hklmsoftwaremicrosoftwindowscurrentversionexplorershell folders" /v "Common Administrative Tools" ^| find "Administrative Tools"’) do call :ProcessResult %%A
  5. for %%F in (%AdminPath:~0,-2%*.lnk") do call :CountAndDisplay "%%~nF"
  6. echo Done! Total %Counter% items . . .
  7. goto :EOF
  8.  
  9.   :ProcessResult
  10.   if [%AdminPath%]==[Empty] (
  11.     if [%1]==[REG_SZ] (
  12.     set AdminPath="
  13.     ) else (
  14.       shift
  15.       goto :ProcessResult
  16.     )
  17.   )
  18.   :JoinPath
  19.   if [%1]==[] goto :EOF
  20.   set AdminPath=%AdminPath%%1
  21.   goto :JoinPath
  22.  
  23.   :CountAndDisplay
  24.   echo %~1
  25.   set /a Counter+=1
  26.   goto :EOF

I’m almost sure there is easier way to get only path from reg output. But this one works too, so I do not really care. ;)

Script # 8 was easier to write, but I still seem to have some problems with output. Anyway – it works better than I would expect, so I left it like that.

CMD, using GeSHi 1.0.8.8 – Beginner Event 8
  1. @echo off
  2. echo Process Owner
  3. for /f "skip=1" %%I in (‘wmic PROCESS where "Name!=’wmic.exe’" get ProcessID’) do call :GetOwners %%I
  4. echo Done!
  5. goto :EOF
  6.  
  7.     :GetOwners
  8.     SET ID=%1
  9.     for /f "delims=" %%P in (‘wmic PROCESS where "ProcessID=’%ID%‘ and name!=’wmic.exe’" get name ^| findstr /r /v "^$ ^Name"’) do (
  10.       set Process=%%P
  11.     )
  12.     for /f "tokens=2,3 delims=;= " %%O in (‘wmic PROCESS where "ProcessID=’%ID%‘ and name!=’wmic.exe’" call getowner ^| find "User"’) do (
  13.       set Owner=%%~O %%P
  14.     )
  15.     echo %Process% %Owner%
  16.     goto :EOF

As you can see most of stuff is done with usage of wmic.exe – pretty handy tool I must admit. Even if gwmi is easier to use and remember. ;)