In preparation for a test, we need to load a Windows Server VM with up to 400,000 users and 100,000 groups, and various mappings between them.
A powershell script has been written to achieve this, running on a Server 2012 R2 VM (4 cores, 8GB RAM). However, at the rate the script is running, it's looking like it could take more than a month to complete.
We've tried the script using both the net command and the Add-AD commands to see if there's any speed increase. There doesn't seem to be. The script uses several For loops to iterate through creating users, creating groups, and adding certain users numbers to group numbers.
Command examples were:
#net users $userName mypassword /add
#New-ADUser -Name $userName -SamAccountName $userName -DisplayName $userName -AccountPassword mypassword -Enabled $true
and
net group $groupName $userName /add
#Add-ADGroupMember -Identity $groupName -Members $userName
Any suggestions on the fastest way to load an AD with a mass of new users/groups/mappings?
Thanks
The PowerShell cmdlets for AD are convenient, but they are not efficient.
Using ADSI directly will likely be faster because it gives you more control of what's going on. PowerShell has a shortcut notation of [ADSI]"LDAP://thepath" to create objects (they're technically DirectoryEntry object, but the examples here use the IADs methods).
There are instructions on creating users here, but I can summarize it:
[ADSI]$OU = "LDAP://OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local"
$new = $OU.Create("user","CN=Ginger Snaps")
$new.put("samaccountname","gsnaps")
$new.setinfo()
#Account is created disabled, so we need to enable and set a password
#(the password can't be set until it's created)
$new.put("userAccountControl",544)
$new.setpassword("P#ssw0rd")
$new.setinfo()
You use $new.put() for whatever other attributes you want to set. You can also create groups this way too, just use "group" instead of "user" in the Create() method.
This is still going to take a while. It's the network connections that will hurt you the most. So you have to:
Get as physically close to a DC as you can (run it on a DC if you can), and
Keep the number of network requests down
If you do run this on a DC, then (if the domain has more than one DC) make sure to target the DC that you're on. You can do that by injecting the DC name into the LDAP:// strings, like this:
"LDAP://dc1.domain.com/OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local"
Number 2 is limited by the fact that you have to do 2 requests per new user (one to create, one to set password). But you can do other things to keep the number down, like create all the users first and store the distinguishedName of each new user, which you can calculate yourself (rather than asking AD for it) because it's the CN=user that you pass to Create() plus the OU. So for the example above, the DN of the new user is:
CN=Ginger Snaps,OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local
Once you have all those, you can create the groups and add all the members in one go. For example:
[ADSI]$OU = "LDAP://OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local"
$new = $OU.Create("group","CN=group1")
$new.put("samaccountname","group1")
$members = #("CN=Ginger Snaps,OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local", `
"CN=Another User,OU=IT,OU=Departments,OU=Employees,DC=Globomantics,DC=Local")
$new.put("member", $members)
$new.setinfo()
Where $members is your array of the distinguishedName for each member.
This way you have one network request that creates the whole group with the members already set, rather than one network request for each member.
Related
I've seen multiple examples on adding a user to a group after creation, but not at the time of creation. Is that possible? Currently, I have something like this: (most attributes removed for simplicity)
$user = New-ADUser -Name "person" -Path "OU=test,OU=myorg" -Office "home" -samAccountName "snuffy.john" -PassThru
if ($user){
Add-ADGroupMember -Identity mygroup -Members $user.samAccountName
}
This causes two calls to the ldap server for each user added and I'm trying to prevent that as I have many thousands of users and the script takes a long time to run. I've checked MS docs but didn't see anything. If it's not possible, it is what it is. Thought I'd try asking at least. I also just started using powershell last week.
You may turn your thinking. with thousands of users I would do it like this.
First create all users.
Then get them by Get-ADUser -Filter * -SearchBase "OU=test,OU=myorg" (or maybe Filter the CreatedDate Attribute to get all new users)
After getting the users try to filter them for the groups you want to put them into and use the Add-ADGroupMember cmdlet, which accepts an array of ADPrincipals for parameter "-members".
This will speed up your code.
Huhu,
is it possible to disable the search for other Users in an AD? In this picture i am logged in as "normal" User.
Get-ADuser search
Here is a Picture of our AD structure.
AD Structure
So i don't want that a User can find another User in the Users OU by powershell (get-aduser)
is that possible?
I hope you have enough informations to understand my issue.
Regards
This is not really a thing in Windows proper. The default in AD is all users read. Secondly, anyone in AD is likely to have an email alias and thus search where they use PowerShell or not by their email alias/SMTP address, and should be for email lookups, so, IMHO, this is a futile use case.
One does not need Get-ADUser to find a user in AD. One has been able to do this since AD has been around and well before PowerShell was ever a thing using older scripting methods with .bat/.cmd/.vbs/WMI/ADSI or .Net directly and that is how it was done before PowerShell was ever a thing.
If you don't what a user using a specific cmdlet/cmdlets, then you need to implement restrictions via 'PowerShell just enough administration (JEA)'
Again, One does not need to use PowerShell to scan and get info from AD, a well documented and used thing, for folks who have PowerShell disabled (or tried to) in their environments.
Example:
How Can I Get a List of All the Users in an OU and Its Sub-OUs?
VBScript:
On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Set objConnection = CreateObject(“ADODB.Connection”)
Set objCommand = CreateObject(“ADODB.Command”)
objConnection.Provider = “ADsDSOObject”
objConnection.Open “Active Directory Provider”
Set objCommand.ActiveConnection = objConnection
objCommand.Properties(“Page Size”) = 1000
objCommand.Properties(“Searchscope”) = ADS_SCOPE_SUBTREE
objCommand.CommandText = _
“SELECT Name FROM ‘LDAP://ou=finance,dc=fabrikam,dc=com’ WHERE objectCategory=’user'”
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
Wscript.Echo objRecordSet.Fields(“Name”).Value
objRecordSet.MoveNext
Loop
Or
ADDS PowerShell (CMDLET, ADSI & .Net) to Expedite Your Tasks
ADSI:
<#
PowerShell ADSI(Active Directory Services Interface) commands
1. How to find the users property.
#>
$users1 = [ADSI]"LDAP://cn=copy,cn=users,dc=contoso,dc=com"
$users1 | select *
# 2. How to find the Group members for a Group.
$test = [ADSI]"LDAP://CN=test,CN=Users,DC=contoso,DC=com"
$test.Member |
ForEach-Object {[ADSI]"LDAP://$_"} |
select samccountname, samaccounttype
# 3. Listing an OU Contents
$ou=[ADSI]"LDAP://ou=tech,dc=contoso,dc=com"
$ou.PSBase.Children
$ou.PSBase.Children | Format-Table sAMAccountName
So this worked for me:
I just got it working by unchecking the "List Contents" from the "authenticated users" of the "Users" OU and I did not recognized any side effects so far.
Rights of Authenticated Users
And the "normal" User can't see the other users anymore by a query.
Tested with powershell: AD-GetUser and CMD "net user"
Query Result
So my problem is solved if there won't be any side effects in the future.
I will let you know.
Cheers
I am a beginner in PowerShell, so I have been tinkering around it to learn more about its uses. Currently I have a task that requires me to remove a list of chosen groups from a user.
The user is in a different domain, hence I have used LDAP.
I am able to find that user and bind it to an object using the command below:
[ADSI]$user = "LDAP://CN=xxx,OU=xxx,DC=xxx"*
so I am able to display whatever information required from $user e.g. $user.sAMAccountName, $user.DisplayName it works. Except for the users groups...
I try the command to remove the groups listed in the user based on sAMAccountName; as all the users in that domain is identified easier by sAMAccountName, it doesnt work.
this command was used just to see if I can remove one group first; if $user can be found and read by the command; it doesnt work
remove-adgroupmember "GroupName" $user.sAMAccountName
or when I tried to display the groups instead to see if $user can be read, it also doesnt work,
Get-ADPrincipalGroupMembership [ADSI]$user = "LDAP://CN=xxx,OU=xxx,DC=xxx" |
select name
I have tried to search regarding this issue, but almost all the tips does not involve different domains or used ldap for other domains, it uses the primary domain instead, and I am not sure on how to edit that part.
If anyone can advice me I would be very grateful, thank you =)
I'm trying to create a script to add a user of my main domain to a group of my secondary domain.
I have two user (userA and userB) on my main domain domainA and I need to add those users to 150 groups on my secondary domain domainB.
I've got a script to do exactly what I want, but only works on the current domain were I run the script. it cannot execute for another (remote) domain.
import-csv path_csv_file.csv | % {Add-ADGroupMember $_.groupname –Members $_.users }
The CSV contains the groups from DomainB are in Column A (groupname) and the users from DomainA that I have in column B (users).
This is the best answer I can give you with what you gave me.
You are missing two essential parameters to Add-ADGroupMember
You can specify a different domain with:
-Server domain.example.com
You will most likely have to specify different credentials for a different domain as well:
-Credential (Get-Credentials)
Since you are doing this in two different domains, store two different credentials:
$domain1_credentials = Get-Credentials # Give domain1\username - password
$domain2_credentials = Get-Credentials # Give domain2\username - password
Ok guys, I've already solve the problem.
So I find out the script that allow me to add a user from domainA to a group on domainB.
This is the solution:
$Group = import-csv path_csv_file.csv | % {Get-ADGroup $_.groupname -Server serverB.tla.domainB.local}
Add-ADPrincipalGroupMembership user_domainA -MemberOf $Group
Thank you for your help!
So I have an interesting script I am trying to figure out, basically I need to change a custom attribute value to a new one. The problem is its for both users and computers and not specific to the groups. So for instance the value might be Billing1 for several users in an OU and this need to be Billing2. So I need to find any instance of the Value of Billing1 and change it to Billing2 not knowing the user or computer object. I can successfully change one at a time if I know who the user is by using Set-ADUser, Set-ADComputer and even with Set-AdObject but I need to figure out a Find and replace function.
I have searched for this and I have found examples of where I can use CSV for users and computers but again I don't know who has what since the value in the attribute can vary and also changes if a reorg happens.
got the correct script...
Get-ADComputer -Properties enterattributename -Filter {enterattributename -like "value to search" } |Set-ADComputer –replace #{ enterattributename =”value to change”}
this also can be applied to Get-ADUser and Get-ADObject