Script Repository


Objects located in Organizational Unit

August 14, 2020
1837

This script emails an HTML-formatted report containing Active Directory objects located in the Organizational Unit on which it is executed and matching a certain LDAP filter.

To execute the script, create a Custom Command or Scheduled Task configured for the Organizational Unit object type.

Script 1: Adaxes 2017.2 or older

Parameters:

  • $searchFilter - Specifies the LDAP search filter that will be used to determine objects that will be included into the report.
  • $reportProperties - Specifies LDAP names of object proeprties that will be included into the report.
  • $excludedOuNames - Specifies names of sub-OUs of the target OU that will be skipped. Pass an empty array not to skip any sub-OUs.
  • $to - Specifies email addresses of the report recipient(s).
  • $subject - Sspecifies the email message subject.
  • $reportHeader - Specifies the report header.
  • $reportFooter - Specifies the report footer.
Edit Remove
PowerShell
$searchFilter = "(&(objectCategory=person)(objectClass=user))" # TODO: modify me
$reportProperties = @("description", "physicalDeliveryOfficeName", "department")
$excludedOuNames = @("Service Accounts", "Disabled Accounts") # TODO modify me

# E-mail message settings
$to = "recipient@example.com" # TODO: modify me
$subject = "Users in OU '%name%'" # TODO: modify me
$reportHeader = "<h2><b>Users in OU '%name%'</b></h2>" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

function IsDescendantOfOu($userDN, $excludedOuNames)
{
    foreach ($ouName in $excludedOuNames)
    {
        if ($userDN.Contains("OU=$ouName,"))
        {
            return $True
        }
    }
    return $False
}

# Find objects matching the LDAP filter
$searcher = $Context.TargetObject
$searcher.SearchFilter = $searchFilter
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500
$propertiesToLoad = $reportProperties + @("distinguishedName", "objectGuid")
$searcher.SetPropertiesToLoad($propertiesToLoad)

