Thursday, June 16, 2016

Piping get-aduser output through several custom powershell functions

For people who write scripts to process large amounts of AD objects, you may find that use of pipelines will be more memory efficient that variables and foreach. In one case, I was working through a problem with a script in powershell v2, where lots of strange failures were occurring, such as failing to assign values to a variable. A statement like: $a = 1, may just randomly not work. As the script was doing some heavy processing of large numbers of objects, I assumed memory consumption was the problem. I wanted to convert the script to use of pipeline. Since the script had several functions that handled different aspects of what was needed, I thought it would be good to try multiple pipelines. In the end, the change to pipelines fixed all the failures in the script.

What I wanted:

Take an OU, run get-aduser on the OU -> Pipe to an analysis function to check password expiration for different types of accounts and password policies, then decide if an email notice needed to be sent -> Pipe (if needed) to an email function -> Pipe the results of all of the above to logging function.

At each stage, different bits of calculated data or additional properties needed to be added to the original get-aduser object. This was possible by using custom PSObjects after the initial analysis function. The basics of the code is below:

function process-OU { 
 param(  
  [parameter(mandatory=$true)][string]$searchbase, 
  [string]$type="standard"
 )
 Get-ADUser -Filter {(enabled -eq $True) -and (mail -like "*") } `
      -SearchBase $SearchBase `
      -Properties mail, PasswordLastSet, sn, PasswordNeverExpires | 
           analyze-user -type $type |email-user |log-result
}

function Analyze-User{
 [CmdletBinding()]
 param (
  [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [Microsoft.ActiveDirectory.Management.ADAccount]$user,
  [string]$Type
 )
 begin {}
 process {
  #do some analysis and decide if you want to 
                #continue with write-output $user
  #
  #Add any additional pieces of information to the user object with
  #   add-member -input $user -force NoteProperty Expired $False
  if ($proceedtoEmail) { write-output $user } 
 }
}

function Email-User {
 [CmdletBinding()]
      Param(  
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        [PSobject]$emailuser  
      )
    #Notice the parameter type is a generic 
    #[psobject] as it is no long conforming 
    #to the [Microsoft.ActiveDirectory.Management.ADAccount] type
 Begin{}
 Process {
  #handle email creation and sending.  
                #Check if it was sent without error, 
                #add email status as another property
 }
}

function log-result {
 [CmdletBinding()]
         Param(   
            [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
              [PSObject]$user   
        )
 begin {}
 process {
  #do some logging here
 }
}


process-OU -searchbase "ou=myusers,dc=contoso,dc=com" -type "regular"

No comments:

Post a Comment