Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Active Directory Objects and the PowerShell Pipeline

Posted on September 28, 2020September 30, 2020

This article is something I've been meaning to write for sometime. As often as I tell people PowerShell is easy to use once you understand its core concepts, that isn't always the case.  This is a problem my friend Gladys Kravitz brought to my attention some time ago.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

Like her, you probably have written a PowerShell function like this that accepts pipelined input.

Function Get-Foo {
  [cmdletbinding()]
  param(
    [Parameter(Mandatory, ValueFromPipelinebyPropertyName)]
    [string]$Name
  )

  Begin {}
  Process {
    Write-Host "working on $Name" -ForegroundColor Green
  }
  End {}
}

This sample function looks at any incoming object, and assigns the Name property to the Name parameter. You can see the results with a simple test.

Get-Service bits, winrm | Get-Foo
working on bits
working on winrm

This function isn't doing anything other than displaying the value of the $Name parameter. Let's take a step forward.

Here's a simple function to get the BITS service that takes pipeline input for the Computername.

Function Get-Bits {
  [cmdletbinding()]
  param(
    [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
    [alias("Name")]
    [string]$Computername
  )

  Begin {}
  Process {
   Write-Host "$Computername" -ForegroundColor yellow
   Get-service -Name bits -ComputerName $computername | Select-Object Machinename,Name,Status
  }
  End {}
}

This works mostly as expected. I can specify a parameter value. I can also take input from the pipeline by property name.

get-bitsBut not with an Active Directory object.

get-bits-errorThis is where Gladys started wondering what she was doing wrong. Clearly, the object has a Name property, because this variation works as expected.

get-bits-byname

It was time to see what was really happening. By the way, if you pipe the Get-ADComputer command to Get-Member, PowerShell will tell you the Name property is a String.

To dive deeper, we turned to the Trace-Command cmdlet. You definitely want to read help and examples. In our case, we needed to see what PowerShell was doing with parameter binding.

trace-ADCommand

There's a lot to take in. As I scrolled down and got to the Get-Bits function, I noticed what PowerShell was doing with parameter binding for Computername.

trace-ADCommand.-bindingjpg

PowerShell wasn't seeing a string. It was seeing an ADPropertyValueCollection, which it couldn't convert which results in an error.

trace-ADCommand.-errorWith this tidbit of information, I revised my sample Get-Bits function.

Function Get-Bits {
#revised version
  [cmdletbinding()]
  param(
    [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
    [alias("Name")]
    [object]$Computername
  )

  Begin {}
  Process {
    write-Host "processing type $($computername.GetType().fullname)" -ForegroundColor yellow
    [Microsoft.ActiveDirectory.Management.ADPropertyValueCollection]::new($Computername)
    switch ($computername.GetType().fullname) {
      "system.string" {$cn = $Computername}
      "microsoft.activedirectory.management.adcomputer" {$cn = $computername.name}
      "Microsoft.ActiveDirectory.Management.ADPropertyValueCollection" {$cn = [Microsoft.ActiveDirectory.Management.ADPropertyValueCollection]::new($computername).name }
      default { $cn = $Computername.computername }
    }
    write-Host "working on $cn" -fore Green
    #  Get-service -Name bits -ComputerName $cn | Select-Object Machinename,Name,Status
  }
  End {}
}

I need to pay attention the type of object I'm getting for Computername. I can't assume it will be a string. I want to verify my theory.

adproperty

Gladys, and most people, was assuming that the AD Object property was a simple thing, like a String. But clearly it is not. I can also infer from testing, that Select-Object plucks the property from collection and uses it to created the Selected.Microsoft.ActiveDirectory.Management.ADComputer object.

Now that we know this, I can revise my sample function to better accommodate pipeline input from an Active Directory cmdlet. This will require the use of parameter sets.

Function Get-Bits {
#with parameter sets
  [cmdletbinding(DefaultParameterSetName = "byString")]
  param(
    [Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline, ParameterSetName = "byString")]
    [alias("Name")]
    [string]$Computername,

    [Parameter(ValueFromPipeline, ParameterSetName = "byADComputer")]
    [Microsoft.ActiveDirectory.Management.ADComputer]$Computer
  )

  Begin {
    Write-Verbose "Starting $($myinvocation.mycommand)"  
  }
  Process {
  Write-Verbose "Using parameter set $($pscmdlet.ParameterSetName)"  
    if ($PSCmdlet.ParameterSetName -eq "byString") {
      $cn = $Computername
    }
    else {
      Write-Verbose "Getting the Name property"
      $cn = $Computer.Name
    }
    Write-Verbose "Getting BITS service from $cn"
    Try {
        Get-Service -Name bits -ComputerName $cn -ErrorAction Stop | 
        Select-Object Machinename, Name, Status
    }
    Catch {
        Write-Warning "Failed to get service status from $CN. $($_.exception.message)"
    }
  }
  End {
    Write-Verbose "Ending $($myinvocation.mycommand)"  
  }
}

This version of the function will take pipeline input by property name for Computername, or the alias Name. Or, it will process an ADComputer object. In the Process block, I can get the proper computername value to pass on to Get-Service. This version gives me the PowerShell experience I'm expecting.
get-bits-rev-stringAnd most importantly, using Get-ADComputer. My test domain has entries for non-existent computers.

Get-bits-revised-adDon't ask me why the AD cmdlets are written this way. They just are.  If we want to incorporate them into our PowerShell work, we will need to make some accommodations. My sample Get-Bits function is just one example.

At least Gladys knows she isn't going crazy and that there are solutions to her Active Directory scripting needs. I encourage you to try out Trace-Command. It might come in handy the next time you encounter a problem and want to cut down on the number of bruises on your forehead.

As usual, comments and feedback are welcome.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Active Directory Objects and the PowerShell Pipeline”

  1. JeffW says:
    October 6, 2020 at 8:33 pm

    Nice!. Much more elegant than get-adcomputer -filter ‘blah’ | select -expandproperty name | do-stuff.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d