0 votes

I'm trying to automate adding users who are enrolled in MFA to an AD group. The scripts I found elsewhere here that do not work so I believe they may have been written against a prior Adaxes version or referencing a report that does not meet our needs.

by (50 points)
0

Hello,

What exactly do you mean by MFA here?

0

Users enrolled in any multifactor authentication policy within Adaxes.

I want a script to query MFA enrollment status, then add only enrolled users to an AD group.

Here is a script I found that should generate a CSV file with all user enrollment status, however it does not run either within Adaxes as a custom scheduled task as an action of type "Run a program or PowerShell script" or via PowerShell directly. Email functionality in the script is ignored as I'm only trying to write a CSV. The errors will be posted below the script.

Script:

$ouDNs = @("CN=Users,DC=domain,DC=com", "DC=domain,DC=com") # TODO modify me. Set to @() for search all users

$reportType = "Enrolled" # TODO: uncomment the type you need
# $reportType = "Not enrolled"
# $reportType = $NULL

# CSV file settings
$csvFilePath = "C:\tools\enrollment-report.csv" # TODO: modify me
$removeCSVFile = $False # TODO: modify me

# Mail settings
$to = "recipient@domain.com" # TODO: modify me
$from = "noreply@localhost" # TODO: modify me
$smtpServer = "mailserver.domain.com" # TODO: modify me
$subject = "Password Self-Service statistics" # TODO: modify me
$message = "Password Self-Service statistics" # TODO: modify me

function GetUserGuids($dn, $list)
{
    $searcher = $Context.BindToObjectByDN($dn)
    $searcher.Criteria = New-AdmCriteria "user"
    $searcher.SearchScope = "ADS_SCOPE_SUBTREE"
    $searcher.PageSize = 500
    $searcher.SetPropertiesToLoad(@("objectGUID"))

    try
    {
        $searchResultIterator = $searcher.ExecuteSearch()
        $searchResults = $searchResultIterator.FetchAll()

        $searchResults | %%{[void]$list.Add([Guid]$_.Properties["objectGUID"].Value)}
    }
    finally
    {
        # Release resources
        if ($searchResultIterator){ $searchResultIterator.Dispose() }
    }
}

# Bind to the 'Password Self-Service Statistics' container
$passwordSelfServiceStatisticsPath = $Context.GetWellKnownContainerPath("PasswordSelfServiceStatistics")
$passwordSelfServiceStatistics = $Context.BindToObject($passwordSelfServiceStatisticsPath)

# Get the enrollment report
$reportIsBeingGenerated = $True
do
{
    try
    {
        $report = $passwordSelfServiceStatistics.GetReport("ADM_PSSREPORTTYPE_ENROLLMENT")
    }
    catch [System.Runtime.InteropServices.COMException]
    {
        if ($_.Exception.ErrorCode -eq "-2147024875")
        {
            # Report is being generated. Wait 10 seconds
            Start-Sleep -Seconds 10
            continue
        }
        else
        {
            $reportIsBeingGenerated = $False
            $Context.LogMessage($_.Exception.Message, "Error")
            return
        }
    }

    if ($report.GenerateDate -lt [System.Datetime]::UtcNow.AddHours(-1))
    {
        $passwordSelfServiceStatistics.ResetReportCache("ADM_PSSREPORTTYPE_ENROLLMENT")
    }
    else
    {
        $reportIsBeingGenerated = $False
    }
}
while ($reportIsBeingGenerated)

# Get user guids
$userGuids = New-Object "System.Collections.Generic.HashSet[System.Guid]"
foreach ($dn in $ouDNs)
{
    GetUserGuids $dn $userGuids
}

# Build the report
$reportRecords = New-Object System.Collections.ArrayList
$records = $report.Records
for ($i = 0; $i -lt $records.Count; $i++)
{
    $record = $records.GetRecord($i)

    # Get user information
    $userPath = $NULL
    $userDisplayName = $NULL
    $userParentCanonicalName = $NULL
    $userAccountIsEnabled = $NULL
    $userIsEnrolled = $NULL
    $userAccountIsExpired = $NULL
    $userInfo = $record.GetUserInfo([ref]$userPath, [ref]$userDisplayName, [ref]$userParentCanonicalName, 
        [ref]$userAccountIsEnabled, [ref]$userIsEnrolled, [ref]$userAccountIsExpired)

    $path = New-Object Softerra.Adaxes.Adsi.AdsPath $userPath
    $guid = [Guid]$path.Guid

    if ($userGuids.Count -ne 0 -and !$userGuids.Contains($guid))
    {
        continue
    }

    if (($reportType -eq "Enrolled" -and !$userIsEnrolled) -or 
        ($reportType -eq "Not enrolled" -and $userIsEnrolled))
    {
        continue
    }

    # Get event date
    $eventDate = $record.EventDate
    if ($eventDate -eq [DateTime]::MinValue)
    {
        $eventDate = $NULL
    }

    # Get policy information
    $policyPath = $NULL
    $policyName = $NULL
    $policyInfo = $record.GetEnrollmentPolicyInfo([ref]$policyPath, [ref]$policyName)

    if ($userIsEnrolled)
    {
        $userIsEnrolled = "Yes ($policyName)"
    }
    else
    {
        $userIsEnrolled = "No"
    }

    # Get invitation info
    $successSendDate = New-Object System.Datetime 0
    $errorMessage = $NULL
    $record.GetSendInvitationInfo([ref]$successSendDate, [ref]$errorMessage)
    if ([System.String]::IsNullOrEmpty($errorMessage) -and $successSendDate -ne [Datetime]::MinValue)
    {
        $enrollmentInvitation = $successSendDate
    }
    else
    {
        $enrollmentInvitation = $errorMessage
    }

    # Get effective policy information
    $effectivePolicyPath = $NULL
    $effectivePolicyName = $NULL
    $record.GetEffectivePolicyInfo([ref]$effectivePolicyPath, [ref]$effectivePolicyName)

    # Add information to the report
    $reportRecord = [PSCustomObject][ordered]@{
        "Name" = $userDisplayName
        "Parent" = $userParentCanonicalName
        "Enrolled" = $userIsEnrolled
        "Effective Policy" = $effectivePolicyName
        "Date/Time" = $eventDate
        "Enrollment Invitation" = $enrollmentInvitation
    }
    $reportRecords.Add($reportRecord)
}

