Public/Users/Find-GraphUser.ps1

# Module: Orbit
# Function: Lookup
# Author: David Eberhardt
# Updated: 24-JAN-2021
# Status: Live

# Add Search in ProxyAddresses - only display with an exact match


function Find-GraphUser {
  <#
  .SYNOPSIS
    Returns User Objects from Azure AD based on a search string or UserPrincipalName
  .DESCRIPTION
    Simplifies lookups with Get-MgUser by using and combining -Search and -ObjectId Parameters.
    CmdLet can find uses by either query, if nothing is found with the Searchstring, another search is done via the ObjectId
    This simplifies the query without having to rely multiple queries with Get-MgUser
  .PARAMETER SearchString
    Required. A 3-255 digit string to be found on any Object.
    Performs multiple searches against this string and parts thereof.
    Starting with UserId, DisplayName, Surname and, if the SearchString contains an @-symbol, Mail & Mailnickname
    Returns unique objects only.
  .EXAMPLE
    Find-GraphUser [-SearchString] "John"
 
    Will search for the string "John" and return all Azure AD Objects found
    If nothing has been found, will try to search for by identity
  .EXAMPLE
    Find-GraphUser [-SearchString] "John@domain.com"
 
    First searches for a User with the UserId "John@domain.com"
    Then searches for DisplayNames or Surnames for string before a space or dot
    Finally searching Mail & Mailnickname for string before an "@"
    Return all Objects found
  .EXAMPLE
    Find-GraphUser -Identity John@domain.com,Mary@domain.com
 
    Will search for the string "John@domain.com" and return all Azure AD Objects found
  .INPUTS
    System.String
  .OUTPUTS
    PSCustomObject
  .NOTES
    None
  .COMPONENT
    UserManagement
  .FUNCTIONALITY
    Queries User Objects in Azure Ad with different mechanics
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/Orbit.Users/Find-GraphUser.md
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/about/about_UserManagement.md
  .LINK
    https://github.com/DEberhardt/Orbit/tree/main/docs/
  #>


  [CmdletBinding()]
  [OutputType([PSCustomObject])]
  param(
    [Parameter(Mandatory, Position = 0, ParameterSetName = 'SearchString', ValueFromPipeline, HelpMessage = 'Search string')]
    [ValidateLength(3, 255)]
    [string[]]$SearchString
  ) #param

  begin {
    Show-OrbitFunctionStatus -Level Live
    Write-Verbose -Message "[BEGIN ] $($MyInvocation.MyCommand)"

    # Asserting Graph Connection
    if ( -not (Test-GraphConnection) ) { throw 'Connection to Microsoft Graph not established. Please validate connection' }

    # Setting Preference Variables according to Upstream settings
    if (-not $PSBoundParameters['Verbose']) { $VerbosePreference = $PSCmdlet.SessionState.PSVariable.GetValue('VerbosePreference') }
    $DebugPreference = if (-not $PSBoundParameters['Debug']) { $PSCmdlet.SessionState.PSVariable.GetValue('DebugPreference') } else { 'Continue' }
    $InformationPreference = if ( $PSBoundParameters['InformationAction']) { $PSCmdlet.SessionState.PSVariable.GetValue('InformationAction') } else { 'Continue' }

  } #begin

  process {
    Write-Verbose -Message "[PROCESS] $($MyInvocation.MyCommand)"

    [System.Collections.Generic.List[object]]$Users = @()
    foreach ($String in $SearchString) {
      [System.Collections.Generic.List[object]]$Search = @()

      try {
        # UserId
        Write-Verbose -Message "Searching for Objects `"UserId:'$String'`""
        $Result = Get-MgUser -UserId "$String" -WarningAction SilentlyContinue -ErrorAction STOP
        if ( $Result ) { $Users.Add($Result) } else { throw }
      }
      catch {
        $MgUserParams = @{
          ConsistencyLevel = 'eventual'
          Count            = 'userCount'
          WarningAction    = 'SilentlyContinue'
          ErrorAction      = 'Stop'
        }

        $Search.Add("DisplayName:$String")
        $Search.Add("Surname:$String")
        $UserPart = $String.split('@') | Select-Object -First 1
        $Surname1 = $UserPart.split(' ') | Select-Object -Last 1
        $Surname2 = $UserPart.split('.') | Select-Object -Last 1
        $GivenName1 = $UserPart.split(' ') | Select-Object -First 1
        $GivenName2 = $UserPart.split('.') | Select-Object -First 1

        if ( -not $Search.contains("DisplayName:$UserPart")) { $Search.Add("DisplayName:$UserPart") }
        if ( -not $Search.contains("DisplayName:$Surname1")) { $Search.Add("DisplayName:$Surname1") }
        if ( -not $Search.contains("DisplayName:$Surname2")) { $Search.Add("DisplayName:$Surname2") }
        if ( -not $Search.contains("Surname:$Surname1")) { $Search.Add("Surname:$Surname1") }
        if ( -not $Search.contains("Surname:$Surname2")) { $Search.Add("Surname:$Surname2") }
        if ( -not $Search.contains("GivenName:$GivenName1")) { $Search.Add("GivenName:$GivenName1") }
        if ( -not $Search.contains("GivenName:$GivenName2")) { $Search.Add("GivenName:$GivenName2") }
        if ( -not $Search.contains("Mail:$UserPart")) { $Search.Add("Mail:$UserPart") }
        if ( -not $Search.contains("MailNickName:$UserPart")) { $Search.Add("MailNickName:$UserPart") }

        $Search | ForEach-Object {
          Write-Verbose -Message "Searching for Objects with `"$_`""
          try {
            $Result = $null = Get-MgUser -Search "$_" @MgUserParams
            if ( $Result ) {
              Write-Verbose -Message "Found $($Result.Count) Object(s) with `"$_`""
              $Users.Add($Result)
            }
          }
          catch {
            Write-Error -Message $_.Exception.Message
          }
        }
      }
    }

    # Output - Filtering objects
    if ( $Users ) {
      $Users | Sort-Object -Unique -Property ObjectId | Get-Unique | Sort-Object DisplayName
    }
  } #process

  end {
    Write-Verbose -Message "[END ] $($MyInvocation.MyCommand)"
  } #end
} # Find-GraphUser