0 votes

We are having problems with the Get-AdmUser command. We are trying to run a user count task, but our script times out with "The pipeline has been stopped".

We debugged the script, and found it to be the Get-AdmUser cmdlet that throws this.

This is the script we are running:

Import-Module Adaxes

$targetOU = "%distinguishedName%"
# Get name of the OU's domain
$domainName = $Context.GetObjectDomain("%distinguishedName%")

$exportpath = "C:\UserCount\"
$custname = "%ou%"
$custnr = (Get-AdmOrganizationalUnit -Identity $targetOU  -Properties * -AdaxesService localhost -Server $domainName).postalCode

#User Count
$exportfile = $exportpath + "Users_" + $domainName + ".csv"

New-Item $exportfile -Type File
$users = Get-AdmUser -Filter {(Enabled -eq $True)} -SearchBase "$targetOU" -Properties * -AdaxesService localhost -Server $domainName | Where {$_.company -notlike "*ikkebetalbar*"}
foreach ($user in $users){
    $samacc = $user.sAMAccountName
    $userna = $user.Name
    Add-Content $exportfile "`"$domainName`",`"$custnr`",`"$custname`",`"$samacc $userna`""
}

#Group Count
$exportfile = $exportpath + "Groups_" + $domainName + ".csv"

New-Item $exportfile -Type File
$groups = Get-AdmGroup -Filter {description -like "TilgangTil*"} -SearchBase "$targetOU" -Properties * -AdaxesService localhost -Server $domainName
foreach ($group in $groups){
    $desc = $group.description -replace "TilgangTil ", ""
    $members = Get-AdmGroupMember -Identity $group -Recursive -AdaxesService localhost -Server $domainName | where {$_.objectClass -ne "group"}
    foreach ($member in $members){
        $user = Get-AdmUser -Identity $member -Properties * -AdaxesService localhost -Server $domainName
        if(($user.Enabled -eq $false) -or ($user.company -like "*ikkebetalbar*")){continue} 
        $memacc = $member.sAMAccountName
        $memna = $member.Name
        Add-Content $exportfile "`"$domainName`",`"$custnr`",`"$custname`",`"$desc`",`"$memacc $memna`""
    }
}
by (960 points)

1 Answer

0 votes
by (215k points)

Hello,

The pipeline has been stopped error usually occurs when a script takes too much time to complete. The thing is that when you launch a script with the Run a program or PowerShell script action, Adaxes waits 10 minutes for the script to complete, and then stops execution.

How many users do you have in that OU? For a script not to be able to complete the search in 10 minutes, there should be very many users in the OU.

To try to remedy the issue, try to invoking cmdlets without the -AdaxesService parameter. In this way you will force the cmdlet use the standard Windows ADSI API instead of Adaxes ADSI API. This should speed up the search a bit. For example:

$users = Get-AdmUser -Filter {(Enabled -eq $True)} -SearchBase "$targetOU" -Properties * -Server $domainName | Where {$_.company -notlike "*ikkebetalbar*"}

If this doesn't help, you can modify the script and invoke Adaxes ADSI API directly, not via Adaxes PowerShell cmdlets. Invoking Adaxes ADSI API directly should also speed up the process. For examples on how to search user accounts using Adaxes ADSI API, see Searching User Accounts. For examples on how to read properties of an object using Adaxes ADSI API interfaces, see Reading Object Properties

0

We have now altered our script to use the ADSI API, but we still get the "The pipeline has been stopped" error.

The OU contains about 1800 users.

This is the script:

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

$exportPath = "C:\UserCount\"
$domainName = $Context.GetObjectDomain("%distinguishedName%")
$customerNumber = (Get-AdmOrganizationalUnit -Identity "%distinguishedName%"  -Properties * -AdaxesService localhost -Server $domainName).postalCode

$adsi = New-Object Softerra.Adaxes.Adsi.AdmNamespace
$adaxes = $adsi.GetServiceDirectly("localhost")

# User Count

$exportFile = $exportPath + "Brukere_$domainName.csv"
New-Item $exportFile -Type File

$search = $adaxes.OpenObject("Adaxes://%distinguishedName%", $null, $null, 0)
$search.SearchScope = "ADS_SCOPE_SUBTREE"
$search.PageSize = 10000
$search.SearchFilter = "(&(objectCategory=user)(samAccountName=*)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!company=*ikkebetalbar*))"

