Export AD User Properties to CSV - sharepoint

I want to interrogate the client' AD to see which users are missing property values such as telephone number ahead of User Profile Sync in SharePoint 2013, the script works but now I need to add a little "magic" in order to create my csv file... I have added a comment below to indicate where I think this "magic" should go!
# get Users and groups
#Get the User from AD
$domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$root = $domain.GetDirectoryEntry()
$search = [System.DirectoryServices.DirectorySearcher]$root
#$search.Filter = "(&(objectCategory=User)(samAccountName=$userName))"
# get a list of the users but not the sp_ service accounts.
$search.Filter = "(&(objectCategory=User) (!(name=SP_*)) )"
$search.SearchScope ="subtree"
# determine the properties we want back
$colPropList = "name", "jobTitle", "telephoneNumber","mail", "department" , "thumbnailPhoto"
foreach ($i in $colPropList){$search.PropertiesToLoad.Add($i)}
$result = $search.FindAll()
if ($result -ne $null)
{
foreach ( $entry in $result )
{
# this works though I might have incorrect names for some of the properties
$user = $entry.Properties;
$user.name
$user.department
$user.jobTitle
$user.telephoneNumber
$user.mail
$user.thumbnailPhoto
*# !!!!!!This is where I need help!!!!!
# as my $user is effectively an object then I should be able to to use it to create a an object with Add-Member
# Do I breaker down the $user properties and create another object with name values ???*
foreach ($o in $user)
{
Add-Member -InputObject $psObject -MemberType NoteProperty -Name $o -Value $o
}
}
$psObject | Export-Csv c:\dev\aduserList.csv -NoTypeInformation
}

I'm not familiar with directorysearcher / adsi, but if you're migrating to SharePoint 2013 I'd guess you also have a computer with PowerShell.
In that case you should use Microsofts ActiveDirectory module (installed on servers and through RSAT for clients) if you have a 2008 DC or 2003 with Active Directory Web Service.
You could also use Quest ADRoles Module.
PowerShell cmdlets are much easier to use for AD administration. You could then shorten down your script to one line(this is the ActiveDirectory module from Microsoft):
Get-ADUser -LDAPFilter "(!(name=SP_*))" -Properties Name, Title, OfficePhone, Mail, Department, thumbnailPhoto | Select-Object Name, Title, OfficePhone, Mail, Department, thumbnailPhoto | Export-Csv c:\dev\aduserList.csv -NoTypeInformation
I'm not sure if the thumbnailphoto part works as I haven't used that attribute before.

