PowerShell Quick Tip: Setting AD object attributes with ScriptBlock parameters

In PowerShell you can pass pipeline data to parameters that are not configured to accept pipeline input using ScriptBlock parameters.  This has been discussed before and it is well worth your time to make yourself familiar with that capability of PowerShell because it allows you to create true one-liners in places where you might think you cannot.  Basically it boils down to this: you can pass a script block into parameters in a cmdlet that is not of type script block and within the script block you provide the $_ variable will contain the object that was just passed down the pipeline.  The script block will be evaluated first, and then the result will be passed into the cmdlet parameter.

Still, even with that knowledge in hand people often trip over the ScriptBlock parameter syntax when using a parameter that takes a hash table (aka an associative array) as input.  The most common example I can think of where this is encountered is in the Quest AD cmdlets.

Many of the Quest AD cmdlets have a parameter called ObjectAttributes.  This parameter serves two purposes: in Get cmdlets it is used to define the values you want to filter on; in Set and New cmdlets it is used to define the values you want to assign to specific attributes.  Not consistent, I know, but that’s a whole other discussion.  In both cases the ObjectAttributes parameter is a hash table and to use it you simply need to define a hash table that matches attribute names with values.  Here’s an example showing how users trip over the syntax without realizing it:

Get-QADComputer Comp1 `
    | Set-QADObject -ObjectAttributes ` 
        @{userAccountControl=$_.userAccountControl -bxor 2}

This one liner was designed to enable or disable a computer object in AD.  It will run without raising an error, and it will even enable or disable the computer object, but it will not work like you might expect.  After running this command the userAccountControl attribute (which contains many flags, not just a flag for enabled/disabled state) will not be properly configured.  Why?  It looks like it is properly using a ScriptBlock parameter, but it is not so the $_.userAccountControl value will either evaluate to 0 if the $_ variable is null or if it does not have a userAccountControl property, or it will contain the userAccountControl value from whatever object the $_ variable contained before you called Get-QADComputer in the first stage of this pipeline.  Nothing in this command instructs PowerShell to treat the ObjectAttributes parameter as a ScriptBlock parameter.  So what’s missing?

The most important thing to remember about ScriptBlock parameters is that they always must be surrounded by script block enclosures (“{“ and “}”).  Otherwise they are not script blocks.  In our example above it looks like the parameter is surrounded by the proper enclosures, but that’s not true.  It’s surrounded by hash table enclosures (“@{“ and “}”), and this is what trips people up when working with this syntax.  To make this be properly treated as a ScriptBlock parameter, we need to surround the hash table with curly braces, like this:

Get-QADComputer Comp1 `
    | Set-QADObject -ObjectAttributes ` 
        {@{userAccountControl=$_.userAccountControl -bxor 2}}

That makes PowerShell recognize that we have a ScriptBlock parameter and the $_ variable within it properly evaluates to the object that just came down the pipeline.  No ForEach-Object or temporary variables required.  It seems simple enough when explaining it but you’d be surprised how many people get tripped up on this syntax.

If you want to see some forum discussions where this has been an issue for others, you can go here or here.

Kirk out.

Share this post:

Leave a comment