$result = $search.ExecuteSearch()
foreach ($user in $result.FetchAll()) {
  $objUser = $adaxes.OpenObject($user.AdsPath, $null, $null, 0)
  $userAccount = $objUser.Get("sAMAccountName")
  $userName = $objUser.Get("name")
  Add-Content $exportFile "`"$domainName`",`"$customerNumber`",`"%ou%`",`"$userAccount $userName`""
}
$result.Dispose()

# Group Count

$exportFile = $exportPath + "Grupper_$domainName.csv"
New-Item $exportFile -Type File

$search = $adaxes.OpenObject("Adaxes://%distinguishedName%", $null, $null, 0)
$search.SearchScope = "ADS_SCOPE_SUBTREE"
$search.PageSize = 10000
$search.SearchFilter = "(&(objectCategory=group)(description=TilgangTil*))"

$result = $search.ExecuteSearch()
foreach ($group in $result.FetchAll()) {
  $objGroup = $adaxes.OpenObject($group.AdsPath, $null, $null, 0)
  $groupDescription = $objGroup.Get("description") -replace "TilgangTil ", ""
  foreach ($byteGuid in $objGroup.Get("adm-MembersGuid")) {
   $guid = New-Object System.Guid(,$byteGuid)
    $guid = $guid.ToString("B")
    $objUser = $adaxes.OpenObject("Adaxes://<GUID=$guid>", $null, $null, 0)
    try {
      if (($objUser.Get("objectClass") -eq "group") -or ($objUser.Get("userAccountControl") -band 0x2) -or ($objUser.Get("company") -like "*ikkebetalbar*")) {
        continue
      }
    }
    catch{}
    $userAccount = $objUser.Get("sAMAccountName")
    if ($userAccount.Length -le 0) {
      continue
    }
    $userName = $objUser.Get("name")
    Add-Content $exportFile "`"$domainName`",`"$customerNumber`",`"%ou%`",`"$groupDescription`",`"$userAccount $userName`""
  }
}
$result.Dispose()
0

We tested the ADSI version of the script in our testing environment, and it takes around 15 seconds to complete on an OU with 10 000 users. Can you describe how do you launch the script? Do you launch it in a Scheduled Task with the help of the Run a program or PowerShell script action? What is the target object of the Task and its Assignment Scope?

0

We are using the script in a Scheduled Task with the help of the Run a program or PowerShell script. The OU selected is in a managed domain without a trust against that domain. What is the recomended specs on a VM for the adaxes service supporting upto 2000 users?

0

We think that the difference between the time required to run the script in your environment and in our environment is now caused by the second part of the script (the portion that deals with groups). The thing is that in our environment, in the OU that we tested the script on, we don't have many groups with lots of members.

After taking a closer look at your version of the script, we see certain points where we can optimize performance of the script. We've already assigned the task to optimize it to our scripting guy, he'll optimize the script for you. As soon as he's ready, we'll post the optimized script here and see if this helps.

0

Hello,

Try the following version of the script modified by our scripting guy. It should complete faster.

Import-Module Adaxes

$exportPath = "C:\UserCount\" # TODO: modify me
$domainName = $Context.GetObjectDomain("%distinguishedName%")
$customerNumber = (Get-AdmOrganizationalUnit -Identity "%distinguishedName%"  -Properties postalCode -AdaxesService localhost -Server $domainName).postalCode

# Build path for the user report file
$exportFile = $exportPath + "Brukere_$domainName.csv"

# Create new file for the user report
New-Item $exportFile -Type File

# Get AdsPath of target object
$targetObject = $Context.BindToObjectByDN("%distinguishedName%")
$targetObjectPath = $targetObject.ADsPath

# Search all users in the target OU
$userSearcher = New-Object "Softerra.Adaxes.Adsi.Search.DirectorySearcher" $NULL, $False
$userSearcher.SearchParameters.BaseObjectPath = $targetObjectPath
$userSearcher.SearchParameters.PageSize = 500
$userSearcher.SearchParameters.SearchScope = "ADS_SCOPE_SUBTREE"
$userSearcher.SearchParameters.Filter = "(&(objectCategory=user)(samAccountName=*)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!company=*ikkebetalbar*))"
$userSearcher.SetPropertiesToLoad(@("sAMAccountName","name"))

$userResult = $userSearcher.ExecuteSearch()

