export-ADData is a flexible PowerShell toolkit for exporting and importing Active Directory accounts. Easily convert AD data to CSV and back, with advanced import features for cross-domain migration, OU reorganization, granular mapping, and robust validation. Ideal for admins managing AD at scale.
export-ADData
: Export Active Directory (AD) users, groups, and computers to CSV files with flexible options.import-ADData
: Import AD users, groups, and computers from CSV files, supporting migration, OU reorganization, cross-domain moves, flattening, and detailed mapping.compare-ADCSV
: Compare two AD export CSVs for verification.check-ADUserPassword
: Check AD user password validity.Want to know when this project is updated?
Subscribe to the commit feed (no login required):
Paste the above link into your favorite RSS reader to get notified of new commits!
The basic usage is to export Active Directory objects by specifying the domain root or OU you wish to target. You are free to edit the exported CSV files—removing unwanted entries or making modifications—before using them as input for the import process. To assign passwords to users, add a “Password” column to the User CSV (this column is not present in the original export) and enter the desired passwords in plain text. Note that setting a password is required to properly restore the “Enabled” status of user accounts during import.
Note:
You can also perform a mass registration from scratch by first preparing CSV templates—simply export data from any sample Active Directory environment to generate the CSV structure, then edit these files as needed. The name of the source domain does not matter, as the importer (import-ADData.ps1
) can convert and map the objects to your new domain automatically.
HOWTO_prepare_CSV_data.md will be a help.
There are four major strategies for combining export and import:
Export specifying “DC=domain,DC=local” and import to “DC=domain,DC=local”
This is like backup and restore of AD users/groups. Note, however, that properties automatically generated by AD, such as GUID and SID, will have different values from the export source.
Export specifying “DC=olddomain,DC=local” and import to “DC=newdomain,DC=local”
Allocate the users/groups onto a new domain basis, translating the domain naming, respecting hierarchies.
Export specifying “DC=domain,DC=local” and import to “OU=osaka,DC=domain,DC=local”
Whole migration from the domain basis to a new specific OU, along with all intermediate OUs the users/groups depend on. In this case, users under CN=Users container are created just under OU=osaka because it is impossible to create Users
container nor OU=Users under the OU. Specifying “newdomain” is also a viable choice, which is like a move to a different floor of a different building.
Export specifying “OU=sales,DC=domain,DC=local” and import to “DC=domain,DC=local” with -TrimOU sales
Useful for flattening part of the OU hierarchy. By exporting from a specific OU and importing to the domain root with -TrimOU
, you can migrate only the objects under that OU directly to the root (or another OU), effectively removing their original OU nesting.
More advanced use is possible. For example, if you export from “OU=sales,DC=domain,DC=local”, and import into “OU=marketing,DC=domain,DC=local” with
-TrimOU "sales"
option, you can effectively move objects from the “sales” OU to the “marketing” OU in a two-step process—without manually editing every DN in the exported CSV data.
See HOWTO_prepare_CSV_data.md for a step-by-step guide on preparing CSV files for import/export.
Exports users, groups, and computers from Active Directory to CSV files using a specified domain or OU as the starting point.
-DNPath
) or dotted prefix (-DNPrefix
).Parameter | Alias | Required | Description |
---|---|---|---|
-DNPath |
-p |
Yes* | Base of the Domain hierarchy from which you want to retrieve objects. DistinguishedName form. |
-DNPrefix |
-d |
Yes* | Alternative to -DNPath . Dotted format (e.g., unit.domain.local ). |
-DCDepth |
 | No | Depth of DC components in -DNPrefix (default: 2). |