# Export to CSV
$reportRecords | Sort-Object @sortParameters | Export-csv -NoTypeInformation -Path $csvFilePath

# Send mail 
#Send-MailMessage -To $to -from $from -SmtpServer $smtpServer -Subject $subject -Body $message -Attachments $csvFilePath

if ($removeCSVFile)
{
    # Remove temporary file
    Remove-Item $csvFilePath -Force
}

Errors running within Adaxes:

    The term 'New-AdmCriteria' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. Stack trace: at GetUserGuids, <No file>: line 21 at <ScriptBlock>, <No file>: line 83

    Exception calling "ExecuteSearch" with "0" argument(s): "Search filter is not specified. Parameter name: searchParameters" Stack trace: at GetUserGuids, <No file>: line 28 at <ScriptBlock>, <No file>: line 83
0

Hello,

Users enrolled in any multifactor authentication policy within Adaxes.

Do you mean accounts enrolled to use mobile applications either for Web interface sign in or password self-service?

Errors running within Adaxes

It looks like you are using a version of Adaxes older than 2023. The cmdlet is not available in this case and the error is expected. For details on how to check your Adaxes service version, see https://www.adaxes.com/help/CheckServiceVersion.

0

Yes, MFA for password self service or web interface sign in. Primarly to be used for external facing password self service.

Yes we're running 2021.1 (3.14.21404.0), because we've been working through issues managing all of our customer domains when we attempt to upgrade to 2023.2.

This MFA script task needs to be completed on the current 2021.1 version because we still do not have the unrelated upgrade issue resolved.

0

Hello,

Thank you for the provided details. How exactly do you want the script to work? Should it add all enrolled users from a predefined location? Should there be any other filters applied to the users?

0

We would like the script to add MFA enrolled users to a specific AD group. Ideally, we'll empty the group when this enrollment script runs periodically just in case someone gets unenrolled for some reason.

1 Answer

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

Hello,

Thank you for specifying. You can use a scheduled task like below. For details on creating scheduled tasks, have a look at the following tutorial: https://www.adaxes.com/help/ScheduleTasksForDirectoryManagement. image.png In the task:

The user is enrolled for TOTP

$applications = $Context.TargetObject.GetApplicationsUserEnrolledIn()
$Context.ConditionIsMet = $applications.Length -ne 0

The user is NOT enrolled for TOTP

$applications = $Context.TargetObject.GetApplicationsUserEnrolledIn()
$Context.ConditionIsMet = $applications.Length -eq 0

Related questions

0 votes
1 answer

Is it possible to script having users added (or removed) from a Security Group based on another AD Attribute? I have found ways to do this in Powershell (something like): ... just utilize the PS script and just run it through Adaxes on a timed fashion? Thanks!

asked Oct 7, 2014 by PunkinDonuts (360 points)
0 votes
1 answer

Is there a report which shows users who are not a member of a specific group?

asked May 3, 2023 by dgilmour (20 points)
0 votes
1 answer

Hello, I have my OUs structured so each department we're working with has an OU for their service accounts under their department OU. e.g. OU=Service Accounts,OU=Sales,OU= ... add each new OU to the scheduled task but I was hoping for something more hands off.

asked Oct 19, 2015 by drew.tittle (810 points)
0 votes
1 answer

For instance to execute a powershell script that enable MFA for all member in that group?

asked Jan 27, 2023 by samuel.anim-addo (20 points)
0 votes
1 answer

As part of offboarding a user I need to generate a report of all AD groups, Entra groups and all Azure / M365 roles and licenses the user has before they ... about keeping a record of the leavers configured profile to simplify cloning them onto new starters.

asked Jun 24 by dhardyuk (20 points)
3,434 questions
3,130 answers
7,984 comments
546,323 users