Tuesday, July 31, 2012

What If Mode - Adding WhatIf to Scripts

What if mode is one of my favorite features of PowerShell.  No other language I have used has given me this ability, and it is very exciting and useful.  You probably already know that -WhatIf will describe the action that would take place rather than actually doing it.  How then can one use it in a script?  It takes a few steps.


First, add the code [CmdletBinding(SupportsShouldProcess=$true)] immediately before the Param statement. This unlocks -Whatif and other common parameters.  Next, wherever you are going to perform an operation that would change something, such as to move an AD account, enclose the commands(s) in an if statement with a condition like this:

if ($PScmdlet.ShouldProcess("Move Account $($child.cn.toString()) to OU $($disabledOU.ou.toString())","","")) {
    $child.MoveTo($disabledOU)
}


The $PSCmdlet.ShouldProcess() method takes many arguments, but the one I use the most takes first a string describing the action and the object, followed by two empty strings.  The execution of this method will respond appropriately based on whether WhatIf is on or not.


There is a lot of potential here, and I encourage you to explore it!

Monday, July 30, 2012

Set Boolean Switches

I was excited when I read in the Get-Help about_commonParameters article that one can set true or false on a switch parameter.  Previously, I thought that it was false unless specified.  Now I see that if one adds a colon and a Boolean variable, then the switch can be set to false even when specified.  It looks like this:

restart-computer -whatif:$false

There were several cases when I didn't know whether I would need a switch or not, and I had convoluted code to form an expression which I would then invoke.  Now it is much cleaner.

So reading those long about_* articles does have its benefits!

Thursday, July 26, 2012

Creating Custom Objects

PowerShell is all about being object-oriented.  Once I learned how to create custom objects, then I really started having fun.  One can add custom properties to either a "blank" object or an existing object (which is cooler). 


To do so, either start with the existing object or a new-object system.object.  Then pipe it to add-member.  Add-member takes a -membertype, then the -name of the property, and finally  the -value.  


The top-three types that I use are as follows: 

  • noteproperty for a "static" value; the value is whatever, can be in parentheses
  • scriptproperty for a "dynamic" value, a code block; use $this. to reference the object
  • aliasproperty for another name for an existing property; the value is just the name of the existing property

I have had much success with add-member in my scripting. I cannot explain it all here, but I hope it whets your appetite!  Remember to use get-help add-member -detailed.

Monday, July 23, 2012

Generating Terminating and non-Terminating Errors

Maybe you know that PowerShell has two kinds of errors: terminating and non-terminating.   The question is how to generate these in a script.  Write-Error generates a non-terminating error, but throw generates a terminating error.  Of course, one can specify the -erroraction to override.


More on errors: 
There are often several non-terminating errors if one runs get-childitem c:\windows, because wherever one does not have access, an error appears, but the "getting" continues.  The terminating error brings execution to a halt, so  get-childitem c:\windows -erroraction stop would end all further code execution  at the first "access denied" (unless Trap or Try/Catch is used).

Friday, July 20, 2012

Select Object Expand Property

Many times over the last year, I have wanted to get a specific property of an object, but I didn't have the exact object, just results from a cmdlet like Get-Acl.  So I would wrap the rest of the code in parentheses and write . and the property name.  Not my favorite thing to do.  Example:
(Get-Acl p:).access


I recently learned about Select-Object having an -ExpandProperty.  This means that instead of the parentheses, I can pipe to Select-Object -ExpandProperty, like so:
Get-Acl p: | select-object -expandproperty access


While it takes more words, I like it because it preserves the forward flow and means I don't have to go back and add parentheses.  This is a simple case, but I hope it illustrates my point.

Thursday, July 19, 2012

Accessing the Registry by String

PowerShell has its own shortcut syntax for accessing the registry HKEYs, like hkcu:.  It is part of the system of providers and psDrives.  But other programs deal with the whole HKEY name, like hkey_current_user.


I just learned that in a registry path string "hkcu:\" is equivalent to "registry::hkey_current_user\".  So if you have a long path for a registry, just tack on that "registry::", and you'll be fine.  This is also necessary for any registry HKEYs that don't have abbreviations, as HKCU and HKLM do (unless you make your own PSDrive).  

Variables in PowerShell Strings

One of the amazing things about PowerShell compared to other scripting languages (VBScript) is its ability to resolve variables within strings.  (http://technet.microsoft.com/en-us/library/ee692790.aspxCalled variable expansion, this new feature looks to make concatenation a thing of the past.  Furthermore, with PowerShell's handling of double versus single quotes, there will no longer be cases of writing four quotes just to get one (escaping a quote with a quote).


However, one thing tripped me up for the last year, until I learned the answer from training with Ashley McGlone. (http://blogs.technet.com/b/ashleymcglone/about.aspx)  The variable expansion didn't help when accessing a property or method of an object, or item in an array.  So I would have a lot of "$a" + $b.toString() + "c" for example.  Then, he showed me the secret:


In a string, I can use $(), and put whatever code I want into it, even an if statement or code block!  So the previous example becomes "$a$($b.toString())c", which is much more compact.  Furthermore, PS3 ISE will color the items in parentheses as variables and members instead of red like strings, making it easier to see what is going on inside them.


One more reason I really enjoy PowerShell!

Auto-Indenting in PowerShell ISE

Just learned a very amazing thing about the PowerShell ISE (including from PS2)!  If one selects multiple lines, then pressing tab will indent them all.  Pressing shift+tab will un-indent them all.  
This is so wonderful! I don't know how many times over the last year I added an if or try block, and I either manually spaced all the lines or just left it alone.  Now, it takes two seconds, and my code looks amazing!