0 votes

I'm having trouble retrieving a value from an attribute but another attribute of similar type I have no trouble getting. The AD schema has been expanded to add these attributes 'hireDate' and 'terminationDate', and both attributes are of the same type Unicode String.

The code for my scheduled task is getting the members of a business unit and looping through each member ($userRec) to retrieve select values. I get the hireDate value using $userRec.Get("hireDate") and try to do the same for terminationDate using $userRec.Get("terminationDate"). I get the hireDate value, no problem. However, on the terminationDate it errors with:

The error:

Softerra.Adaxes.Adsi.DirectoryComException (0x8000500D): The 'terminationDate' property cannot be found in the cache.
   at #F.#Uo.GetEx(IAdmObject obj, String name)
   at Softerra.Adaxes.Adsi.AdmObject.GetEx(String name)
   at #F.#Uo.Get(IAdmObject obj, String name)
   at Softerra.Adaxes.Adsi.AdmObject.Get(String name)
   at Get(Object , Object[] )
   at System.Management.Automation.DotNetAdapter.AuxiliaryMethodInvoke(Object target, Object[] arguments, MethodInformation methodInformation, Object[] originalArguments) - occurred at line # 250 at char 41 while executing                 $termDate = $userRec.Get("terminationDate").

Help!

by (270 points)

1 Answer

0 votes
by (216k points)
selected by
Best answer

Hello,

The IADs::Get method raises an exception if a property is empty (value not set). You need to handle the exception in your code, for example:

[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service
$admNS = New-Object("Softerra.Adaxes.Adsi.AdmNamespace")
$admService = $admNS.GetServiceDirectly("localhost")

# Bind to object
$userDN = "CN=Gregory Bryan,OU=New York,OU=Offices,DC=example,DC=com"
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)

try
{
    $terminationDate = $user.Get("terminationDate")
}
catch [System.Runtime.InteropServices.COMException]
{
    if ($_.Exception.ErrorCode -eq -2147463155)
    {
        Write-Host "The property is empty"
    }
    else
    {
        throw $_.Exception
    }
}
0

I had already put it inside a try...catch which only masks the issue that it's not getting the value. When the results of the task weren't as expected and I realized it was because of the termination date values, I REM'd the try...catch. I've confirmed that there are records in that Business Unit which have a terminationDate set, but it's not returning values from those. I implemented the code you suggested just to see if it would branch to different error code than the -2147463155, but it didn't.

0

Hello,

First of all, using the try... catch block to handle empty properties is good practice, so we recommend you keep the block in your code.

Secondly, to understand what your issue is, can you provide the following information:

  1. Can you provide more details on how your application or script authenticates in AD? Does the user account used for authentication have enough permissions to view the terminationDate attribute of the accounts in question? The permission must be granted via Security Roles.
  2. What do you pass as the 2nd and 3rd parameters when calling the OpenObject method? Do you set the parameters to $NULL?
    $user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)
  3. Can you provide the Membership Rules of the Business Unit that you mentioned? As far as we understand, it is based on a LDAP query. Can you post here the LDAP query filter?
  4. Can you view he value of the terminationDate attribute for the users in question via Adaxes, for example, in the Administration Console?
  5. Also, could you post your script here or at least the relevant part of it?
0

