There’s a lot that can be achieved in a little bit of PowerShell (a single (pipe)line, even), and that brings with it a tendency to throw a solution together quickly. As the saying goes, though, with great power comes great responsibility, so you need to be careful.
Using -whatif and -confirm can help you to avoid hanging yourself, but you also need to do more thorough testing before you put a script into production (and yes, I’m talking to myself as much as anyone else here).
For example, I have tripped over a problem (and I know others who have done the exact same thing), where I wrote a PowerShell script that altered some objects in Active Directory. I had some dummy objects to test on and after a few itterations I had a script which manipulated them in just the way I wanted. I changed my input to the appropriate set of live objects and it all worked. Brilliant.
The trouble occurred when the script was run subsequently on a different set of input which referred to some objects which had previously been removed from Active Directory. I hadn’t tested the script with any input that referred to objects which didn’t exist. If you’d asked me ahead of time, I probably would have said that I’d expect the script would just ignore those rows in the input file. Most of the time that’s probably what would happen…
…except in this particular case, when no exact matching object was found, it dropped back to a WILDCARD MATCH!!! Cue a bunch of objects that shouldn’t have been touched, getting messed up in some inconvenient ways! 🙁
The first time this happened, it had everyone utterly perplexed. It was fixed with no understanding of the cause. The second time the same script did the same thing we worked it out, fixed the mess and the script. I subsequently saw a similar script create a similar problem for someone else, and I was able to help him remediate that situation before anyone noticed.
What those experiences hammered home for me was the need to formulate test input for my scripts very carefully. Don’t get me wrong, this wasn’t news for me, as I’m sure it isn’t for you, but the awareness of how much worse things might have been in those semi-disasters has helped me to formulate better testing, and I’m pleased to say that I haven’t had an avoidable problem caused by one of my scripts since then.
So, if there’s any chance that your script is going to face anything unexpected in the future, you need to test for it, and perhaps including some input cleansing in there. In your test input you should include some stuff that’s fine and your script shouldn’t alter, some things that your script should operate on, some duplicates, some things that don’t exist, and some stuff that just plain make no sense. Try to break it as much as you can (although be careful where you’re running it!).
Oh, and if there’s any chance that someone else may run your script in the future, make sure that you document what you know it works for, and what you haven’t tested. There might not be a need for you to test for every possible outcome today, but you don’t want someone coming and knocking on your door blaming you for something that you didn’t do, but didn’t test for either. You can at least make people aware of the scenario that you did test for, and let them know that you didn’t check that it wouldn’t blow things up if they decided to run it as domain admin instead!