-OutPath |
-o |
No | Folder path for output CSVs. Dialog prompts if omitted. |
-Computer |
-comp |
No | Export Computers only. Users and Groups are not processed. |
-ExcludeSystemObject |
-nosys |
No | Exclude system accounts from export. |
* Either
-DNPath
or-DNPrefix
is required. They are mutually exclusive.
# Export AD Users and Groups from the Domain root to CSV files in "C:\ADExport", excluding system objects
.\export-ADData.ps1 -DNPath "DC=mydomain,DC=local" -OutPath "C:\ADExport" -ExcludeSystemObject
# Export AD Users and Groups, specifying a specific hierarchy base.
.\export-ADData.ps1 -DNPath "OU=unit,DC=mydomain,DC=local" -OutPath "C:\ADExport"
# Export AD Computers from the domain root, making the script prompt for output folder via dialog
.\export-ADData.ps1 -DNPath "DC=mydomain,DC=local" -Computer
Imports AD users, groups, and computers from CSV files, supporting domain migration, OU reorganization, and advanced mapping features. Automatically creates missing OUs and can handle a wide range of migration scenarios.
-User
, -Group
and -Computer
mode).ManagedBy
attribute for Groups separately in a dedicated run (-FixGroup
mode).CN=Users
, CN=Computers
) specially and appropriately, redirecting them to a designated OU when needed.-TrimOU
, -NoDefaultContainer
, -NoForceDefaultContainer
).ObjectClass
column in your CSV file to ensure it matches the selected import mode (user, group, or computer). If a mismatch is detected, you are warned before import begins. The -NoClassCheck
switch disables only the check on the ObjectClass
column; filename check is always enabled.Parameter | Alias | Required | Description |
---|---|---|---|
-DNPath |
-p |
Yes* | Target base DN for import (e.g., DC=newdomain,DC=local or OU=sales,DC=newdomain,DC=local ). The base DN object (OU or domain root) must already exist; this script does NOT create the base OU. |
-DNPrefix |
-d |
Yes* | Alternative to -DNPath . Dotted format (e.g., unit.domain.local ). |
-DCDepth |
 | No | Depth of DC components in -DNPrefix (default: 2). |
-User |
-u |
No | Import mode for users. Implied if -UserFile specified. |
-UserFile |
-uf |
No | Path to user CSV file. Dialog prompts if omitted and -User is set. |
-Group |
-g |
No | Import mode for groups. Implied if -GroupFile specified. |
-GroupFile |
-gf |
No | Path to group CSV file. Dialog prompts if omitted and -Group is set. |
-Computer |
-c |
No | Import mode for computers. Implied if -ComputerFile specified. |
-ComputerFile |
-cf |
No | Path to computer CSV file. Dialog prompts if omitted and -Computer is set. |
-FixGroup |
 | No | Operates in a post-import fixup mode for existing groups. Run after user and group imports. This sets ManagedBy references that require prior import of users/groups. See note below. |
-NoClassCheck |
 | No | By default, this script checks that all records in the input file have an ObjectClass matching the selected import mode (user, group, or computer). This switch disables the ObjectClass column check, allowing you to import files that are missing the column or contain mixed/incorrect types. Filename-based mode checks are always performed. Only use this if you know what you are doing. |
-IncludeSystemObject |
 | No | Import critical system users/groups (normally dangerous). |
-NewUPNSuffix |
 | No | New suffix for UserPrincipalName. Defaults to value derived from -DNPath . |
-NoProtectNewOU |
 | No | Newly created OUs will not be protected from accidental deletion. |
-TrimOU |
 | No | Remove one or more rightmost (nearest the domain root) OUs from source DNs before import. |
-NoDefaultContainer |
 | No | Place users/groups/computers with no OU or in “Default” container, i.e., CN=Users or CN=Computers , directly under the domain root. |
-NoForceDefaultContainer |
 | No | Import objects as their DN dictates: if the DN is directly under the domain root, import as is; if under default container e.g., CN=Users,DC=... , import as is. Mutually exclusive with -NoDefaultContainer . |