Something like this should work:
$search.FindAll() | select -Expand Properties |
select #{n='name';e={$_.name}},
#{n='department';e={$_.department}},
#{n='jobTitle';e={$_.jobtitle}},
#{n='telephoneNumber';e={$_.telephonenumber}},
#{n='mail';e={$_.mail}},
#{n='thumbnailPhoto';e={$_.thumbnailphoto}} |
Export-Csv c:\dev\aduserList.csv -NoTypeInformation
Note that the properties used in the expression section of the calculated property (#{n='name';e={expression}}) must be lowercased:
#{n='thumbnailPhoto';e={$_.thumbnailphoto}}
Using the Get-ADUser cmdlet from the ActiveDirectory module as Frode F. suggested is a more convenient way to get the information you want, but it requires that the AD PowerShell module is installed on the computer where it's used, and that the AD Web Services are installed and running on a DC.

Related

Combining & matching output from Get-AzureADUser, Get-AzureADSubscribedSku , Get-AzureADUserManager

Problem & what i have now
The script
comments are in norwegian btw, if they look strange lol
Connect-AzureAD
#variabel
$Users = Get-AzureADUser -All:$true | where-object { $null -ne $_.AssignedLicenses.SkuId } | Sort-Object CompanyName, UserPrincipalName| Select-Object -Property CompanyName, DisplayName, UserPrincipalName, Department, Mobile, TelephoneNumber
#formatting
$userlistTable = $Users | Format-Table
$userlistHTML = $Users | ConvertTo-Html
#outputs
$userlistHTML > out.html # ut som HTML
$userlistTable > out.txt # ut som Tabell i .txt
$userlistTable # ut som Tabell i terminal
My output as it stands right now:
CompanyName DisplayName UserPrincipalName Department Mobile TelephoneNumber
----------- ----------- ----------------- ---------- ------ ---------------
Company inc Usser Name username#website.com Callsenter 12345678 87654321
What i would like. is a table that has all the info in the output of $Users to inclide the users "SkuPartNumber".
The field u get by running the command Get-AzureADSubscribedSku | Select -Property SkuPartNumber
I would also like to get the users "manager", that u get by running Get-AzureADUserManager.
that last command uses the users Object ID to find their manager.
And to be honest, im very lost on how to combine these commands into one table.
its not the end of the world as it is right now. i could of just have multiple tables but having to manually cross reference these takes some time.
Im really not sure why these things are split into different commands to be honest. i get that a license is via 365 and not azure. but it seems a little backwards that i cant see the licenses from the command showing me all the user information. when a user class in powershell DOES infact show the sku ID. its burried within AssignedLicenses from running the command:
Get-AzureADUser | where-object -property UserPrincipalName -eq "emailhere#domain.com" | FL
This will give you among other things, this info:
AssignedLicenses : {class AssignedLicense {
DisabledPlans: System.Collections.Generic.List`1[System.String]
SkuId: 3b555118-da6a-4418-894f-7df1e2096870
}
conclusion
I know this was a long read. and if u made it this far im sorry.
any help with this would be amazing. This might be super easy to do, but im very far from a powershell wiz. thanks again for reading, and any help.
You can add additional properties to selected objects with calculated properties like Select #{label='name';expression={foo}}
$Users = Get-AzureADUser -All:$true
$Users | Where-Object { $_.AssignedLicenses.SkuId } |
Select-Object -Property UserPrincipalName, ## other properties here...
#{l='ManagerUPN';e={($_ | Get-AzureADUserManager).UserPrincipalName}},
#{l='AssignedSKUs';e={$_.AssignedLicenses.SkuId -join ';'}}
UserPrincipalName ManagerUPN AssignedSKUs
----------------- ---------- ------------
user#domain.com manager#domain.com 00000000-0000-0000-0000-000000000000;11111111-1111-1111-1111-111111111111
It can be slow to run Get-AzureADUserManager for every user, but that's how azure stores the relationships.
When you have a lot of users, it can be slightly faster to get the manager users first, then use Get-AzureADUserDirectReport -all $true to expand all the directreports in one call. The Microsoft.Graph.Users module is also a bit more lightweight

list all vendors in azure ad who had logged/never logged in the past 24 hours

I wrote a script to list all vendors in the azure ad to check if they are working or not. the script find the logged in users for the past day and if there is a record it should print, if there is no record and the vendor did not logged in or work it should print no login records. but my script is not working well any one can help?
###########################Here is the code ##################
#get azure ad users
$AzADUsers = get-azureaduser
#start for loop
foreach ($user in $AzADUsers){
#list attributes
$dp = $user.DisplayName
$company = $user.CompanyName
# list of contractors/vendors who didn't log in during the day.
if ($company -eq "Vendor Resource - companyname1" -or $company -eq "Vendor Resource - companyname2" -or $company -eq "Vendor Resource - companyname3") {
#check if they logged in the past 24 hours
$SetDate = (Get-Date).AddDays(-1);
$SetDate = Get-Date($SetDate) -format yyyy-MM-dd
$AllSiginLogs = Get-AzureADAuditSignInLogs -Filter "createdDateTime gt $SetDate"
$LoginRecord = $AllSiginLogs | Sort-Object CreatedDateTime -Descending
if($LoginRecord.Count -gt 0){
$lastLogin = $LoginRecord[0].CreatedDateTime
}
else{
$lastLogin = 'no login record | Sick'
}
Write-Host "Last logon time : " $lastLogin $dp $company
Write-Host " "
}
}
in addition to our discussion:
Currently you loop through the $AzAdUsers and query foreach the SignInLogs. But you do not filter the SignInLogs for the specific user, you query all the time the same information and select the latest entry from that log, but it has no relation to the current user.
You have to filter the SignInLog for the specific user, e.g.:
$AllSiginLogs = Get-AzureADAuditSignInLogs -filter "Id eq '$($user.Id)' and createdDateTime gt $SetDate"
After that you could do:
$attrsht = #{
userId=$User.id
DisplayName=$user.displayname
LastSignIn=$LoginRecord.CreatedDateTime
}
new-object -typename psobject -property $attrsht
Btw. the AzModule will be replaced by the microsoft.graph modules. So it might be the right time to do the switch, which you have to do in any case until 2024.
If you do so, you can directly get the lastSignInDateTime from the user object:
#Switch to beta API
select-mgprofile -name beta
$lastSignIn = get-mguser -userId $user.id -Property signinactivity
$lastSignIn.LastSignInDateTime
In regards to you latest comment:
once again, if you want to know the last signInDateTime for a specific user you have to filter for that user id. if you filter by companyname you will probably get several users back and then you have to loop over this array of users and query the signInLog foreach user. the problem you are facing is that you miss to specify consistensylevel and countvariable, e.g.:
$company = "MyCompanyName"
$users = Get-MgUser -filter "companyname eq '$company'" -ConsistencyLevel eventual -CountVariable $null -property Id,CompanyName,DisplayName
select-mgprofile -Name beta
$lastSignInDateTime = #(
foreach ($user in $users){
$LoginRecord = get-mguser -userId $user.id -Property signinactivity
$attrsht = #{
userId=$User.id
DisplayName=$user.displayname
CompanyName=$user.CompanyName
LastSignIn=$LoginRecord.signinactivity.LastSignInDateTime
}
new-object -typename psobject -property $attrsht
}
)
You need to have the MgGraph module installed to run the above mentioned cmdlets -> install-module microsoft.graph
More information in regards to consistensylevel:
https://devblogs.microsoft.com/microsoft365dev/build-advanced-queries-with-count-filter-search-and-orderby/

Office 365 - how to manage many users

I have 200 unsorted users in office 365. I want to find an easy way to manage who they are and what security group each user belongs to.
Is there an easy way to export username and what groups each user belongs to?
Iam quite new to poweshell...
But i want to export a CSV file with user and gruops.
Is this possible?
Or do you recommend any other way to quick get an overview of all users and what grups they belong to.
Some users need to be in multiple groups and i suspect some users are missing in groups they should be in..
Thanks for any tips i can get.
################################################################################################################################################################
# Script accepts 2 parameters from the command line
#
# Office365Username - Optional - Administrator login ID for the tenant we are querying
# Office365Password - Optional - Administrator login password for the tenant we are querying
#
#
# To run the script
#
# .\Get-DistributionGroupMembers.ps1 [-Office365Username admin#xxxxxx.onmicrosoft.com] [-Office365Password Password123]
#
#
# Author: Alan Byrne
# Version: 2.0
# Last Modified Date: 16/08/2014
# Last Modified By: Alan Byrne alan#cogmotive.com
################################################################################################################################################################
#Accept input parameters
Param(
[Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)]
[string] $Office365Username,
[Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$true)]
[string] $Office365Password
)
#Constant Variables
$OutputFile = "DistributionGroupMembers.csv" #The CSV Output file that is created, change for your purposes
$arrDLMembers = #{}
#Remove all existing Powershell sessions
Get-PSSession | Remove-PSSession
#Did they provide creds? If not, ask them for it.
if (([string]::IsNullOrEmpty($Office365Username) -eq $false) -and ([string]::IsNullOrEmpty($Office365Password) -eq $false))
{
$SecureOffice365Password = ConvertTo-SecureString -AsPlainText $Office365Password -Force
#Build credentials object
$Office365Credentials = New-Object System.Management.Automation.PSCredential $Office365Username, $SecureOffice365Password
}
else
{
#Build credentials object
$Office365Credentials = Get-Credential
}
#Create remote Powershell session
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $Office365credentials -Authentication Basic –AllowRedirection
#Import the session
Import-PSSession $Session -AllowClobber | Out-Null
#Prepare Output file with headers
Out-File -FilePath $OutputFile -InputObject "Distribution Group DisplayName,Distribution Group Email,Member DisplayName, Member Email, Member Type" -Encoding UTF8
#Get all Distribution Groups from Office 365
$objDistributionGroups = Get-DistributionGroup -ResultSize Unlimited
#Iterate through all groups, one at a time
Foreach ($objDistributionGroup in $objDistributionGroups)
{
write-host "Processing $($objDistributionGroup.DisplayName)..."
#Get members of this group
$objDGMembers = Get-DistributionGroupMember -Identity $($objDistributionGroup.PrimarySmtpAddress)
write-host "Found $($objDGMembers.Count) members..."
#Iterate through each member
Foreach ($objMember in $objDGMembers)
{
Out-File -FilePath $OutputFile -InputObject "$($objDistributionGroup.DisplayName),$($objDistributionGroup.PrimarySMTPAddress),$($objMember.DisplayName),$($objMember.PrimarySMTPAddress),$($objMember.RecipientType)" -Encoding UTF8 -append
write-host "`t$($objDistributionGroup.DisplayName),$($objDistributionGroup.PrimarySMTPAddress),$($objMember.DisplayName),$($objMember.PrimarySMTPAddress),$($objMember.RecipientType)"
}
}
#Clean up session
Get-PSSession | Remove-PSSession

Fill in column into excel with powershell

I'm trying to create a report which will get two sets of information, Group name and domain. The problem is that the information will be output into one column instead of two for example:
Group Member Domain
thisIsGroupMember,Domain
but I want it to be like this:
Group Member Domain
thisIsGroupMember, Domain
I also try export-csv but the created csv file only show
Length
32
Here's my code:
$appName = $findone.properties.name
$domain = (($findone.properties.adspath -split ',')[3].substring(3)
$inputstring = "$appName,$domain"
out-file -FilePath "C:\Test\Result.csv" -append -inputObject $inputstring
If your code iterates through a list of objects pulled from AD you can use something like this:
# your foreach code
{
...
$appName = $findone.properties.name
$domain = (($findone.properties.adspath -split ',')[3].substring(3)
$output += ,(New-Object -TypeName psobject -Property #{"Group Member"=$appName;"Domain"=$domain})
}
$output | Export-Csv "C:\Test\Result.csv"
$output is an array of objects being created on the fly with $appName and $domain values. It will then nicely export to a csv after all AD objects are processed.

Active Directory Powershell - forest-wide search script using .csv list of users

I am looking for a bit of help, hope nobody will bash me for being an ignorant.
Not that long ago I became something of an AD admin, organisation is big so the tasks vary. I can easily complete what I require via Powershell or snap-ins in most cases.
However I have a task on my hands that exceed my "creativity". I have a list of over 10 000 users in .csv which I need to look up in on-premises AD if they exist. My two problems are:
-I am very new to scripting and getting increasingly frustrated that I can't comprehend it and make my scripts work as I need them to
-Deadline for this task and other responsibilities give me little time to read more on scripting basics and learn. As such I am in most cases forced to look for script snippets on the web and modify them a bit to meet my needs. This worked up until now as the script I have on my hands is a bit too complex for me.
Biggest problem I was facing so far is creating a forest-wide search. My organization have a single root domain and 4 child domains. When running a simple foreach loop a like the one below:
ForEach ($User in (Import-Csv c:\users\public\users.csv))
{ If (Get-ADUser $User.mail -server GLOBALCATALOGADDRESS:xxxx)
{ Write-Host "User found: $($User.mail)"
}
Else
{ Write-Host "User not found: $($User.mail)"
}
}
It searches only domain to which my computer is connected.
So I managed to find and modify a forest-wide search script and came up with following:
#Get Domain List
$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = #($objForest.Domains | Select-Object Name)
$Domains = $DomainList | foreach {$_.Name}
$User = Import-CSV c:\users\public\users.csv
#Act on each domain
foreach($Domain in ($Domains))
{
Write-Host "Checking $Domain" -fore red
$ADsPath = [ADSI]"LDAP://$Domain"
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher($ADsPath)
#The filter
Foreach($mail in($User))
{
$objSearcher.Filter = "(&(objectCategory=user)(mail=$User.mail))"
$objSearcher.SearchScope = "Subtree"
$colResults = $objSearcher.FindAll()
foreach ($objResult in $colResults)
{
$objArray = $objResult.GetDirectoryEntry()
write-host $objArray.mail
}
}
}
The script seems to be good in its original form (found here: http://powershell.nicoh.me/powershell-1/active-directory/forest-wide-object-searches) and searches well with wildcard and single parameter as filter.
However I have no idea what am I missing to make it search for every email address I have in .csv and to make it return information whether or not user with such mail was found.
Script itself runs but given the time it takes and blank output it feels like it searches for only one user. I am 100% sure that at least one user from the list exists in on-prem AD.
Any suggestions are very welcome.
Thanks for your attention.
[EDIT]
Final script:
#Get Domain List and load user e-mails from file
$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$DomainList = #($objForest.Domains | Select-Object Name)
$Domains = $DomainList | foreach {$_.Name}
$Users = Import-CSV c:\users\public\users.csv
#Act on each domain
foreach($Domain in ($Domains))
{
Write-Host "Checking $Domain" -fore red
Foreach($mail in ($Users.mail))
{
Get-ADUser -filter {mail -eq $mail} -Server $domain -properties mail | select mail
}
}
Do yourself a favour and download AD Powershell module: http://blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory-module-in-powershell-in-windows-7.aspx
You will then be able to simplify your code and run things like this, making your task much clearer:
...
foreach($Domain in ($Domains))
{
Write-Host "Checking $Domain" -fore red
Foreach($mail in ($User.mail))
{
Get-ADUser -filter {mail -eq $mail} -Server $domain -Properties mail |
select-object -ExpandProperty mail
}
}
...
More on AD PS cmdlets: http://technet.microsoft.com/en-us/library/ee617195.aspx
Use -LDAPfilter & point the -Server to GC.
Get-ADUser -Server DC01.Contoso.com:3268
-Ldapfilter "(ObjectClass=user)(mailnickname=David)"
The above command will search the GC DC01.contoso.com for all the users that their Alias/mailnickname is David.
Is is enough to contact the Domain itself instead of a DC of the domain. Thus this shoud also work
get-aduser -Filter {mailnickname -eq "David") -Server contoso.com:3268

Resources