I do not have access to Admin Rights hence I cannot install the AD module.
How do I retrieve users' usergroup on different domains without the use of Active Directory? Any ideas? I have access to other domains, but I'm only able to access users in my own domain using this script, but not others.
$filedirectory = "C:\Users\x\Desktop\z\Project\test.txt"
$outputdirectory = "C:\Users\x\Desktop\Project\Export.csv"
$allusernames = Get-Content $filedirectory
$groups = ""
$resultarray =#()
foreach ($allusernames in $allusernames) {
$groupObject = new-object PSObject
$currentusername = $allusernames
$groups = ([ADSISEARCHER]"samaccountname=$($currentusername)").Findone().Properties.memberof -replace '^CN=([^,]+).+$','$1' | out-string
$groupObject | add-member -MemberType NoteProperty -name "User" -Value $currentusername
$groupObject | Add-Member -MemberType NoteProperty -name "Groups" -Value $groups
$resultarray +=$groupObject
}
$resultarray | export-csv -Path $outputdirectory -NoTypeInformation
You can use ADSI to specify any domain and built the ADSIsearcher from it, like this:
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$domain")
Note, that you can also use GC:// to query a Global Catalog and [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() to dynamically get the current forest and its domains.
Because you are querying group memberships, please note that the group membership is an attribute of the group, not the user. The memberof attribute only shows group memberships of domains of the same domain, if the group is domain local.
$ForestName = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Name
$root = [ADSI]"GC://$ForestName"
$Searcher = [ADSISEARCHER]$root
This was what I used.
Related
I am trying to get a powershell script to export all users in an OU and sub OUs which I can do fine, but when I try to get the user's OU, I get nothing for the OU. I have looked all over online and found a few scripts that pull just the user's OU, but they are a little slow and I can't seem to get them to pull groups or is for pulling from one group instead of listing all users and their groups.
I am trying to export this list and sort by OU so that I can ensure each student is in the proper groups. We have had a few students that were in extra groups and I want a quick and easy look to find those students.
#Student
$Report = #()
#Collect all users
$Users = Get-ADUser -Filter * -SearchBase 'OU=Student,DC=domain,DC=com' -Properties distinguishedname, Name, GivenName, SurName, SamAccountName, UserPrincipalName, MemberOf, Enabled -ResultSetSize $Null
# Use ForEach loop, as we need group membership for every account that is collected.
# MemberOf property of User object has the list of groups and is available in DN format.
Foreach($User in $users){
$UserGroupCollection = $User.MemberOf
#This Array will hold Group Names to which the user belongs.
$UserGroupMembership = #()
#To get the Group Names from DN format we will again use Foreach loop to query every DN and retrieve the Name property of Group.
Foreach($UserGroup in $UserGroupCollection){
$GroupDetails = Get-ADGroup -Identity $UserGroup
#Here we will add each group Name to UserGroupMembership array
$UserGroupMembership += $GroupDetails.Name
}
#As the UserGroupMembership is array we need to join element with ',' as the seperator
$Groups = $UserGroupMembership -join ','
#Creating custom objects
$Out = New-Object PSObject
$Out | Add-Member -MemberType noteproperty -Name DistinguishedName -Value #{Name="DistinguishedName";Expression={$_.distinguishedname | ForEach-Object {$_ -replace '^.+?(?<!\\),',''}}}
$Out | Add-Member -MemberType noteproperty -Name Name -Value $User.Name
$Out | Add-Member -MemberType noteproperty -Name UserName -Value $User.SamAccountName
$Out | Add-Member -MemberType noteproperty -Name Status -Value $User.Enabled
$Out | Add-Member -MemberType noteproperty -Name Groups -Value $Groups
$Report += $Out
}
#Output to screen as well as csv file.
$Report | Sort-Object DistinguishedName | FT -AutoSize
$Report | Sort-Object DistinguishedName | Export-Csv -Path $env:temp\students.csv -NoTypeInformation
There you go, I added some comments to help you understand the thought process.
This should be a lot faster than what you were doing.
The problem while adding your OUs was here:
$Out | Add-Member -MemberType noteproperty -Name DistinguishedName -Value #{Name="DistinguishedName";Expression={$_.distinguishedname | ForEach-Object {$_ -replace '^.+?(?<!\\),',''}}}
Which should've been:
$Out | Add-Member -MemberType noteproperty -Name DistinguishedName -Value ($user.distinguishedname -replace '^.+?(?<!\\),','')
#Student
$Report = [system.collections.generic.list[pscustomobject]]::new()
# Using Collection.Generic.List instead of System.Array for efficiency
#Collect all users
$Users = Get-ADUser -Filter * -SearchBase 'OU=Student,DC=domain,DC=com' -Properties MemberOf
# -> Use -SearchScope Subtree if you want to go all the way down in OU recursion starting from the 'OU=Student'
# -> distinguishedname, Name, GivenName, SurName, SamAccountName, UserPrincipalName and Enabled are Default Properties
# of Get-ADUser, no need to call them.
# -> -ResultSetSize $Null is default for Get-ADUSer, no need to call it
# Use ForEach loop, as we need group membership for every account that is collected.
# MemberOf property of User object has the list of groups and is available in DN format.
Foreach($User in $users)
{
#This Array will hold Group Names to which the user belongs.
$UserGroupMembership = [system.collections.generic.list[string]]::new()
#To get the Group Names from DN format we will again use Foreach loop to query every DN and retrieve the Name property of Group.
Foreach($UserGroup in $User.MemberOf)
{
# $GroupDetails = Get-ADGroup -Identity $UserGroup
# -> Instead of this, we can do some string manipulation
# which will be a lot faster and give you the same results.
$UserGroupMembership.Add($UserGroup.Split(',OU=')[0].replace('CN=',''))
}
#As the UserGroupMembership is array we need to join element with ',' as the seperator
$Groups = $UserGroupMembership -join ','
#Creating custom objects
<#
$Out = New-Object PSObject
$Out | Add-Member -MemberType noteproperty -Name DistinguishedName -Value #{Name="DistinguishedName";Expression={$_.distinguishedname | ForEach-Object {$_ -replace '^.+?(?<!\\),',''}}}
$Out | Add-Member -MemberType noteproperty -Name Name -Value $User.Name
$Out | Add-Member -MemberType noteproperty -Name UserName -Value $User.SamAccountName
$Out | Add-Member -MemberType noteproperty -Name Status -Value $User.Enabled
$Out | Add-Member -MemberType noteproperty -Name Groups -Value $Groups
$Report += $Out
-> Again, Add-Member is highly inefficient compared to casting PSCustomObject
-> += is evil ( •̀ᴗ•́ )و ̑̑
#>
$Report.Add(
[pscustomobject]#{
OrganizationalUnit = ($user.DistinguishedName -replace '^.+?(?<!\\),','')
Name = $user.Name
UserName = $user.sAMAccountName
Status = $user.Enabled
Membership = $Groups
})
}
#Output to screen as well as csv file.
$Report | Sort-Object OrganizationalUnit | FT -AutoSize
$Report | Sort-Object OrganizationalUnit | Export-Csv -Path $env:temp\students.csv -NoTypeInformation
I don't know how many users you have but every time you += on an array the entire array plus the new element is copied to a completely new array. This is a bad practice and gets exponentially worse with every item added the array. You can avoid this by building the arrays as a loop result or by using dotnet list object with an efficient add() method.
You also look up the same group names repeatedly. I don't know the numbers but it's probably a lot better to put all your groups in a hashtable once and then look them up.
Your question is unclear, but if you want a list of users and their groups, you are going the long way around. You mention the ou but AFAICS there is no org unit used in the code. Do you want the AD ou property or a part of the DN? You don't seem to be using either.
Note that the DN is a string and sorting by DN will just give an alpha string sort which is not helpful. Are your students in separate org units under OU=students ? This is not clear. If so, use the AD canonicalName to sort the list.
No need to include default properties in -property. Splatting is nice.
You should improve your question by indicating what your AD structure looks like and what you think your output should look like.
Also, format your code for readability.
You want something along these lines:
# group hashtable, for efficient name lookup
$groupName = #{}
$ignoredGroups = #( 'AllStudents','AllUsers', 'etc' ) # don't clutter list with these groups
Get-AdGroup -filter '*' | # any restrictions? searchbase, etc
ForEach-Object {
if ( $ignoredGroups -notcontains $_.Name ) {
$groupName[ $_.distinguishedName ] = $_.Name
}
}
# ADsplat, for readability
$AD_Splat = #{
Filter = '*'
SearchBase = 'OU=Student,DC=domain,DC=com'
Properties = 'MemberOf,CanonicalName,sn,givenName'.split(',') # split to array
ResultSetSize = $Null # !? also, there are system limits to size
}
$results = Get-ADUser #ad_splat |
ForEach-Object {
$DN = $_.distinguishedName # do you need this at all?
$CName = $_.canonicalName # for sorting by AD org unit
$XName = $_.sn + ', ' + $_.givenName
if ( $_.Enabled ) { $Enabled = 'Y'} else { $Enabled = '.' }
$groups = (
$_.memberOf |
ForEach-Object { $GroupName[ $_ ] } | # lookup name
where-Object { $_ } | # ignore nulls (when group not in hashtable)
sort-object # consistent ordering between users
) -join ';' # don't use comma, csv conflict
# leave custom object in pipe! This builds the array efficiently.
New-Object PSObject -Property #{
DistinguishedName = $dn
Name = $_.name
XName = $XName
Login = $_.SamAccountName
CName = $CName
Groups = $Groups
}
} | Sort-Object CName # sort the objects by canonical name
$results | format-table
$results | Export-Csv -Path 'c:\temp\usersgroups.csv' -NoTypeInformation
Good Afternoon,
I searched through this forum and a few others combining ideas and trying different angles but haven't figured this out. If this has been answered, and I suck at searching, I am sorry and please let me know.
End Goal of script: have an excel file with columns for the AD properties Name, Office, Org, and most importantly a seperate column for each group a user is a member of.
The problem I am running into is creating a new column for each/every group that a user has. Not all users have the same amount of groups. Some have 10 some have 30 (yes 30, our AD is a mess).
Here is what I have done so far, and the spot that I am having difficulty with is towards the end:
$scoop = get-content C:\temp\SCOOP.txt ##This is a text file with a list of user id's, to search AD with
$outfile = 'C:\temp\SCOOP_ID.csv'
$ou = "OU=Humans,OU=Coupeville,DC=ISLANDS" #This is the searchbase, helps AD isolate the objects
Clear-Content $outfile #I clear content each time when I am testing
Foreach($ID in $scoop){
##AD Search filters##
$filtertype = 'SamAccountName'
$filter1 = $ID
##End AD Search filters##
##AD Search --MY MAIN ISSUE is getting the MemberOF property properly
$properties = get-aduser -SearchBase $ou -Filter {$filtertype -eq $filter1} -Properties Name,Office,Organization,MemberOf | select Name,Office,Organization,MemberOf
##AD Search ## Turns the MemberOf property to a string, I tried this during my testing not sure if objects or strings are easier to work with
#$properties = get-aduser -SearchBase $ou -Filter {$filtertype -eq $filter1} -Properties Name,Office,Organization,MemberOf | select Name,Office,Organization, #{n='MemberOf'; e= { $_.memberof | Out-String}}
#Attempt to specify each property for the output to csv
$name = $properties.Name
$office = $properties.Office
$org = $properties.Organization
$MemberOf = $properties.MemberOf
$membersArray = #()
foreach($mem in $MemberOf){ $membersArray += $mem }
###This is what I typically use to export to a CSV - I am sure there are other maybe better ways but this one I know.
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value $name -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Office' -Value $office -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Org' -Value $org -Force
$Focus | Add-Member -MemberType NoteProperty -Name 'Groups' -Value $MemberOf -Force
<########################
#
# Main ISSUE is getting the $memberOf variable, which contains all of the users groups, into seperate columns in the csv. To make it more plain, each column would be labeled 'Groups', then 'Groups1', and so on.
I have tried a few things but not sure if any were done properly or what I am messing up. I tried using $memberof.item($i) with a FOR loop but couldnt figure out how to send each
item out into its own Add-Member property.
#
#######################>
##Final Output of the $Focus Object
$Focus | Export-Csv $outfile -Append -NoTypeInformation
}
I came up with this solution, simply loop $MemberOf and add a unique name.
$MemberOf = #('a','b','c','d','e','f') #example
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'test' -Force
$i=0; $MemberOf | % {
$i++
$Focus | Add-Member -MemberType NoteProperty -Name "Group $i" -Value $_ -Force
}
$Focus | Export-Csv xmgtest1.csv -Append -Force -NoTypeInformation
However this doesn't work in your case, since you run this code once per user and there's no "awareness" of the entire set. So you would (in your existing architecture) need to ensure that the largest number of groups is added first.
You can fix this by creating the CSV all at once (only other option would be to constantly load/unload the csv file).
First, add $csv = #() to the top of your file.
Then, after you finish creating $Focus, add it to $csv.
Finally, you may remove -Append.
The slimmed down version looks like this:
$csv = #()
#Foreach($ID in $scoop){ etc..
$MemberOf = #('a','b','c','d','e','f') #example
$Focus = [PSCustomObject]#{}
$Focus | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'test' -Force
#$Focus | Add-Member etc ...
$i=0; $MemberOf | % {
$i++
$Focus | Add-Member -MemberType NoteProperty -Name "Group $i" -Value $_ -Force
}
$csv += $Focus
# } end of Foreach($ID in $scoop)
$csv | Export-Csv xmgtest1.csv -NoTypeInformation
Hope this helps.
I am trying to create a backup powershell script for user documents. I have created a script where I am putting on a form box the username I want to backup and then the script proceeds. The last thing is that I want to have a rule that if I put a wrong name, the script will not proceed.
Does anyone knows how I can "read" the present useraccounts on a laptop, in order to create rule to cross-check the input with the useraccounts?
Best regards.
This will read all of the folders in C:\Users and attempt to find a corresponding account in AD:
Get-Childitem C:\users -Directory |
ForEach-Object {
$profilePath = $_.FullName
Get-AdUser -Filter {SamAccountName -eq $_.Name} |
ForEach-Object {
New-Object -TypeName PsCustomObject |
Add-Member -MemberType NoteProperty -Name Name -Value $_.Name -PassThru |
Add-Member -MemberType NoteProperty -Name ProfilePath -Value $profilePath -PassThru |
Add-Member -MemberType NoteProperty -Name SID -Value $_.SID -PassThru
}
} | Format-Table Name,SID, profilePath -AutoSize
Obviously you can modify to get different AD properties, if needed. Also, remove the Format-Table command in order to pipe the output objects for further manipulation.
Note:
This requires the AD PowerShell Module to be installed on the system you run the script on.
It only outputs an object if it finds a user account, so you won't see anything for folders it finds that have no account.
Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'" | Select Name
will give you names of local accounts. Other available fields for select are listed here.
I am fairly new to scripting in Powershell and have been faced with this task. Display a table that identifies the servers in a particular OU and ensure that they are a member of the correct group. There should also be nothing "hard coded" into the script (i.e. server names or group names). Essentially, the script should evaluate the server's name and determine which group it should be a member. If it is in the right group, print it to a table showing it is correct but if is not, also print it to the table indicating it is in the wrong group.
I began by utilizing the Quest ActiveRoles plugin and determining I would need to use nested loops. I would first loop through the security groups and evaluate each server against that group to see if it was a member. I then add the computer and the group to a custom PSObject and am able to print that out as a Correct answer. That part works fine. I run into problems when I try to also print out the incorrect answers. Because of the way I have the loops structured, the majority of the servers will not be in the selected group so they will all come back as incorrect.
My question is, what would be the best way to loop through this information and compare the server name to the group membership and still be able to show which are in the correct group and which are in the incorrect group. My code is below.
#Load Quest Active Roles Snapin
Add-PSSnapin quest.activeroles.admanagement
#Load Active Directory module
Import-Module ActiveDirectory
#Variables
$AccelGroup = Get-QADGroup -SearchRoot 'lumosnet.com/Centrify/Role Groups' -GroupType 'Security' | where {$_.name -like "* Servers"}
$AccelComputer = Get-QADComputer -SearchRoot 'lumosnet.com/Centrify/servers'
$report = #()
$AccelGroup | foreach{$ADN=$_.DN
$AccelComputer | foreach{$AMember=$_.memberof
$AComp=$_.name
If($AMember -like $ADN)
{
$ReportObj = New-Object PSObject
$ReportObj | Add-Member -MemberType NoteProperty -Name Computer_Name -Value $AComp
$ReportObj | Add-Member -MemberType NoteProperty -Name Group_Name -Value $($AMember -replace '^CN=([^,]+),OU=.+$','$1')
$ReportObj | Add-Member -MemberType NoteProperty -Name Correct? -Value "Correct"
$report += $ReportObj
}
Else
{
}
}
}
write-host ($report | FT -Autosize | Out-String)
Instead of trying to do the join yourself, consider using LDAP queries to retrieve the servers in the group, and then another to retrieve those not in the group. It will probably still end up simpler:
$ouPath = "LDAP://OU=Database,OU=Domain Servers,DC=EXAMPLE,DC=LOCAL"
$groupPath = "CN=ITT Testing Servers,OU=Domain Servers,DC=EXAMPLE,DC=LOCAL"
$correctFilter = ("(&(objectClass=computer)(memberof={0}))" -f $groupPath)
$incorrectFilter = ("(&(objectClass=computer)(!(memberof={0})))" -f $groupPath)
# set up the searcher
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $ouPath
$objSearcher.PageSize = 1000
$objSearcher.SearchScope = "Subtree"
#("name","operatingSystem","lastLogonTimestamp") | %{ $unused = $objSearcher.PropertiesToLoad.Add($_) }
# retrieve the correct items
$objSearcher.Filter = $correctFilter
Write-Host "Servers correctly in group"
$goodItems = $objSearcher.FindAll()
$goodItems | %{ New-Object PSObject -Property $_.Properties } | ft name,operatingsystem,lastLogonTimestamp
# retrieve the bad items
$objSearcher.Filter = $incorrectFilter
Write-Host "Servers in wrong group"
$badItems = $objSearcher.FindAll()
$badItems | %{ New-Object PSObject -Property $_.Properties } | ft name,operatingsystem,lastLogonTimestamp
You can, of course, loop over each result to get them to a single list as you are doing currently.
I currently use this script to obtain the SID of a user from AD. Not that each time I need an SID, I have to open the script and type the persons username in, which when I have 100's to do can be frustrating. The current script is as follows:
$name = "username"
(New-Object System.Security.Principal.NTAccount($name)).Translate([System.Security.Principal.SecurityIdentifier]).Value
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Is there a way that I can use the same script but put the AD usernames in a textfile and pull them into powershell and have the output come out like so I get the username and the SID. Ideally into CSV format?
Cheers,
Assuming you have a list of usernames, each on its own row in userlist.txt, the process is not too complicated.
# Array for name&sid tuples
$users = #()
cat C:\temp\userlist.txt | % {
# Syntax sugar
$spSid = [Security.Principal.SecurityIdentifier]
# Custom object for name, sid tuple
$user = new-object psobject
$user | Add-Member -MemberType noteproperty -name Name -value $null
$user | Add-Member -MemberType noteproperty -name Sid -value $null
$user.Name = $_
$user.Sid = (New-Object Security.Principal.NTAccount($_)).Translate($spSid).Value
# Add user data tuple to array
$users += $user
}
# Export array contents into a CSV file
$users | Select-Object -Property Name,Sid | Export-Csv -NoTypeInformation C:\temp\sidlist.txt