Validate/modify user input using a script

With Adaxes, you can enforce various constraints on the data entered by users. For example, using property patterns it is possible to validate property values with regular expressions, specify a list of allowed values for a property, make a property required, etc.

However, sometimes that's not enough. For example, you may want to ensure that the employee ID specified for a new user is unique, verify that the HR database contains a record for the user, add a digit to the username if it already exists, etc. This can be done with the help of PowerShell scripts.

In this tutorial, you will learn how to create a business rule to automatically execute a script before a user account is created, and how to use the script to validate and modify the information entered for the user.

  1. Launch Adaxes Administration console.

     How { #collapse1}
    • On the computer where Adaxes Administration console is installed, open Windows Start menu.

    • Click Adaxes Administration Console.

  2. Right-click your Adaxes service, point to New and click Business Rule.

  3. Enter a name for the new business rule and click Next.

  4. To trigger the business rule before a user account is created:

    • In the Object Type list, select User.

    • Select Before and then select creating a user.

    Click Next.

  5. Click Add an action.

  6. Select Run a program or PowerShell script.

    Click the button to provide a custom description for the action.

  7. Click the Edit button.

    To get information about the user you can use value references (e.g. %username%). Value references will be replaced with corresponding property values of the user account. For example:

    $htable = @{FirstName="%firstname%";LastName="%lastname%";Department="%department%";}
    

    After replacing the value references, the script will look as follows:

    $htable = @{FirstName="John";LastName="Doe";Department="Marketing";}
    

    To get and update user account properties and control operation execution, you can use a variable called $Context. It is a predefined PowerShell variable of type ExecuteScriptContext.

    To determine whether a value was specified for a property, call the IsPropertyModified method. To get a property value, call the GetModifiedPropertyValue method. To update a property value, use the SetModifiedPropertyValue method.

    if ($Context.IsPropertyModified("userPrincipalName"))
    {
        # Get the property value.
        $newValue = $Context.GetModifiedPropertyValue("userPrincipalName")
        
        # Modify the value.
        $newValue = $newValue + "1"
        
        # Update the value.
        $Context.SetModifiedPropertyValue("userPrincipalName", $newValue)
    }
    

    To determine whether the user's password was modified during the operation, use the IsPasswordChanged method. To get the new password, call the GetNewPassword method.

    if ($Context.IsPasswordChanged())
    {
        $newPassword = $Context.GetNewPassword()
        ...
    }
    

    To cancel the operation, call the Cancel method.

    if ($isValueInvalid)
    {
        $Context.Cancel("The value is invalid.")
        return
    }
    

    To add a record to the operation Execution Log, use the LogMessage method. The second parameter of the method can take the following values: "Information", "Warning", and "Error".

    $Context.LogMessage("The username has been changed.", "Information")
    

    To get the domain name of the user, call the GetObjectDomain method. The method takes the distinguished name (DN) of an object as the input parameter.

    $domainName = $Context.GetObjectDomain("%distinguishedName%")
    

    To send an email or SMS message, use SendMail and SendSms methods.

    $Context.SendMail($toAddress, $subject, $bodyText, $bodyHtml)
    $Context.SendSms($mobileNumber, $text)
    
     Example 1 – Validate that Employee ID is unique and formatted correctly
    Import-Module Adaxes
    
    if ($Context.IsPropertyModified("employeeID"))
    {
        # Get the value.
        $value = $Context.GetModifiedPropertyValue("employeeID")
    
        # Validate the value.
        if (([System.String]::IsNullOrEmpty($value)) -or (-not($value.Contains("-"))))
        {
            $Context.Cancel("Invalid Employee ID!")
            return
        }
    
        # Check whether the value is unique.
        if ((Get-AdmUser -Filter 'employeeID -eq $value') -ne $null)
        {
            $Context.Cancel("A user with the specified Employee ID already exists!")
            return
        }
    }
    

    To use the script, install Adaxes PowerShellModule on the computer, where your Adaxes service is running.

     Example 2 – Add a digit to the username if it is not unique
    Import-Module Adaxes
    
    function IsUserNameUnique($isOnPremiseObject, $username, $samAccountName)
    {
        if ($isOnPremiseObject)
        {
            $filter = {userPrincipalName -eq $username -or sAMAccountName -eq $samAccountName}
        }
        else
        {
            $filter = {userPrincipalName -eq $username}
        }
    
        $domain = $Context.GetObjectDomain("%distinguishedName%")
        $user = Get-AdmUser -Filter $filter `
            -Server $domain -AdaxesService localhost
        return $null -eq $user
    } 
    
    # Check directory type.
    $isOnPremiseObject = $Context.TargetObject.DirectoryType -eq 1
    
    # Get the username.
    $username = $Context.GetModifiedPropertyValue("userPrincipalName")
    $samAccountName = $Context.GetModifiedPropertyValue("samAccountName") 
    
    # Check if it is unique.
    if (IsUserNameUnique $isOnPremiseObject $username $samAccountName)
    {
        return
    } 
    
    # If the username is not unique, add a digit to it.
    $localPart, $domainPart = $username.Split("@")
    $uniqueUsername = $Null
    $samAccountNameUnique = $Null
    for ($i = 1;; $i++)
    {
        $uniqueUsername = $localPart + $i + "@" + $domainPart
        if ($isOnPremiseObject)
        {
            $samAccountNameUnique = $samAccountName + $i
        }
    
        if (IsUserNameUnique $isOnPremiseObject $uniqueUsername $samAccountNameUnique)
        {
            break
        }
    } 
    
    # Update username.
    $Context.SetModifiedPropertyValue("userPrincipalName", $uniqueUsername)
    $Context.LogMessage("The username has been changed to " + $uniqueUsername `
        + ".", "Information")
    
    if ($Context.IsPropertyModified("sAMAccountName"))
    {
        # Update samAccountName
        $Context.SetModifiedPropertyValue("sAMAccountName", $samAccountNameUnique)
        $Context.LogMessage("The samAccountName has been changed to " + $samAccountNameUnique `
            + ".", "Information")
    }
    

    To use the script, install Adaxes PowerShell Module on the computer, where your Adaxes service is running.

     Example 3 – Rename the user if the Full Name is not unique within the OU
    Import-Module Adaxes
    
    function DoesObjectExist($objectDN)
    {
        $obj = Get-AdmObject $objectDN.ToString() -ErrorAction SilentlyContinue
        return $obj -ne $null
    }
    
    # Get the user's distinguished name (DN).
    $objectDN = $Context.TargetObject.ObjectInfo.DN
    
    # Check whether an object with the same DN already exists.
    if (-not (DoesObjectExist $objectDN))
    {
        return
    }
    $rdn = $objectDN.Leaf
    for ($i = 1;; $i++)
    {
        # Build a new DN.
        $objectName = $rdn.Value + $i
        $newRdn = New-Object "Softerra.Adaxes.Ldap.Rdn" $rdn.Type, $objectName
        $objectDN = $objectDN.Parent
        $objectDN.AddLeaf($newRdn)
        if (-not (DoesObjectExist $objectDN))
        {
            # Rename the user.
            $Context.SetModifiedPropertyValue("name", $objectName)
            $Context.LogMessage("Full Name has been changed to " + $objectName `
                + ".", "Information")
            break
        }
    }
    

    To use the script, install Adaxes PowerShell Module on the computer, where your Adaxes service is running.

     Example 4 – Check the password length
    $PasswordMinLength = 5
    if ($Context.IsPasswordChanged())
    {
        # Get the password.
        $newPassword = $Context.GetNewPassword()
        
        # Check the password length.
        if ($newPassword.Length -lt $PasswordMinLength)
        {
            $Context.Cancel("The password is too short.")
            return
        }
    }
    
     Example 5 – Remove spaces from the username
    $spacesRemoved = $false
    
    # Username
    if ($Context.IsPropertyModified("userPrincipalName"))
    {
        $userPrincipalName = $Context.GetModifiedPropertyValue("userPrincipalName")
        if ($userPrincipalName.Contains(" "))
        {
            # Remove spaces.
            $userPrincipalName = $userPrincipalName.Replace(" ", "")
            # Update the username.
            $Context.SetModifiedPropertyValue("userPrincipalName", $userPrincipalName)
            $spacesRemoved = $true
        }
    }
    
    # Log a message.
    if ($spacesRemoved)
    {
        $Context.LogMessage("Spaces have been removed from the username.", "Information")
    }
    
     Example 6 – Replace specific characters in the username
    $props = @("userPrincipalName", "sAMAccountName")
    $map = @{ "å"="a"; "ö"="o"; "ä"="a";"ü"="u"; "ñ"="n"; "é"="e"; " "="-"; }
    
    foreach ($prop in $props)
    {
        if ($Context.IsPropertyModified($prop))
        {
            $value = $Context.GetModifiedPropertyValue($prop)
    
            foreach ($key in $map.Keys)
            {
                $value = $value.Replace($key, $map[$key])
            }
    
            $Context.SetModifiedPropertyValue($prop, $value)
            $Context.LogMessage($prop + ": " + $value, "Information")
        }
    }
    

    For more information on how to create scripts for business rules, see Server-side scripting.

    For information about the cmdlets included in the Adaxes PowerShell module, see Adaxes PowerShell Module.

  8. Optionally, you may want the business rule to run the script only if certain conditions are met.

     Step by step { #step_by_step_condition .mb-7}
    • Right-click the action and then click Add Condition in the context menu.

    • Select the If <property> <relation> <value> condition.

    • In the Condition Parameters section, specify Employee Type - equals - Subcontractor.

    • Click OK.

    You can also use scripts to check conditions.

     Step by step { #step_by_step_condition_script .mb-7 }
    • Right-click the action and then click Add Condition in the context menu.

    • Select the If PowerShell script returns true condition.

    • Click the Edit button to open the script editor.

    • When done, click OK.

    If a condition is met, the script must set the ConditionIsMet property of the $Context variable to $true:

    $Context.ConditionIsMet = $true
    
     Example 1 – If the username contains a digit
    $username = "%username%"
    foreach ($char in $username.ToCharArray())
    {
        if ([System.Char]::IsDigit($char))
        {
            $Context.ConditionIsMet = $true
            return
        }
    }
    
     Example 2 – If Department has changed and Manager hasn't changed
    $departmentModified = $Context.IsPropertyModified("department")
    $managerModified = $Context.IsPropertyModified("manager")
    $Context.ConditionIsMet = $departmentModified -and -not $managerModified
    
     Example 3 – If a user with the specified Employee ID is not found in SQL database
    $DatabaseHost = "localhost"
    $DatabaseName = "HRDatabase"
    $DatabaseTableName = "Users"
    $DatabaseIDField = "UserId"
    
    # Connect using the credentials of the Adaxes service accouunt.
    $DatabaseUsername = $null
    $DatabasePassword = $null
    
    $Context.ConditionIsMet = $true
    
    $employeeId = "%employeeID%"
    if ([System.String]::IsNullOrEmpty($employeeId))
    {
        $Context.LogMessage("Employee ID is not specified!", "Warning")
        return
    }
    
    $connectionString = "Data Source=$DatabaseHost; Initial Catalog=$DatabaseName;"
    if ($DatabaseUsername -eq $null)
    {
        $connectionString = $connectionString + "Integrated Security=SSPI;"
    }
    else
    {
        $connectionString = $connectionString 
            + "User ID=$DatabaseUsername;Password=$DatabasePassword;"
    }
    $connection = New-Object "System.Data.SqlClient.SqlConnection"  $connectionString
    $connection.Open()
    $command = $connection.CreateCommand()
    $command.CommandText = "SELECT COUNT(*) FROM " + $DatabaseTableName + " WHERE " +`
        $DatabaseIDField + "=@UserID"
    $command.Parameters.Add("@UserID", $employeeId) | Out-Null
    $count = $command.ExecuteScalar()
    
    $Context.ConditionIsMet = $count -eq 0
    
    $command.Dispose()
    $connection.Close()
    

    For information on how to create scripts for business rules, see Server-side scripting.

    When done, click Next.

  9. On the Activity Scope step, click Add.

    Select from the following items:

    • All Objects – select to execute the business rule when a user account is created in any domain managed by Adaxes.

    • Domain – select to execute the business rule when a user account is created in a specific domain.

    • OU or Container – select to execute the business rule when a user account is created in a specific organizational unit or container.

    You can exclude specific organizational units and domains from the activity scope of the business rule. For example, if you've assigned the business rule over the whole domain, but do not want it to trigger when a user account is created in a specific organizational unit, you can exclude the organizational unit from the activity scope. To exclude an object, select the Exclude the selection option in the Assignment Options dialog.

     Step by step { #exclude_scope}
    • Click the object you want to exclude.

    • In the Assignment Options dialog, select the Exclude the selection option.

    • Click OK.

  10. When done, click OK and then click Finish.