3

I'm trying to combine the output of two functions with the output of the default Get-ADUser-cmdlet. I'm interested in when an account was created, if it's locked and what it's name is. I also want to know when the user logged on for the last time (using multiple DC's) and if the account is being used as a shared mailbox.

I've written two custom functions Get-ADUserLastLogon and isSharedMailbox, both functions use the Write-Output function to output their output. In case of Get-ADUserLastLogon this will be Lastlogon: time and in case of isSharedMailbox this will be shared: yes/no. I'm also using a standard Get-ADUser call in a foreach loop

Now, the default output of Get-ADUser is:

SAMAccountName LockedOut Created
-------------- --------- -------
ACC False 23-10-2015 8:20:20

Output of the custom functions is as following:

Lastlogon : 1-1-1601 1:00:00

Shared: yes

What I would like is to combine the LastLogon and Shared 'headers' to be combined into the Get-ADUser. So the output would become:

SAMAccountName LockedOut Created LastLogon Shared

Code of current code, where the accounts get imported from an Excel sheet:

foreach($username in $usernameWithTld){
    if ($username -eq $NULL){
        break
    }

    $usernameWithoutTld = $username.split('\')

    Get-ADUser $usernameWithoutTld[1] -Properties LockedOut, SamAccountName, 
    Created -ErrorAction Stop | Select-Object SAMAccountName, LockedOut, 
    Created

    Get-ADUserLastLogon -UserName $usernameWithoutTld[1]

   # Shared mailbox?

   isSharedMailbox -mailboxname $usernameWithoutTld[1]
}

Function code:

function isSharedMailbox([string]$mailboxname){
    $isObject = Get-ADUser  -Filter {name -eq $mailboxname} -SearchBase "..." | Select-Object DistinguishedName,Name

    if ($isObject -match "DistinguishedName"){
        $output = "Shared: no"
        Write-Output $output
    } else {
        $output = "Shared: No"
        Write-Output $output
    }

}


function Get-ADUserLastLogon([string]$userName){

  $dcs = Get-ADDomainController -Filter {Name -like "*"}
  $time = 0
  foreach($dc in $dcs)
  { 
    $hostname = $dc.HostName
    $user = Get-ADUser $userName | Get-ADObject -Properties lastLogon 
    if($user.LastLogon -gt $time) 
    {
      $time = $user.LastLogon
    }
  }
  $dt = [DateTime]::FromFileTime($time)
  Write-Output "LastLogon : $dt"

}

I'm sure there are lots of improvements that can be made, I'm still learning how to write (proper) PowerShell. I hope someone can answer my question.

1
  • isSharedMailbox will always return No, might want to fix that ;) Commented Jun 14, 2017 at 10:40

3 Answers 3

5

You could use a Calculated Property in your Select-Object. Have a look at example 4 for the MSDN page.

In your case this would be:

Get-ADUser $usernameWithoutTld[1] -Properties LockedOut, SamAccountName, Created -ErrorAction Stop | `
Select-Object SAMAccountName, LockedOut, Created, @{Name='LastLogon';Expression={Get-ADUserLastLogon -UserName $usernameWithoutTld[1]}}, @{Name='IsSharedMailbox';Expression={isSharedMailbox -mailboxname $usernameWithoutTld[1]}}

Or even better, you can use the object(s) that Get-ADUser puts in the pipeline to in turn call your functions for that specific object, and can be useful in case your query returns multiple results:

Get-ADUser $usernameWithoutTld[1] -Properties LockedOut, SamAccountName, Created -ErrorAction Stop | `
Select-Object SAMAccountName, LockedOut, Created, @{Name='LastLogon';Expression={Get-ADUserLastLogon -UserName $_.sAMAccountName}}, @{Name='IsSharedMailbox';Expression={isSharedMailbox -mailboxname $_.sAMAccountName}}
Sign up to request clarification or add additional context in comments.

2 Comments

This is exactly what I'm looking for. Thanks alot for your explanation and solution! :)
@Brainscrewer, Is the script above works for OnPremise Only or Hybrid-Office365 ?
2

One way to do this is to get your functions to return the values you are interested in, store them in variables, and combine everything together afterwards into a PSObject containing the properties you are interested.

The benefits of storing as an object are many. For example, you can use Select-Object, Sort-Object etc in the pipeline, or Export-CSV and other Cmdlets that expect InputObject

foreach($username in $usernameWithTld){
    if ($username -eq $NULL){
        break
    }

    $usernameWithoutTld = $username.split('\')

    $adDetails = Get-ADUser $usernameWithoutTld[1] -Properties LockedOut, SamAccountName, 
    Created -ErrorAction Stop | Select-Object SAMAccountName, LockedOut, 
    Created

    $lastlogin = Get-ADUserLastLogon -UserName $usernameWithoutTld[1]

   # Shared mailbox?

   $isshared = isSharedMailbox -mailboxname $usernameWithoutTld[1]

   # putting together the PSobject
   [array]$myResults += New-Object psobject -Property @{
        SAMAccountName = $adDetails.SAMAccountName
        LockedOut      = $adDetails.LockedOut
        Created        = $adDetails.Created
        LastLogon      = $lastlogin
        Shared         = $shared # true/false or yes/no, depending on function
        #Shared         = if($shared){"yes"}else{"no"} # yes/no, based on true/false from function

   }
}

Functions:

function isSharedMailbox([string]$mailboxname){
    $isObject = Get-ADUser  -Filter {name -eq $mailboxname} -SearchBase "..." | Select-Object DistinguishedName,Name

    return ($isObject -match "DistinguishedName") # returns true/false

    <# if you prefer to keep yes/no
    if ($isObject -match "DistinguishedName"){
        return "Yes"  # no in original code
    } else {
        return "No"
    }
    #>
}

function Get-ADUserLastLogon([string]$userName){

  $dcs = Get-ADDomainController -Filter {Name -like "*"}
  $time = 0
  foreach($dc in $dcs)
  { 
    $hostname = $dc.HostName
    $user = Get-ADUser $userName | Get-ADObject -Properties lastLogon 
    if($user.LastLogon -gt $time) 
    {
      $time = $user.LastLogon
    }
  }
  $dt = [DateTime]::FromFileTime($time)

  return $dt
  #Write-Output "LastLogon : $dt"

}

1 Comment

Is the script above works for OnPremise Only or Hybrid-Office365 ?
1

You can store the result of the functions in global variables and finally concatenate them is one way.

Else you can use return the output from the function and use the value later or like : $value= functionname then $value will hold the return value of the function and later you can combine the results.

function isSharedMailbox([string]$mailboxname){
    $isObject = Get-ADUser  -Filter {name -eq $mailboxname} -SearchBase "..." | Select-Object DistinguishedName,Name

    if ($isObject -match "DistinguishedName"){
        $output = "Shared: no"
        $Global:result1= $output
    } else {
        $output = "Shared: No"
        $Global:result1= $output
    }

}


function Get-ADUserLastLogon([string]$userName){

  $dcs = Get-ADDomainController -Filter {Name -like "*"}
  $time = 0
  foreach($dc in $dcs)
  { 
    $hostname = $dc.HostName
    $user = Get-ADUser $userName | Get-ADObject -Properties lastLogon 
    if($user.LastLogon -gt $time) 
    {
      $time = $user.LastLogon
    }
  }
  $dt = [DateTime]::FromFileTime($time)
  $Global:result2= "LastLogon : $dt"

}
## Calling the function . Change the placeholders accordingly
Get-ADUserLastLogon -UserName $usernameWithoutTld[1]
isSharedMailbox -mailboxname $usernameWithoutTld[1]

$FinalResult = "result1" + "result2"
$FinalResult

Hope it helps you better understanding.

2 Comments

I would not want to use global variables when a calculated property would be a much more elegant way to do this.
@JamesC.: Ya right. I just do not want to change any code on that context. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.