*Either
-DNPath
or-DNPrefix
is required. They are mutually exclusive.
-FixGroup
mode-FixGroup
enables a special post-import operation to set the ManagedBy
property on groups, using the same GroupFile as in the import step. This is necessary because ManagedBy
typically references user objects, which must already exist in the target AD. This mode does not create or remove any groups or users—it only updates the ManagedBy
property for existing groups, mapping references according to the -DNPath
, and advanced options (such as -TrimOU
, -NoDefaultContainer
, etc.).
-FixGroup
is mutually exclusive with user/group import modes.-GroupFile
(prompted if omitted).DNPath
(and advanced options if applicable) as your prior imports for correct results.Allows you to remove one or more OUs from the end (domain-root side) of the DistinguishedName of objects to be imported. The argument must be a comma-separated list of OU names (without the OU=
prefix).
-TrimOU "deeper,sales"
This example trims OU=sales
first, then OU=deeper
, from the rightmost OUs (nearest the domain root) of each DN path, if present.
Rules:
OU=
prefix, full DN fragments, or any other prefix.DC
, CN
, or any components other than OUs.-TrimOU
argument: ou
, cn
, dc
, users
, computers
, =
(case-insensitive match; =
is not permitted anywhere in the name).=
), but it prevents confusion and scripting errors.,,
) are invalid.-TrimOU
, always enclose the list in quotes (single or double), for example: -TrimOU "deeper,sales"
. This ensures PowerShell passes the entire list as a single argument.-TrimOU
that all entries have as their rightmost OUs.Examples:
Exported DN | -TrimOU Argument | Resulting Path After Trim | Explanation |
---|---|---|---|
OU=deeper,OU=sales,DC=domain,DC=local | sales | OU=deeper,DC=domain,DC=local | Match (rightmost OU is “sales”), only “sales” trimmed |
OU=deeper,OU=sales,DC=domain,DC=local | deeper | [ unchanged ] | No match (rightmost OU is “sales”, not “deeper”) |
OU=deeper,OU=sales,DC=domain,DC=local | deeper,sales | DC=domain,DC=local | Match (rightmost sequence is “deeper,sales”), both OUs trimmed |
OU=foo,OU=bar,OU=deeper,OU=sales,DC=domain,DC=local | deeper,sales | OU=foo,OU=bar,DC=domain,DC=local | Match (rightmost sequence), both OUs trimmed |
OU=foo,OU=bar,OU=deeper,OU=sales,DC=domain,DC=local | bar,deeper | [ unchanged ] | No match (rightmost OUs are “deeper,sales”) |
By default, users, groups, and computers that would otherwise be created directly under the domain root are placed in the domain’s “Default” container (CN=Users,DC=...
for users and groups, CN=Computers
for computers).
If you specify -NoDefaultContainer
, such objects are instead created directly under the domain root (DC=...
).
If you specify -NoForceDefaultContainer
, objects are imported exactly as their DN dictates:
This behavior also applies in cases where the resulting DN path ends up directly under the domain root, such as when all OUs are removed from an object’s original DN by the -TrimOU
option.
Precautions:
To set a password for users during import, add a "Password"
column to your User CSV (this column is not present in the original export) and enter the desired password in plain text.
Password is required to Enable
an account during import.
If the password is absent for a user, the account will be created but remain disabled.
You have two options to control the “User must change password at next logon” (ChangePasswordAtLogon
) setting for users to be imported:
"ChangePasswordAtLogon"
column to your User CSV.
TRUE
, YES
, or 1
, case-insensitive), the flag will be explicitly set (user must change password at next logon).FALSE
, NO
, or 0
), the flag will be explicitly cleared."Password"
column for that user."ChangePasswordAtLogon"
column is not present or is blank for a user, the script will honor the 0x80000
bit in the userAccountControl
column, if set, provided a password is also present. If both the 0x80000
bit and the "ChangePasswordAtLogon"
column are either absent or indicate a negative value, the script does not clear the “User must change password at next logon” flag; instead, the default password policy of the destination AD will apply.Golden rule:
The "ChangePasswordAtLogon"
column, if present and non-blank, takes precedence over the userAccountControl bit.
Summary Table:
ChangePasswordAtLogon (column) | Password Set | Action |
---|---|---|
TRUE/YES/1 | Yes | Set-ADUser -ChangePasswordAtLogon $true |
FALSE/NO/0 | Yes | Set-ADUser -ChangePasswordAtLogon $false |
TRUE/YES/1 | No | Warn, do not set |
FALSE/NO/0 | No | Set-ADUser -ChangePasswordAtLogon $false (this is allowed) |
blank/missing | Yes | userAccountControl bit 0x80000 → set flag if present |
blank/missing | No | userAccountControl bit 0x80000 → warn, do not set |
When importing or registering the ManagedBy
property, especially with advanced options or when targeting default containers, the destination OU or container for the referenced object may not match your expectations due to mapping rules and option interactions (such as -TrimOU
or -NoDefaultContainer
).
A common issue is that the Distinguished Name (DN) in the ManagedBy
field of the source CSV may not correspond to the DN of any imported user or group in the target AD. For example, if a computer object is imported into OU=sales,DC=domain,DC=local
, but its ManagedBy
value in the source CSV is directly on the domain-root (DC=domain,DC=local). The registration will fail unless a user with that exact DN exists in the destination AD.
Note: It is also impossible to register
ManagedBy
if it refers to aContact
object, which is currently out of scope for this script.
If you encounter unexpected placements or registration failures, review your DN mapping and advanced parameters.
You may need to adjust specific CSV records (for example, update the ManagedBy
DN to match the actual imported user’s DN), or hand register the ManagedBy
property after import to achieve the intended outcome.
These properties are normally sourced from the groupType
column. However, recalculating the hexadecimal integer for groupType
can be cumbersome when modifications are required.
To simplify this process, you may leave groupType
blank or prefix its value with a hash (“#”). In these cases, the script will use the string columns GroupCategory
and GroupScope
instead.
# Import AD Groups from CSV to a new domain, excluding system objects
.\import-ADData.ps1 -DNPath "DC=newdomain,DC=local" -GroupFile ".\Groups_olddomain_local.csv"
# Import AD Users from CSV to an OU on a domain, using a file dialog
.\import-ADData.ps1 -DNPath "OU=osaka,DC=newdomain,DC=local" -User
# NOTE: You must create the **base** OU "osaka" in the destination AD before running the import, if it does not already exist.
# Import AD Computers from CSV
.\import-ADData.ps1 -DNPath "DC=domain,DC=local" -ComputerFile "C:\Exp\Computers_olddomain_local.csv"
# Import users, trimming two rightmost OUs and placing directly under domain root (not in CN=Users)
.\import-ADData.ps1 -DNPath "DC=domain,DC=local" -UserFile "Users_deeper_sales_domain_local.csv" -TrimOU "deeper,sales" -NoDefaultContainer
# Import users, preserving DN structure (Users container or domain root) as-is
.\import-ADData.ps1 -DNPath "DC=domain,DC=local" -UserFile "Users.csv" -NoForceDefaultContainer
To set the ManagedBy
property for groups after importing users and groups, run the following sequence. Be sure to use the same -DNPath
and advanced options (such as -TrimOU
, -NoDefaultContainer
, etc.) for all runs to ensure DN mapping is consistent.
# Import groups
.\import-ADData.ps1 -DNPath "DC=newdomain,DC=local" -GroupFile ".\Groups_olddomain_local.csv"
# Import users
.\import-ADData.ps1 -DNPath "DC=newdomain,DC=local" -UserFile ".\Users_olddomain_local.csv"
# Register ManagedBy for groups using FixGroup mode
.\import-ADData.ps1 -DNPath "DC=newdomain,DC=local" -FixGroup -GroupFile ".\Groups_olddomain_local.csv"
-NoDefaultContainer
with caution; placing users or groups directly under the domain root can cause confusion in large AD environments. Many AD tools and scripts—including some Microsoft tools—do not expect or properly handle such objects.Compares two CSV exports of AD users, groups or computers, helping you verify changes, migrations, or synchronization.
Enabled
and PasswordNeverExpires
are also checked and reported, but these fields are considered auxiliary and do not affect the main inclusion criteria.-IncludeEqual
switch).Parameter | Alias | Required | Description |
---|---|---|---|
-OldFile |
-o |
Yes | Old CSV file (source) |
-NewFile |
-n |
Yes | New CSV file (destination) |
-OutFile |
 | No | Output CSV file for results |
-IncludeEqual |
 | No | Include entries with no detected difference |
# Compare two user CSVs and output differences to a file
.\compare-ADCSV.ps1 -OldFile "oldusers.csv" -NewFile "newusers.csv" -OutFile "diff.csv"
# Compare groups, show all entries (including identical)
.\compare-ADCSV.ps1 -OldFile "oldgroups.csv" -NewFile "newgroups.csv" -IncludeEqual
Checks whether a user’s password is set as expected by querying AD.
Parameter | Alias | Required | Description |
---|---|---|---|
-UserName |
-u |
Yes | Username to validate |
-Password |
-p |
Yes | Password in plain text (prompted if omitted) |
-Domain |
-d |
No | AD Domain to query (dot or DN format; uses preset if omitted) |
# Check if the user's password is correct
.\check-ADUserPassword.ps1 -UserName "jdoe" -Password "password123"
import-ADData.ps1
maintains a detailed log of all operations and errors. The log file is saved as import-ADData.log
in the script directory.
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
Tatsuya Nonogaki