Developing with Adaxes .NET API
Adaxes exposes a set of ADSI classes and interfaces that you can use to interact with the Adaxes service. This enables you to build custom applications and integrations for Adaxes, using .NET programming languages.
This article introduces you to the base principles of developing .NET applications and external PowerShell scripts for Adaxes. That is, scripts which run in standalone PowerShell or within third-party applications. For information about writing internal PowerShell scripts to use in business rules, custom commands, and so on, see Server-side scripting.
Adaxes also has a REST API. Its functionality is limited to managing directory objects, but it is language-independent. As long as the programming or scripting language of your choice can send HTTP requests, you can use the REST API. For details, see the REST API overview.
Importing the Adaxes library
In PowerShell scripts
To get access to Adaxes classes and interfaces, import the Adaxes PowerShell module. The module has to be installed.
Import-Module Adaxes
This approach works in both, PowerShell 5.1 and PowerShell 7.
In .NET projects
Adaxes client library is available on NuGet as a package named Softerra.Adaxes.Client. To get access to Adaxes classes and interfaces, reference this package in your project.
The library can be used in projects that target:
- .NET Framework 4.8
- .NET 8.0 and above
If your project targets .NET, it also has to target the Windows operating system. Make sure to include -windows in TargetFramework in your project file. For example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
</PropertyGroup>
</Project>
<ItemGroup>
<PackageReference Include="Softerra.Adaxes.Client" Version="3.18.0" />
</ItemGroup>
Connecting to an Adaxes service
To connect to an Adaxes service instance running on a specific host:
- Create an instance of the AdmNamespace class.
- Call IAdmNamespace.GetServiceDirectly, passing the DNS host name or IP address of the computer to the method.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); } }
A successful connection is represented by the IAdmService interface.
Connecting to a nearest available service
If you have multiple Adaxes services sharing configuration, you can let Adaxes automatically pick the nearest available instance instead of specifying which instance to connect to.
To connect to the nearest available Adaxes service from a specific configuration set:
- Create an instance of the AdmNamespace class.
- If there are multiple configuration sets in your domain, set the DefaultConfigurationSet property of the AdmNamespace instance to the identifier of the desired configuration set.
- Call IAdmNamespace.GetNearestService. If you want to use the credentials of the currently logged on user to search for available service instances, set the second and the third parameters to
null.
- PowerShell
-
Import-Module Adaxes # Only for example purposes. Never store credentials in plaintext. $username = "admin@example.com" $password = "MyPassword!" # Connect to an Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetNearestService("mydomain.com", $username, $password) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Only for example purposes. Never store credentials in plaintext. string username = "admin@example.com"; string password = "MyPassword!"; // Connect to an Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetNearestService("mydomain.com", username, password); } }
Binding to objects
To perform any operation with an object, such as a user account, you need to bind to it. The binding method is identical for directory objects and Adaxes configuration objects – IAdmService.OpenObject.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsUser user = (IADsUser)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); } }
After binding to an object, you can use the appropriate interfaces to perform operations on the object. The interfaces you can use depend on the type of the object.
- All object types support the IADs and IAdmTop interfaces.
- User objects support the IADsUser interface.
- Group objects support the IADsGroup interface.
- Container objects, such as organizational units, support the IADsContainer interface.
For a full list, see Interfaces supported by objects.
Binding by specific identifiers
To bind to an object, you need to know its ADS path, which can be constructed from various object identifiers. Adaxes uses an identical ADS path structure for directory objects and Adaxes-specific objects.
"Adaxes://Server:Port/ObjectIdentifier"
-
Adaxes – the case sensitive namespace name.
-
Server (optional) – the domain controller name, IP address, or the domain name where the Adaxes will search for the directory object referred by the ADS path.
-
Port (optional) – the port to be used for the connection. If no port number is specified, the default port number will be used. The default port number is 389 if not using an SSL connection or 636 if using an SSL connection.
-
ObjectIdentifier – the identifier of an object. The identifier can be a distinguished name (DN), GUID, or SID.
Binding to an object by DN
To bind to a directory object using the object's distinguished name, the ObjectIdentifier part of the ADS path must contain the DN of the object. For example:
Adaxes://CN=John Smith,CN=Users,DC=mycompany,DC=comor
Adaxes://mydomain.com/CN=John Smith,CN=Users,DC=mycompany,DC=comFor details on how to get the DN of a directory object, see Get the DN of a directory object.
DNs of Microsoft Entra objects
The distinguished names of Microsoft Entra objects contain the object GUID to make the DN unique, because Microsoft Entra ID allows creating multiple objects with the same name. For example:
CN=John Smith\0AUID:952322ad597f4b1bb4ce40360a1bc07c,OU=Users,DC=example,DC=onmicrosoft,DC=com CN=John Smith\0AUID:86ecfb68226f43e295fe50a370b9db31,OU=Users,DC=example,DC=onmicrosoft,DC=comWhen you specify a DN to bind to a Microsoft Entra object, you can omit the GUID:
CN=John Smith,OU=Users,DC=example,DC=onmicrosoft,DC=comHowever, if multiple objects in Microsoft Entra ID have the same name (e.g. two users named John Smith) and are located in the same container in Adaxes, Adaxes will bind to the first object it encounters.
Example
The following code sample binds to a specific user account by DN and then disables the account.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=mycompany,DC=com", $null, $null, 0) $user.AccountDisabled = $true $user.SetInfo() - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsUser user = (IADsUser)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=mycompany,DC=com", null, null, 0); user.AccountDisabled = true; user.SetInfo(); } }
Binding to an object by GUID
Each object has a globally unique identifier (GUID) that is stored in the objectGUID property. As opposed to the distinguished name that changes when an object is renamed or moved, the GUID never changes.
If you want an ADS path to be valid after an object is renamed or moved, you need to specify the object's GUID as the ObjectIdentifier part. For example:
Adaxes://<GUID=90495758-7E98-47B6-AA98-5B49129EF1DB>If your Adaxes service manages multiple domains, it is recommended that the ADS path contains the name of the domain where the object is located. This will make the binding operation faster.
Adaxes://mydomain.com/<GUID=90495758-7E98-47B6-AA98-5B49129EF1DB>Example
The following code sample binds to a specific directory object by its DN, gets the GUID of the object, and then binds to the object using the GUID.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $object = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $guid = [Guid]$object.Get("objectGUID") $guidPath = "Adaxes://<GUID=$guid>" $object = $service.OpenObject($guidPath, $null, $null, 0) - C#
-
using System; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs obj = (IADs)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); byte[] guidBytes = (byte[])obj.Get("objectGUID"); Guid guid = new Guid(guidBytes); string guidPath = string.Format("Adaxes://<GUID={0}>", guid); obj = (IADs)service.OpenObject(guidPath, null, null, 0); } }
Binding to an object by SID
Each security principal (user, security group, computer) has a security identifier (SID) stored in the objectSID property. The SID is unique within the domain and does not change even if the object is renamed or moved to another container (within the same domain).
To bind to an object by its SID, set the ObjectIdentifier part of the ADS path as the SID of the object in the SDDL format. For example:
Adaxes://<SID=S-1-5-21-573937-2149998-410785>If your Adaxes service manages multiple domains, it is recommended that the ADS path contains the name of the domain where the object is located. This will make the binding operation faster.
Adaxes://mydomain.com/<SID=S-1-5-21-573937-2149998-410785>To convert the value of the objectSID property to the SDDL format, you can use the Sid class.
Example
The following code sample binds to a specific user by its DN, gets the SID of the user, and then binds to the user using the SID.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $sidBytes = $user.Get("objectSID") $sid = New-Object "Softerra.Adaxes.Adsi.Sid" @($sidBytes, 0) $sidPath = "Adaxes://<SID=$sid>" $user = $service.OpenObject($sidPath, $null, $null, 0) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs user = (IADs)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); byte[] sidBytes = (byte[])user.Get("objectSID"); Sid sid = new Sid(sidBytes, 0); string sidPath = string.Format("Adaxes://<SID={0}>", sid); user = (IADs)service.OpenObject(sidPath, null, null, 0); } }
Binding to well-known objects
Binding to Adaxes configuration objects {id="bind-to-adaxes-objects"}
You can bind to and manage Adaxes configuration objects similarly to how you would manage directory objects.
Each type of an Adaxes configuration object is stored in a dedicated container. There is a separate container for business rules, security roles, mail settings, web interface configurations, and so on. Each container has a user-friendly alias which you can use to obtain its ADS path. For a full list, see Aliases for containers that store Adaxes configuration objects.
The following code sample gets the ADS path of the container for business rules by its alias, and binds to it.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $businessRulesPath = $service.Backend.GetConfigurationContainerPath("BusinessRules") $container = $service.OpenObject($businessRulesPath, $null, $null, 0) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); string businessRulesPath = service.Backend.GetConfigurationContainerPath("BusinessRules"); IADsContainer container = (IADsContainer)service.OpenObject( businessRulesPath, null, null, 0); } }
Managing Adaxes configuration
For further information on managing Adaxes configuration objects, see the following articles:
Aliases for containers that store Adaxes configuration objects
| Container | Alias |
|---|---|
| Managed domains | ManagedDomains |
| Security roles | AccessControlRoles |
| Business rules | BusinessRules |
| Property patterns | PropertyPatterns |
| Custom commands | CustomCommands |
| Scheduled tasks | ScheduledTasks |
| Approval requests | ApprovalRequests |
| Business units | BusinessUnits |
| Policies for password self-service | PasswordSelfServicePolicies |
| Microsoft 365 tenants | CloudServicesO365 |
| Root container for reports | ReportsRoot |
| Reports \ Overview | ReportOverviews |
| Reports \ All Reports | Reports |
| Reports \ Schedule | ReportSchedule |
| Report categories | ReportCategories |
| SMS settings | SmsSettings |
| Mail settings | MailSettings |
| Service settings | ServiceSettings |
| Common settings for Adaxes services that share common configuration | ConfigurationSetSettings |
| Web interface configurations | WebUIConfigurationContainer |
| Client applications | ClientAppsContainer |
Binding to the parent object
To get the ADS path of the container where a particular object resides, you can use the IADs.Parent property. Every directory object implements the IADs interface.
Example
The following code sample binds to the parent container of a directory object.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $object = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=mycompany,DC=com", $null, $null, 0) $parent = $service.OpenObject($object.Parent, $null, $null, 0) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs obj = (IADs)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=mycompany,DC=com", null, null, 0); IADs parent = (IADs)service.OpenObject(obj.Parent, null, null, 0); } }
Binding to child objects
To bind to any child object in a container, you can use the IADsContainer.GetObject method. Every container object implements the IADsContainer interface.
Example
The following binds to a user named John Smith in the Users container.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $parent = $service.OpenObject("Adaxes://CN=Users,DC=mycompany,DC=com", $null, $null, 0) $child = $parent.GetObject("user", "CN=John Smith") - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsContainer parent = (IADsContainer)service.OpenObject( "Adaxes://CN=Users,DC=mycompany,DC=com", null, null, 0); IADs child = (IADs)parent.GetObject("user", "CN=John Smith"); } }
Alternatively, you can use the AdsPath helper class to build the ADS path of a child object like in the example below. This approach works only if the ADS path of the parent object is constructed using a distinguished name (DN).
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $parentPath = "Adaxes://CN=Users,DC=mycompany,DC=com" $adsPath = New-Object "Softerra.Adaxes.Adsi.AdsPath" $parentPath $childPath = $adsPath.CreateChildPath("CN=John Smith") $child = $service.OpenObject($childPath.ToString(), $null, $null, 0) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); const string parentPath = "Adaxes://CN=Users,DC=mycompany,DC=com"; AdsPath adsPath = new AdsPath(parentPath); AdsPath childPath = adsPath.CreateChildPath("CN=John Smith"); IADs child = (IADs)service.OpenObject(childPath.ToString(), null, null, 0); } }
Binding to the RootDSE
RootDSE (Root Directory Service Entry) is the root of the directory data tree. Properties of the RootDSE object can be used to retrieve data such as distinguished names of the domain, schema, and configuration containers. The following ADS path can be used to bind to the RootDSE:
Adaxes://<domain>/rootDSE
The <domain> is the name of a domain or the DNS name of a domain controller. The <domain> is optional. The following path is totally valid:
Adaxes://rootDSE
In this case, the path will refer to the RootDSE of the AD LDS instance used to store Adaxes configuration.
Example
The following code sample binds to the RootDSE of a domain and gets the DNS name of the domain controller being used by the Adaxes service.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $rootDse = $service.OpenObject("Adaxes://mydomain.com/rootDSE", $null, $null, 0) $dcDnsName = $rootDse.Get("dnsHostName") Write-Host $dcDnsName - C#
-
using System; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs rootDse = (IADs)service.OpenObject( "Adaxes://mydomain.com/rootDSE", null, null, 0); string dcDnsName = (string)rootDse.Get("dnsHostName"); Console.WriteLine(dcDnsName); } }
Binding to the domain partition {id=bind-to-domain-partition}
The domain partition (or the default naming context) stores directory objects like users, groups, computers and organizational units. The domain partition is replicated to all domain controllers of a domain. When you bind to the domain partition, you bind to the top container of the domain. If you want to search in the entire domain, you need to perform a search under the domain partition object.
The following ADS path can be used to bind to the domain partition of a domain:
Adaxes://<servername>
The <servername> is the name of a domain or the DNS name of a domain controller.
Example
The following code sample updates the minimum password length in the Default Domain Password Policy by updating the minPwdLength property of the domain partition object.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $defaultNC = $service.OpenObject("Adaxes://mydomain.com", $null, $null, 0) $defaultNC.Put("minPwdLength", 8) $defaultNC.SetInfo() - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs defaultNC = (IADs)service.OpenObject( "Adaxes://mydomain.com", null, null, 0); defaultNC.Put("minPwdLength", 8); defaultNC.SetInfo(); } }
Searching for objects
You can search for directory objects and Adaxes configuration objects, such as security roles, business rules, and scheduled tasks. To perform a search query, you need to bind to the container in which you want to search. All containers support the IAdmDirectorySearcher interface. Use the Criteria and SearchScope properties to define the search criteria and scope.
To start searching, call IAdmDirectorySearcher.ExecuteSearch. This method returns a IAdmSearchResultIterator interface that you can use to iterate through search results.
To fetch all search results, call IAdmSearchResultIterator.FetchAll. Each search result is represented by IAdmSearchResult.
The following code sample searches for all users from the Sales department in the organizational unit called People.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $searcher = $service.OpenObject( "Adaxes://OU=People,DC=company,DC=com", $null, $null, 0) $searcher.Criteria = New-AdmCriteria "user" {department -eq "Sales"} $searcher.SearchScope = "ADS_SCOPE_SUBTREE" try { $results = $searcher.ExecuteSearch() foreach ($result in $results.FetchAll()) { Write-Host $result.ADsPath } } finally { $results.Dispose() } - C#
-
using System; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; using Softerra.Adaxes.Directory.Criteria; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IAdmDirectorySearcher searcher = (IAdmDirectorySearcher)service.OpenObject( "Adaxes://OU=People,DC=company,DC=com", null, null, 0); // Build search criteria. SimpleCriteriaItem userCriteria = new() { Property = "department", Operator = "eq", Values = { "Sales" } }; Criteria criteria = new(); criteria.AddType("user", userCriteria); // Set search parameters and execute search. searcher.Criteria = criteria; searcher.SearchScope = ADS_SCOPEENUM.ADS_SCOPE_SUBTREE; using (IAdmSearchResultIterator results = searcher.ExecuteSearch()) { foreach (IAdmSearchResult result in results.FetchAll()) { Console.WriteLine(result.AdsPath); } } } }
See also:
Reading object properties
To read the properties of a directory object, use the Get or GetEx methods of the IADs interface, supported by all objects. All Adaxes-specific properties have the adm- prefix and can be retrieved like any other property.
The following code sample gets the username of a user account.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $username = $user.Get("userPrincipalName") - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs user = (IADs)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); string username = (string)user.Get("userPrincipalName"); } }
Certain properties are accessed through dedicated interfaces instead of IADs. For example, to get the Terminal Services profile path of a user, read the TerminalServicesProfilePath property of the IADsTSUserEx interface.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $tsProfilePath = $user.TerminalServicesProfilePath - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsTSUserEx tsUser = (IADsTSUserEx)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); string tsProfilePath = tsUser.TerminalServicesProfilePath; } }
For more information, see Interfaces supported by directory objects.
Creating objects
To create a new directory object, you need to bind to the organizational unit or container where you want to create the object.
After binding, call IADsContainer.Create and pass the object class and relative distinguished name (RDN) of the new object to the method. Use the same RDN structure when creating Active Directory and Entra ID objects.
The method returns an instance of an ADSI object which represents the new directory object. To save it to the directory, set its properties using IADs.Put or IADs.PutEx, and then call IADs.SetInfo.
The following code sample creates a new user in the Users container.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") # Bind to the parent container $parent = $service.OpenObject("Adaxes://CN=Users,DC=company,DC=com", $null, $null, 0) # Create a new user object $user = $parent.Create("user", "CN=John Smith") # Set object properties $user.Put("givenName", "John") # First name $user.Put("sn", "Smith") # Last name $user.Put("userPrincipalName", "jsmith") # Username $user.Put("unicodePwd", "secret") # Password $user.Put("pwdLastSet", 0) # Must change password at next logon $user.AccountDisabled = $false # Save the user to the directory $user.SetInfo() - C#
-
using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); // Bind to the parent container. IADsContainer parent = (IADsContainer)service.OpenObject( "Adaxes://CN=Users,DC=company,DC=com", null, null, 0); // Create a new user object. IADs user = (IADs)parent.Create("user", "CN=John Smith"); // Set object properties. user.Put("givenName", "John"); // First name user.Put("sn", "Smith"); // Last name user.Put("userPrincipalName", "jsmith"); // username user.Put("unicodePwd", "secret"); // Password user.Put("pwdLastSet", 0); // Must change password at next logon ((IADsUser)user).AccountDisabled = false; // Save the user to the directory. user.SetInfo(); } }
See also:
Modifying objects
To modify the properties of an object, use either IADs.Put or IADs.PutEx. Both methods make changes to property values in the property cache, which means they won't persist unless you explicitly save them. To save the changes to the directory, call IADs.SetInfo.
The following code sample modifies the description and the account expiration date of a user object.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $user.Put("description", "My description") $expirationDate = (Get-Date).AddDays(30) # Current date + 30 days $user.Put("accountExpires", $expirationDate) $user.SetInfo() - C#
-
using System; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADs user = (IADs)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); user.Put("description", "My description"); DateTime expirationDate = DateTime.Now.AddDays(30); // current date + 30 days user.Put("accountExpires", expirationDate); user.SetInfo(); } }
See also:
- Modifying user accounts
- Enabling and disabling user accounts
- Unlocking user accounts
- Renaming user accounts
- Modifying groups
- Modifying organizational units
Copying objects
To copy a directory object, bind to the container or organizational unit where the copy should be placed.
After binding to the container, call IADsContainer.CopyHere and pass the ADS path of the object you want to copy as the method parameter. If you copying an object to the same container, you must specify a different relative distinguished name (RDN) for the new object.
The following code sample creates a new user by copying an existing account.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") # Bind to the target container. $targetContainer = $service.OpenObject("Adaxes://CN=Users,DC=company,DC=com", $null, $null, 0) # Create a new user object by copying the user account of John Smith. $sourceUserPath = "Adaxes://CN=John Smith,OU=Sales,DC=company,DC=com" $newUserRdn = "CN=Ann Jones" $user = $targetContainer.CopyHere($sourceUserPath, $newUserRdn) # Update some properties. $user.Put("givenName", "Ann") # First name $user.Put("sn", "Jones") # Last name $user.Put("userPrincipalName", "ajones") # Username $user.Put("unicodePwd", "secret") # Password $user.Put("pwdLastSet", 0); # Must change password at next logon # Save the user to the directory. $user.SetInfo() - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); // Bind to the target container IADsContainer targetContainer = (IADsContainer)service.OpenObject( "Adaxes://CN=Users,DC=company,DC=com", null, null, 0); // Create a new user object by copying the user account of John Smith. const string sourceUserPath = "Adaxes://CN=John Smith,OU=Sales,DC=company,DC=com"; const string newUserRdn = "CN=Ann Jones"; IADs user = (IADs)targetContainer.CopyHere(sourceUserPath, newUserRdn); // Update some properties. user.Put("givenName", "Ann"); // First name user.Put("sn", "Jones"); // Last name user.Put("userPrincipalName", "ajones"); // Username user.Put("unicodePwd", "secret"); // Password user.Put("pwdLastSet", 0); // Must change password at next logon // Save the user to the directory. user.SetInfo(); } }
See also:
Moving objects
To move a directory object from one location to another, bind to the destination container or organizational unit.
After binding to the container, call IADsContainer.MoveHere and pass the ADS path of the object you want to move as the method parameter.
The following code sample moves a user from one organizational unit to another.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") # Bind to the target organizational unit. $targetOU = $service.OpenObject("Adaxes://CN=TargetOU,DC=company,DC=com", $null, $null, 0) # Move the account of John Smith from SourceOU to TargetOU. $userPath = "Adaxes://CN=John Smith,OU=SourceOU,DC=company,DC=com" $movedUser = $targetOU.MoveHere($userPath, $null) - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); // Bind to the target organizational unit. IADsContainer targetOU = (IADsContainer)service.OpenObject( "Adaxes://CN=TargetOU,DC=company,DC=com", null, null, 0); // Move the account of John Smith from SourceOU to TargetOU. const string userPath = "Adaxes://CN=John Smith,OU=SourceOU,DC=company,DC=com"; IADsUser movedUser = (IADsUser)targetOU.MoveHere(userPath, null); } }
Deleting objects
To delete a directory object, bind to it and call IADsDeleteOps.DeleteObject. The IADsDeleteOps interface is supported by all directory objects.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $user = $service.OpenObject("Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", $null, $null, 0) $user.DeleteObject("ADM_DELETEOBJECTFLAGS_AUTO") - C#
-
using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi; using Softerra.Adaxes.Interop.Adsi.Utils; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsDeleteOps user = (IADsDeleteOps)service.OpenObject( "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com", null, null, 0); user.DeleteObject(ADM_DELETEOBJECTFLAGS_ENUM.ADM_DELETEOBJECTFLAGS_AUTO); } }
Deleted objects can be restored. For details, see Restoring deleted objects.
Reading the execution log
When performing operations on directory objects, Adaxes may execute additional actions. For example, you may have a business rule that automatically assigns Microsoft 365 licenses to newly created users.
The information about additional actions is recorded in the execution log of an operation. To get the details of the last operation performed on a directory object, you can use the IAdmLastOperationOps interface supported by all directory objects. The IAdmLastOperationOps.GetLastOperationInfo method returns the IAdmOperationInfo interface, which you can use to obtain various information about the operation.
To get the operation execution log, use the IAdmOperationInfo.ExecutionLog property. The execution log is represented by the IAdmExecutionLogEntryCollection interface. Execution log records are represented by the IAdmExecutionLogEntry interface.
Example
The following code sample outputs the execution log of a user creation operation.
- PowerShell
-
Import-Module Adaxes # Connect to the Adaxes service. $ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace" $service = $ns.GetServiceDirectly("localhost") $parent = $service.OpenObject("Adaxes://CN=Users,DC=company,DC=com", $null, $null, 0) $user = $parent.Create("user", "CN=John Smith") $user.Put("userPrincipalName", "jsmith") $user.SetInfo() $operationInfo = $user.GetLastOperationInfo() $executionLog = $operationInfo.ExecutionLog Write-Host $executionLog.ToString() - C#
-
using System; using Interop; using Interop.Adsi; using Softerra.Adaxes.Adsi; using Softerra.Adaxes.Interop.Adsi.PersistentObjects; class Program { static void Main(string[] args) { // Connect to the Adaxes service. AdmNamespace ns = new AdmNamespace(); IAdmService service = ns.GetServiceDirectly("localhost"); IADsContainer parent = (IADsContainer)service.OpenObject( "Adaxes://CN=Users,DC=company,DC=com", null, null, 0); IADs user = (IADs)parent.Create("user", "CN=John Smith"); user.Put("userPrincipalName", "jsmith"); user.SetInfo(); IAdmOperationInfo operationInfo = ((IAdmLastOperationOps)user).GetLastOperationInfo(); IAdmExecutionLogEntryCollection executionLog = operationInfo.ExecutionLog; Console.Write(executionLog.ToString()); } }
For more ways of accessing log records, see Accessing log records.