1. Task runs using an account that has permissions to access all managed users, including this attribute because there's another script that modifies 'terminationDate'. (see attachment)
2. Using GetObject.
3. (&(sAMAccountType=805306368)(employeeID=1*)(!(termFlag=1)))
4. Yes
5. If this excerpt is not sufficient, let me know.

    # Process the Business Unit members
    try
    {
        $buResult = $buSearcher.ExecuteSearch()
        $objects = $buResult.FetchAll()

        if ($objects.Length -gt 1)
        {
            $Context.LogMessage("Found more than one Business Unit with name '$businessUnitName'.", "Warning")
            return
        }
        if ($objects.Length -eq 0)
        {
            $Context.LogMessage("Business Unit '$businessUnitName' does not exist.", "Error")
            return
        }

        # Get the Business Unit Members
        $unit = $Context.BindToObject($objects[0].AdsPath)
        $members = $unit.Members()

        $totalUserCount = $members.Count

        $count = 0
        $report = @()

        $configurationSetSettingsPath = $Context.GetWellKnownContainerPath("ConfigurationSetSettings")
        $admConfigurationSetSettings = $Context.BindToObject($configurationSetSettingsPath)

        $connection = New-Object "System.Data.SqlClient.SqlConnection"  $connectionString
        $connection.Open()   

       for ($i = 0; $i -lt 10; $i++)        #unREM and use this line to try limited user updates or troubleshooting
       # for ($i = 0; $i -lt $totalUserCount; $i++)
        { #$Context.LogMessage("i = $i", "Information")        #unREM for troubleshooting
            # Check whether the user is managed by Adaxes
            $userRec = $members.GetObject($i)
            $userRec.GetInfo
            $userSidsBytes = $userRec.Get("ObjectSid")
            $sid = New-Object "Softerra.Adaxes.Adsi.Sid" @($userSidsBytes, 0)
            if ($admConfigurationSetSettings.IsUnmanagedAccount($sid))
            {
                #$Context.LogMessage($userRec.Get("cn") + " is an unmanaged account.", "Information")        #unREM for troubleshooting
                continue
            } else {
              #  $Context.LogMessage($userRec.Get("cn") + " is a managed account.", "Information")        #unREM for troubleshooting
            }

  #insert function here if it fails getPropertiesFromUserRec
  #getPropertiesFromUserRec ($userRec)
            [string]$AD_employeeID = $userRec.Get("employeeID")
            [string]$AD_givenName = $userRec.Get("givenName")
            [string]$AD_sn = $userRec.Get("sn")
           # $Context.LogMessage("$i. $AD_givenName $AD_sn" , "Information")
            [string]$AD_telephoneNumber = $userRec.telephoneNumber
            [string]$AD_mail = $userRec.EmailAddress
            if ([System.String]::IsNullOrEmpty($AD_telephoneNumber)){
             $AD_telephoneNumber = ""   
            }
            if ([System.String]::IsNullOrEmpty($AD_mail)){
             $AD_mail = ""   
            }
          #  $Context.LogMessage($AD_mail, "Information")        #unREM for troubleshooting
          #  $Context.LogMessage($AD_telephoneNumber, "Information")        #unREM for troubleshooting
            try{
                $AD_HireDate = $userRec.Get("hireDate")
            }catch{
             #   $Context.LogMessage("No Hire Date", "Information")        #unREM for troubleshooting
                $AD_HireDate = ""
            }
            try{
                $termDate = $userRec.Get("terminationDate")
                $terminationDate = Get-Date -Date $termDate -Format MM-dd-yyyy h:mm
                $Context.LogMessage("Actual term $termDate", "Information")
            }catch{
              $noTermDate = Get-Date -Date "01-01-1900 0:00"
            #  #$Context.LogMessage("$AD_employeeID has NO term $noTermDate", "Information")
              $termDateBody += "$AD_employeeID has NO term $noTermDate `n"
            }

           if ($terminationDate -ne $noTermDate){
                $AD_terminationDate = $terminationDate 
            } else {
                $AD_terminationDate = $noTermDate
            }
            try{
                [string]$AD_wcDeptCode = $userRec.Get("wcDeptCode")
            }catch{
             #   $Context.LogMessage("No dept code.", "Information")        #unREM for troubleshooting
                $AD_wcDeptCode = ""
            }
            try{
                [string]$AD_wcDivCode = $userRec.Get("wcDivCode")
            }catch{
            #    $Context.LogMessage("No div code", "Information")        #unREM for troubleshooting
                $AD_wcDivCode = ""
            }
            try{
                [string]$AD_termFlag = $userRec.Get("termFlag")
            }catch{
             #   $Context.LogMessage("No term flag.", "Information")        #unREM for troubleshooting
                $AD_termFlag = ""
            }

0

Hello,

The issue occurs because the LDAP filter for the Business Unit is not correct. The following part of the filter: (!(termFlag=1)) means 'any value except 1'. This also includes an empty value. In other words, your Business Unit does include users whose termFlag attribute is empty.

The correct filter for your Business Unit is as follows:
(&(sAMAccountType=805306368)(employeeID=1\)(termFlag=*)(!(termFlag=1)))*

0

Granted the termFlag should always have a value, and currently everyone in the Business Unit does. Your suggestion will prevent anyone whom may in the fututre, in error, not have a value in termFlag from being included in that BU. So thanks for that.

My problem is that when someone who had been previously hired and separated from the agency, now having been rehired and has the former separation date populated in terminationDate, I want to get a handle on that value and can't.

0

Hello,

We checked the code that you provided, and everything looks correct. So, the only possible reason we can see is that the terminationDate attribute is empty for some users. Can you check that manually? Can you test with several users that you are sure that they have the terminationDate set?

0

For most it's blank, as expected. However for some there are dates, which is the reason I submitted this as an issue, because I've already checked and double-checked and am 100% sure that there select users who have terminationDate populated. I'm sending proof to Support via email.

0

Hello,

The issue occurred because of an error in the syntax of the Get-Date cmdlet. The thing is that you specified the string format for terminationDate without quotes. With such a syntax, by default in PowerShell, MM-dd-yyyy and h:mm are considered to be two different parameters of the Get-Date cmdlet. As the h:mm parameter is unknown to the cmdlet, an exception is raised. You need to include the string format in double quotes to avoid such ambiguity:

Get-Date -Date $termDate -Format "MM-dd-yyyy h:mm"

You included both getting the property and converting it in the try block. Because of this, the catch block was invoked in both the cases: when the property was empty and when the property was not empty, but a conversion error occurred.

We suggest the following:

  • Separate getting the property and converting it.
  • Include only getting the property in the try... catch block.

Code:

try
{
    $termDate = $userRec.Get("terminationDate")
}
catch
{
    $termDate = $NULL
}

if ($termDate -eq $NULL)
{
    $noTermDate = Get-Date -Date "01-01-1900 0:00"
    #  #$Context.LogMessage("$AD_employeeID has NO term $noTermDate", "Information")
    $termDateBody += "$AD_employeeID has NO term $noTermDate `n"
}
else
{
    $terminationDate = Get-Date -Date $termDate -Format "MM-dd-yyyy h:mm"
    $Context.LogMessage("Actual term $termDate", "Information")
}

Related questions

0 votes
1 answer

Hi, I am making business rule which calls powershell script and inside the script I need to check whether account which is added to group is security group. I am using Get- ... , the same command return, that group type is security So what am I doing wrong?

asked Feb 20, 2020 by KIT (960 points)
0 votes
1 answer

We are wanting to display all values entered into a multi value text attribute in an email sent by Adaxes. What we've found is that only the first entry into the array ... Entry" Is there a way to reference the variable so that it displays all entries? Thanks

asked Dec 12 by msheppard (610 points)
0 votes
1 answer

Ideally looking to make this a rule based group, but report or business unit should work also. In our domain, service accounts become direct reports of the user who requested/ ... if a specific object is a/not a direct report. Is this possible? Thank you

asked Nov 14, 2023 by ThompsonAlex (40 points)
0 votes
1 answer

Hello, is there a way to save powershell variable to axases attribute and send it via "send email notification" in Scheduled task? for example, check if Office 2016 ... .name) installed"} ` then add $customattrib value to Send email notification. Thank you

asked Feb 13, 2020 by vheper (20 points)
0 votes
1 answer

I have a need to pull the last n characters from a value and append it to another (adding last 4 of mobile number to sAMAccountName). I see the way to get the ... it will error out when trying to create it. Any advice would be greatly appreciated. Thanks!

asked Dec 20, 2017 by Bowman4864 (270 points)
3,588 questions
3,277 answers
8,303 comments
548,097 users