Accommodate or Dictate Your Scripts
I’ve been thinking a lot about this lately. What, you ask? How to approach writing a script or advanced function. Most of the time I’ve always in the accommodate world, where I try to imagine every scenario that might happen and account for that in my script. But is this the right approach? Should I instead simply dictate that this is how you use the script? A lot of people do it (VMware requires Connect-VIServer before you do anything). Should I start doing the same?
It’s pretty intuitive that a script that anticipates everything you may do would be pretty easy to use, right? It makes for a lot of work, and the scripts can get pretty complicated, but UX is high? Isn’t it? I’m not so sure anymore. They work in a lot of different ways, but sometimes that confuses people even more. “How do I use it? Anyway you want.” Not a really satisfying answer.
The alternative is to write the script in such a fashion that they must be run a certain way This certainly limits choices for the user but a script that uses object output can avoid a lot of this by simply letting the user decide what to do with their data and not worrying about making sure they do it right. This second approach both appeals and appalls me. It appeals to my dominant, nit-picky side because I can make sure you do things correctly (at least my interpretation of correct). But it appalls me in the way that I have no idea how people might want to use this script, and who the hell am I? But lately I’ve been finding myself leaning this way because it simplifies my code and frankly embraces some basic tenants of PowerShell. The idea that a script does one thing, one thing only and if you want to do more you pass it down the pipeline to the next script, which in turn does one thing and so on.
This recently applied to a module I’ve been working on at athena. The SQL.Automation module has several functions in it all relating to SQL. The primary function, and if you know me you know this, is Invoke-SQLQuery. But there are several other functions that all work with SQL Availability Groups, Get-AGCluster, Get-AGDatabaseState and Get-AGReplicaState–there’s also a Set-AGClusterFailover but it’s not 100% yet (so close!). The three “Get” functions all retrieve different information from the Availability Group and when I originally wrote them they all gathered all of the AG information they needed independently. This worked, of course, but required a lot of work on my part. So I started working on “version 2” that simply leveraged Get-AGCluster (which did everything I needed anyway) and this is where I started to hit me. I had all kinds of code in there to determine if I needed Get-AGCluster, why not just require the use of Get-AGCluster? Setup pipeline and all of the other Get-* commands would work great with Get-AGCluster information coming down the pipe. And it really worked, what was going to be a long rewrite process suddenly went very quickly, since I had all the information I needed from the Get-AGCluster the other scripts essentially became loops with SQL queries retrieving the specific information that they needed to.
I think going forward I will probably go this route. I’m also beginning to think I should publish the SQL.Automation module.
I’m really curious what you think: Accommodate or Dictate in your Scripts? Comment and chime in your thoughts.
It really depends on what the goal of your script is. Right now, I’m immersed in writing scripts for our auditors who are specifying 1) data must be collected and presented by automation in order to verify that no human has manipulated it; 2) you must be able to verify completeness and accuracy; 3) you must be able to generate a report on demand (i.e., in the presence of an auditor). The issues relate mostly to applications and servers and services that affect revenue and include items like who did it; who authorized it, when was it done, what was done, when was it done, who has access to it, what access do they have, and more. This class of scripts have to be complete in themselves, users can only invoke them, they can’t have command line options or query the user for options. So they fall in your class of must run this way, and besides the auditors, management here seems to like it that way, too.
Lots of Linux tools and The C Programming Language built-in (std.) functions were written with the idea `Do one thing and do it well.’
Doing one thing absolutely right makes it useful as a recipient of output or a source for input to other functions and functionality.
Sometimes, smaller is better.