try
{
    # Get the default Web Interface address
    $webInterfaceAddress = "%adm-WebInterfaceUrl%"
    if ([System.String]::IsNullOrEmpty($webInterfaceAddress))
    {
        $Context.LogMessage("Default Web Interface address not set for Adaxes service.", "Warning")
    }
    
    # Get display names of all properties
    $culture = [System.Globalization.CultureInfo]::CurrentCulture
    $attributeFriendlyNamesCache = [Softerra.Adaxes.Directory.AttributeFriendlyNamesCache]::GetInstance($culture)
    
    # Build HTML table
    $table = "<table border='1'>"
    $table += "<tr><th>User display name</th>"
    foreach ($propertyLdapName in $reportProperties)
    {
        # Add property name to the report
        if ($attributeFriendlyNamesCache.HasFriendlyName($propertyLdapName))
        {
            $propertyName = $attributeFriendlyNamesCache.GetFriendlyName($propertyLdapName, "user")
        }
        else
        {
            $propertyName = $propertyLdapName
        }

        $table += "<th>$propertyName</th>"
    }

    $table += "</tr>"
    
    # Add user info to the report
    $searchResultIterator = $searcher.ExecuteSearch()
    $users = $searchResultIterator.FetchAll()

    foreach ($user in $users)
    {
        # Skip users located in excluded OUs
        if (IsDescendantOfOu $user.Properties["distinguishedName"].Value $excludedOuNames)
        {
            continue
        }
        
        # Add user info to the report
        # Add display name and link to view in the Web Interface
        $guid = [Guid]$userID.Properties["objectGuid"].Value
        $userDisplayName = [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($userID.AdsPath, "IncludeParentPath")
        $tableRow = "<tr><td><a href='$webInterfaceAddress`ViewObject.aspx?guid=$guid'>$userDisplayName</a></td>"

        # Add the specified properties
        foreach ($propertyLdapName in $reportProperties)
        {
            $value = $userID.Properties[$propertyLdapName].Values
            if ($value.Length -gt 1)
            {
                $value = $value -join "; "
            }
            $tableRow += "<td>$value</td>"
        }

        $tableRow += "</tr>"
        $table += $tableRow
    }
    
    # Finish building the HTML table
    $table += "</table>"
    $htmlReport = $reportHeader + $table + $reportFooter

    # Send mail
    $Context.SendMail($to, $subject, $NULL, $htmlReport)
}
finally
{
    # Release resources used by the search
    $searchResultIterator.Dispose()
}

Script 2: Adaxes 2018.1 or later

Parameters:

  • $searchFilter - Specifies the LDAP search filter that will be used to determine objects that will be included into the report.
  • $reportProperties - Specifies LDAP names of object proeprties that will be included into the report.
  • $excludedOuNames - Specifies names of sub-OUs of the target OU that will be skipped. Pass an empty array not to skip any sub-OUs.
  • $to - Specifies email addresses of the report recipient(s).
  • $subject - Sspecifies the email message subject.
  • $reportHeader - Specifies the report header.
  • $reportFooter - Specifies the report footer.
Edit Remove
PowerShell
$searchFilter = "(&(objectCategory=person)(objectClass=user))" # TODO: modify me
$reportProperties = @("description", "physicalDeliveryOfficeName", "department")
$excludedOuNames = @("Service Accounts", "Disabled Accounts") # TODO modify me

# E-mail message settings
$to = "recipient@example.com" # TODO: modify me
$subject = "Users in OU '%name%'" # TODO: modify me
$reportHeader = "<h2><b>Users in OU '%name%'</b></h2>" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

function IsDescendantOfOu($userDN, $excludedOuNames)
{
    foreach ($ouName in $excludedOuNames)
    {
        if ($userDN.Contains("OU=$ouName,"))
        {
            return $True
        }
    }
    return $False
}

# Get display names of all properties
$path = $Context.GetWellKnownContainerPath("ConfigurationSetSettings")
$configurationContainer = $Context.BindToObject($path)
$culture = [System.Globalization.CultureInfo]::CurrentCulture
$attributeFriendlyNames = $configurationContainer.GetAttributeFriendlyNames($culture.ThreeLetterISOLanguageName, "ADM_GETATTRFRIENDLYNAMESMODE_MERGED")
$attributeFriendlyNamesMap = @{}
foreach ($attributeFriendlyName in $attributeFriendlyNames)
{
    $ldapPropertyName = $attributeFriendlyName.AttributeName

    $typeSpecificFriendlyNames = $attributeFriendlyName.TypeSpecificFriendlyNames
    if ($typeSpecificFriendlyNames.Length -eq 0)
    {
        $attributeFriendlyNamesMap.Add($ldapPropertyName, $attributeFriendlyName.GenericFriendlyName)
        continue
    }
    
    $friendlyName = $NULL
    foreach ($type in $typeSpecificFriendlyNames)
    {
        if ($type.ObjectType -ne $Context.TargetObject.Class)
        {
            continue
        }
        $friendlyName = $type.FriendlyName
        break
    }
    
    if ($friendlyName -eq $NULL)
    {
        $attributeFriendlyNamesMap.Add($ldapPropertyName, $attributeFriendlyName.GenericFriendlyName)
    }
    else
    {
        $attributeFriendlyNamesMap.Add($ldapPropertyName, $friendlyName)
    }
}

# Find objects matching the LDAP filter
$searcher = $Context.TargetObject
$searcher.SearchFilter = $searchFilter
$searcher.SearchScope = "ADS_SCOPE_SUBTREE"
$searcher.PageSize = 500
$propertiesToLoad = $reportProperties + @("distinguishedName", "objectGuid")
$searcher.SetPropertiesToLoad($propertiesToLoad)

try
{
    # Get the default Web Interface address
    $webInterfaceAddress = "%adm-WebInterfaceUrl%"
    if ([System.String]::IsNullOrEmpty($webInterfaceAddress))
    {
        $Context.LogMessage("Default Web Interface address not set for Adaxes service.", "Warning")
    }
    
    # Build HTML table
    $table = "<table border='1'>"
    $table += "<tr><th>User display name</th>"
    foreach ($propertyLdapName in $reportProperties)
    {
        # Add property name to the report
        if ($attributeFriendlyNamesMap.ContainsKey($propertyLdapName))
        {
            $propertyName = $attributeFriendlyNamesMap[$propertyLdapName]
        }
        else
        {
            $propertyName = $propertyLdapName
        }

        $table += "<th>$propertyName</th>"
    }

    $table += "</tr>"
    
    # Add user info to the report
    $searchResultIterator = $searcher.ExecuteSearch()
    $users = $searchResultIterator.FetchAll()

    foreach ($user in $users)
    {
        # Skip users located in excluded OUs
        if (IsDescendantOfOu $user.Properties["distinguishedName"].Value $excludedOuNames)
        {
            continue
        }
        
        # Add user info to the report
        # Add display name and link to view in the Web Interface
        $guid = [Guid]$user.Properties["objectGuid"].Value
        $userDisplayName = [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($user.AdsPath, "IncludeParentPath")
        $tableRow = "<tr><td><a href='$webInterfaceAddress`ViewObject.aspx?guid=$guid'>$userDisplayName</a></td>"

        # Add the specified properties
        foreach ($propertyLdapName in $reportProperties)
        {
            $value = $user.Properties[$propertyLdapName].Values
            if ($value.Length -gt 1)
            {
                $value = $value -join "; "
            }
            $tableRow += "<td>$value</td>"
        }

        $tableRow += "</tr>"
        $table += $tableRow
    }
    
    # Finish building the HTML table
    $table += "</table>"
    $htmlReport = $reportHeader + $table + $reportFooter

    # Send mail
    $Context.SendMail($to, $subject, $NULL, $htmlReport)
}
finally
{
    # Release resources used by the search
    $searchResultIterator.Dispose()
}

Comments ( 4 )
avatar
Patrick Achuff
Aug 04, 2020
I believe this was developed prior to the newest release and therefore does not work since the Friendly name cache is no longer in the look area that this script refers to.

Would it be possible to get a 2018.1+ version?
avatar
Support
Aug 05, 2020

Hello Patrick,

There is no need to use custom Commands or Scheduled Tasks with scripts in the latest version of Adaxes to get the data. You can use reports for this purpose. For example, to get a report of all users located in an OU, use the built-in report All users. By default, the report is located in container Reports\All Reports\Users. For information on how to schedule reports, have a look at the following tutorial:https://www.adaxes.com/tutorials_ActiveDirectoryManagement_ScheduleReports.htm.

avatar
Patrick Achuff
Aug 13, 2020
Hi,
The reason we didn't use a scheduled report is related to permissions. The only way to specify who gets emailed is via the report scope. In this case we are trying to generate a ticket in our ticket management system by sending an email to a service account's email box. The service account has no rights to view the objects in the report - nor should it. Using a scheduled report then you get a blank report.

As far as I know the only way to accomplish what we are trying to do is using scripting.
avatar
Support
Aug 14, 2020

Hello Patrick,

Thank you for clarifying. We added a script that will work in Adaxes 2018.1 and later versions.

avatar
Patrick Achuff
Aug 27, 2020
Thank you, you guys are so great!
Leave a comment