# Get the user's sAMAccountName and name and add them to the file
foreach ($user in $userResult.FetchAll()) 
{
    $userAccount = $user.Properties["sAMAccountName"].Value
    $userName = $user.Properties["name"].Value
    Add-Content $exportFile "`"$domainName`",`"$customerNumber`",`"%ou%`",`"$userAccount $userName`""
}
$userResult.Dispose()

# Build path for the group report file
$exportFile = $exportPath + "Grupper_$domainName.csv"

# Create new file for the group report
New-Item $exportFile -Type File

# Search all groups in the target OU
$groupSearcher = New-Object "Softerra.Adaxes.Adsi.Search.DirectorySearcher" $NULL, $False
$groupSearcher.SearchParameters.BaseObjectPath = $targetObjectPath
$groupSearcher.SearchParameters.PageSize = 500
$groupSearcher.SearchParameters.SearchScope = "ADS_SCOPE_SUBTREE"
$groupSearcher.SearchParameters.Filter = "(&(objectCategory=group)(description=TilgangTil*))"
$groupSearcher.SetPropertiesToLoad(@("description","name"))

$groupResult = $groupSearcher.ExecuteSearch()

foreach ($group in $groupResult.FetchAll()) 
{
    # Get and change the description of the group
    $groupDescription = $group.Properties["description"].Value -replace "TilgangTil ", ""
    $group = $Context.BindToObject($group.AdsPath)

    # Build a filter to search for members
    $memberFilterBuilder = New-Object "System.Text.StringBuilder"
    $memberFilterBuilder.Append("(&(!objectClass=group)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!company=*ikkebetalbar*)(|")

    # Get GUIDs of all members
    try
    {
        $membersGuidsInByte = $group.GetEx("adm-MembersGuid")
    }
    catch
    {
        $membersGuidsInByte = $NULL
    }

    # If there are no members in the group, continue
    if($membersGuidsInByte -eq $NULL)
    {
        continue
    }

    foreach ($byteGuid in $membersGuidsInByte)
    {
        # Add the user's GUID to the filter
        $guid = [Softerra.Adaxes.Ldap.FilterBuilder]::Create($byteGuid)
        $memberFilterBuilder.Append($guid)
    }
    $memberFilterBuilder.Append("))")

    # Search all members of the current group
    $membersSearcher = New-Object "Softerra.Adaxes.Adsi.Search.DirectorySearcher" $NULL, $False
    $membersSearcher.SearchParameters.PageSize = 500
    $membersSearcher.SearchParameters.SearchScope = "ADS_SCOPE_SUBTREE"
    $membersSearcher.SearchParameters.Filter = $memberFilterBuilder.ToString()
    $membersSearcher.SearchParameters.VirtualRoot = $True
    $membersSearcher.SetPropertiesToLoad(@("sAMAccountName","name"))

    $membersResult = $membersSearcher.ExecuteSearch()

    foreach ($user in $membersResult.FetchAll()) 
    {
        if (-not($user.Properties.Contains("sAMAccountName"))) 
        {
          continue
        }
        # Get the sAMAccountName property
        $userAccount = $user.Properties["sAMAccountName"].Value

        # Get the name property
        $userName = $user.Properties["name"].Value

        # Add info to the file
        Add-Content $exportFile "`"$domainName`",`"$customerNumber`",`"%ou%`",`"$groupDescription`",`"$userAccount $userName`""
    }
    $membersResult.Dispose()
}
$groupResult.Dispose()
0

I just tested the script in our enviorment. The script took a while to run, and came out with this error multiple times:
"Multiple ambiguous overloads found for "Create" and the argument count: "1".

Any ideas?

This is the only section where "create" is used:

foreach ($byteGuid in $group.Get("adm-MembersGuid")) 
    {
        # Add the user's GUID to the filter
        $guid = [Softerra.Adaxes.Ldap.FilterBuilder]::Create($byteGuid)
        $memberFilterBuilder.Append($guid)
    }
    $memberFilterBuilder.Append("))")
0

The script contained a small error. I've updated the script in my post above.

0

Still getting errors:
Exception calling "GetEx" with "1" argument(s): "The 'adm-MemberGuid' property cannot be found in the cache."
Exception calling "FetchAll" with "0" argument(s): "The search filter cannon be recognized. (Server: wrongdomain.local)"

We have 3 managed domains, this is supposed to only run against one of them at the time, but it shows error on the "wrongdomail.local". This happens even though this is ran against an OU in the correct domain.

0

There was yet one more small issue with the script. Please find the updated script in my post above.

0

The script works now, thanks :)

Related questions

0 votes
1 answer

I am getting the following error... The type initializer for 'System.Management.Automation.PSCredential' threw an exception. The term 'Get-AdmUser' is not recognized as the ... working for months and then suddenly... BOOM! They started throwing this error.

asked Sep 2, 2016 by rmedeiros (360 points)
0 votes
1 answer

Hi, I know there probably better places for this question but since I need to use Get-AdmUser I was wondering if you could help me build a Filter to find all ... automatically send a report every month but we need to narrow it down Thanks in advance Ingemar

asked Sep 15, 2015 by ijacob (960 points)
0 votes
1 answer

I know I got this code to check for a unique email address from you guys, just can't find where Import-Module Adaxes if ($Context.IsPropertyModified("mail")) { $value = ... all the targeted type of objects under Adaxes' purview? Thanks again for the help!!!

asked Mar 25, 2013 by jiambor (1.2k points)
0 votes
1 answer

I'm currently running a SQL SPROC from within powershell, getting a value, and attempting to assign that value to an AD attribute. Everything goes fine getting the value, but ... avoid calling PS from within PS to load the module and run the command. Thanks!

asked Feb 3, 2017 by gmadd13 (50 points)
0 votes
1 answer

Let's say I have a Business Rule that is fired prior to adding members to a group. Is it possible to get the number of objects being added to that group as ... that tells me that 6 objects will be added or is each added user treated completely independently?

asked Apr 20 by ngb (90 points)
2,779 questions
2,512 answers
6,576 comments
26,876 users