I'm trying to input a csv file, which contains Givename & Lastname information of the users. When I run the command listed below samAccountName does not give me the expected output.
Please see below and let me know what should be corrected.
Input:
GivenName,LastName,Password,TargetOU,Description,Manager
Jeffrey,Terry,Pass12,"OU=Users,DC=mmc,DC=local",mmc user,knadella
A,King,Pass13,"OU=Users,DC=mmc,DC=local",mmc user,knadella
Chris ,Charles,Pass14,"OU=Users,DC=mmc,DC=local",mmc user,knadella
Command:
$samAccountName = ($csvcontent.GivenName.Substring(0,1))+( $csvcontent.LastName)
Current Output:
J A C Terry King Charles
Desired Output:
ATerry, AKing and CCharles
Please assist.Thank you!!
You are aggregating all of the details in one go, combining the results of the GivenNamecolumn (J A C) with the results of the LastName column (Terry King Charles)`
This loops over each user:
foreach($user in $csvcontent){
[array]$samAccountName += $user.GivenName[0] + $user.LastName
}
Output:
JTerry AKing CCharles
Going to give you what I use about 30 times a day. The way you are looking to create it will break some login options.
# <FirstLetterGivingName><LastName> for example
# WGates (William Gates)
$sam = $_.GivenName.substring(0,1)+$_.Lastname
That is a good thing, but as the company grows, you will start to run into an issue where the usernames are the same. This is not a perfect solution, but having GivenName (0,3) will give you the first three letters. This will usually fix this issue. It is really rare if you hit someone with the same first three letters and lastname, but it could happen.
$sam = $_.GivenName.substring(0,3)+$_.Lastname
I have also seen companies do this, but advise not to do this, because it would be hard for the user to remember the login.
$sam = $_.GivenName.substring(0,1)+$_.Lastname.substring(0,7)
This script has been used thousands of times, but has been edited a little for this post.
#Test to make sure your output looks correct
#You can do this by running the following:
#Import-csv ".\import_create_ad_users.csv" | Out-GridView
# ERROR REPORTING ALL
Set-StrictMode -Version latest
Import-Module ActiveDirectory
#----------------------------------------------------------
#STATIC VARIABLES
#----------------------------------------------------------
$path = Split-Path -parent $MyInvocation.MyCommand.Definition
$newpath = $path + ".\import_create_ad_users.csv"
$log = $path + ".\create_ad_users.log"
$date = Get-Date
$i = 1
#$addn = (Get-ADDomain).DistinguishedName
#$dnsroot = (Get-ADDomain).DNSRoot
$DNdom = Get-ChildItem -Path Ad:\ | where {$_.Name -eq "Configuration"}
$addn = ($DNdom.DistinguishedName -split "," ,2)[1]
$wmiDomain = Get-WmiObject Win32_NTDomain -Filter "DnsForestName = '$( (Get-WmiObject Win32_ComputerSystem).Domain)'"
$dnsroot = $wmiDomain.DomainName + ".local"
#----------------------------------------------------------
#START FUNCTIONS
#----------------------------------------------------------
Function Start-Commands
{
Create-Users
}
Function Create-Users
{
"Processing started (on " + $date + "): " | Out-File $log -append
"--------------------------------------------" | Out-File $log -append
Import-CSV $newpath | ForEach-Object {
If (($_.GivenName -eq "") -Or ($_.LastName -eq ""))
{
Write-Host "[ERROR]`t Please provide valid GivenName and LastName. Processing skipped for line $($i)`r`n"
"[ERROR]`t Please provide valid GivenName and LastName. Processing skipped for line $($i)`r`n" | Out-File $log -append
}
Else
{
# Replace dots / points (.) in names, because AD will error when a
# name ends with a dot (and it looks cleaner as well)
$replace = $_.Lastname.Replace(".","")
If($replace.length -lt 4)
{
$lastname = $replace
}
Else
{
$lastname = $replace.substring(0,4)
}
# Create sAMAccountName according to this 'naming convention':
# <FirstLetterInitialGivingName><LastName> for example
# WGates (William Gates)
$sam = $_.GivenName.substring(0,1)+$_.Lastname
Try { $exists = Get-ADUser -LDAPFilter "(sAMAccountName=$sam)" }
Catch { }
If(!$exists)
{
# Set all variables according to the table names in the Excel
# sheet /import CSV. The names can differ in every project, but
# if the names change, make sure to change it below as well.
$setpass = ConvertTo-SecureString -AsPlainText $_.Password -force
Try
{
Write-Host "[INFORMATION]`t User is now being built : $($sam)"
"[INFORMATION]`t User is now being built : $($sam)" | Out-File $log -append
New-ADUser $sam -path $_.TargetOU -GivenName $_.GivenName -Initials $_.Initials `
-Surname $_.LastName -UserPrincipalName ($sam + "#" + $dnsroot) -DisplayName ($_.GivenName + " " + $_.LastName) `
-Description $_.Description -Manager $_.Manager -AccountPassword $setpass -Enabled $TRUE -ChangePasswordAtLogon $TRUE
Write-Host "[INFORMATION]`t Created a new user named : $($sam)"
"[INFORMATION]`t Created new user named: $($sam)" | Out-File $log -append
$dn = (Get-ADUser $sam).DistinguishedName
# Rename the object to a good looking name
$newdn = (Get-ADUser $sam).DistinguishedName
Rename-ADObject -Identity $newdn -NewName ($_.GivenName + " " + $_.LastName)
Write-Host "[INFORMATION]`t Renamed the user $($sam) to $($_.GivenName) $($_.LastName)`r`n"
"[INFORMATION]`t Renamed the user $($sam) to $($_.GivenName) $($_.LastName)`r`n" | Out-File $log -append
}
Catch
{
Write-Host "[ERROR]`t Oops, something went wrong: $($_.Exception.Message)`r`n"
}
}
Else
{
Write-Host "[SKIP]`t User $($sam) ($($_.GivenName) $($_.LastName)) already exists or returned an error!`r`n"
"[SKIP]`t User $($sam) ($($_.GivenName) $($_.LastName)) already exists or returned an error!" | Out-File $log -append
}
}
Else
{
Write-Host "[SKIP]`t User ($($_.GivenName) $($_.LastName)) will be skipped for processing!`r`n"
"[SKIP]`t User ($($_.GivenName) $($_.LastName)) will be skipped for processing!" | Out-File $log -append
}
$i++
}
"Processing ended (on " + $date + "): " | Out-File $log -append
"--------------------------------------------" + "`r`n" | Out-File $log -append
}
Write-Host "***************************SCRIPT HAS STARTED***************************"
Write-Host "***************************SCRIPT HAS STARTED***************************"
Write-Host "***************************SCRIPT HAS STARTED***************************`r`n"
Start-Commands
Write-Host "***************************SCRIPT HAS FINISHED***************************"
Write-Host "***************************SCRIPT HAS FINISHED***************************"
Write-Host "***************************SCRIPT HAS FINISHED***************************"
Your CSV would have the following headers:
GivenName LastName LoginName Description Password Manager TargetOU
You need to itterate each item and not the whole array at once:
$samAccountName = $csvcontent | % {
($_.GivenName.Substring(0,1))+($_.LastName)
}
Related
My PowerShell script to retrieve the last sign in date of Azure AD users doesn't work when using variables within the filter for UPN. This is a well discussed topic when it comes to AzureAD PowerShell cmdlets, with the most common answer being to wrap the variable in additional quotes. However, none of the examples are for this exact cmdlet. In any case, this does not work for me. To break things down I am now using the approach of building my filter as a variable ($filter).
If I use
$filter = "UserPrincipalName eq 'user123#domain.com'"
the Get-AzureADAuditSignInLogs cmdlet passes me a result. If I use $filter = "UserPrincipalName eq '$($row.UserPrincipalName)'", Get-AzureADAuditSignInLogs gives a $null result.
In BOTH cases, Write-Host $filter outputs the exact same string so there is no problem with retrieving the entry from the CSV file. There is something "special" about the way MS's Azure AD cmdlets implement filters.
Has anyone come across this before? Is there a way I can force my variable to be as if I "hand typed" it?
Connect-AzureAD
$Result = $null
$output = $null
$filter = $null
$csv = Import-csv -Path c:\temp\UPNs.csv
ForEach($row in $csv)
{
$filter = "UserPrincipalName eq '$($row.UserPrincipalName)'"
#$filter = "UserPrincipalName eq 'user123#domain.com'"
$filter = $filter.ToString()
Write-Host $filter
$Result = Get-AzureADAuditSignInLogs -Filter $filter -Top 1 | Select-Object CreatedDateTime, UserPrincipalName
$output = ($Result.UserPrincipalName.ToString() + "," + $Result.CreatedDateTime.ToString())
$output | Out-File C:\temp\HighwaysSignInInfo.txt -Append
Write-host $output
}
CSV file:
UserPrincipalName
user123#domain.com
user1234#domain.com
user12345#domain.com
user12356#domain.com
user1234567#domain.com
This filter works just fine:
Get-AzureADAuditSignInLogs -Filter "startsWith(userPrincipalName,'name#Contoso.com')"
Although some websites say you can use Get-AzureADAuditSignInLogs -Filter "UserPrincipalName eq 'name#Contoso.com'" it doesn't seem to work for me.
The full script (with handling for bandwidth throttling)
#GetAADUserSignIns v1.0
#This script will obtain the last sign in date for each supplied UPN via a source csv file. The biggest issue with such queries is bandwidth throttling. This is handled within the script using a simple
#Try, Catch combined with a Function that can be used to make nested calls.
#IMPORTANT: Review the below 3 options to generate a source file (Option 3 is recommended)
#1. This attempts dump the entire audit log to text file. However you are likely to be throttled before the export completes so don't bother
#Get-AzureADAuditSignInLogs -Filter -All:$true | Out-File C:\Temp\AuditLogsAll.txt
#2. To get a list of all AAD accounts exported to csv (This will capture guest accounts too, the list will be huge, therefore not recommended to run Get-AzureADAuditSignInLogs with)
#Get-AzureADUser -All $true | Export-Csv C:\Temp\AADUsers.csv -NoTypeInformation
#3. Obtain a list of on-prem AD accounts that have a valid UPN
#Get-ADUser -Filter {userPrincipalName -like "*#customdomain.com"} | Select-Object userPrincipalName | Export-Csv C:\Temp\UPNs.csv -NoTypeInformation
Connect-AzureAD
Function GetLastSignInDate {
param (
[string]$upn
)
$filter = "startsWith(userPrincipalName,'" + $upn + "')"
Try
{
$Result = Get-AzureADAuditSignInLogs -Filter $filter -Top 1 | Select-Object CreatedDateTime, UserPrincipalName
$output = ($upn + "," + $Result.CreatedDateTime.ToString())
$output | Out-File C:\temp\SignInInfo.txt -Append
Write-host $output -ForegroundColor Green
}
Catch
{
$message = $_
if ($message -like "*Too Many Requests*")
{
Write-host "Sleeping for 10 seconds due to throttling limitations..." -ForegroundColor Yellow
sleep 10
#Nested function call to retry the entry that was throttled
GetLastSignInDate $upn
}
elseif ($message -like "*This request is throttled*")
{
Write-host "Sleeping for 10 seconds due to throttling limitations..." -ForegroundColor Yellow
sleep 10
#Nested function call to retry the entry that was throttled
GetLastSignInDate $upn
}
elseif ($message -like "*null-valued*")
{
$output = ($upn + ", Not Found")
$output | Out-File C:\temp\SignInInfo.txt -Append
Write-host $output -ForegroundColor Gray
}
elseif ($message -like "*Invalid filter clause*")
{
$output = ($upn + ", Invalid character")
$output | Out-File C:\temp\SignInInfo.txt -Append
Write-host $output -ForegroundColor Gray
}
elseif ($message -like "*Error reading JToken*")
{
$output = ($upn + ", Script stopped due to authentication token timeout")
Write-host $output -ForegroundColor White -BackgroundColor Red
exit
}
else
{
$output = ($upn + ",Error - " + $message.ToString().SubString(0,15))
$output | Out-File C:\temp\SignInInfo.txt -Append
Write-host $output -ForegroundColor Red
}
}
}
$csv = $null
$Result = ""
$output = ""
$filter = ""
$i = $null
$csv = Import-csv -Path C:\temp\upns.csv
ForEach($row in $csv)
{
$upn = $row.UserPrincipalName.ToLower().Replace('`r`n','').Replace('`r','').Replace('`n','').Trim()
GetLastSignInDate $upn
}
I'm trying to clean up the active directory ahead of the Skype 4 Business deployment, which requires correcting sip addressing. After doing some poking around I found other problems, including unusual emails formats, which I need to account for. I was asked to roll out the changes, but due to an error Get-CsAdUser -Identity $line.Name when the user can't be found. However this means they are taking a slot from a user who could be changed, as written at this time.
I would like it if the error occurs increase $line, do not increment $limiter, and try again with the next person on the list. I'm still reading how to use try/catch and return but I'm still unsure how to structure these to allow script to process another 25 people every run.
## Collect User Base
Get-CsAdUser -OU "OU=..." -Filter {Enabled -eq $True} | Where-Object{$_.UserAccountControl -notmatch "AccountDisabled"}| Select Name, WindowsEmailAddress, SipAddress|Export-Csv -NoTypeInformation -Append -Path c:\tmp\EmailSIP_$d.csv
$csv = Import-csv c:\tmp\EmailSIP_$d.csv
## Change 25 users
$first = $True
$limiter = 0
foreach ($line in $csv){
$goodsip = -join ("sip:", $line.WindowsEmailAddress)
$sipcheck = ($goodsip -ne $line.SipAddress) #If SIP not as expected then "proceed with change is TRUE"
$otherchecks #If no other AD fields are formatted 'incorrectly' will "proceed with change be True"
If ($emailcheck -And $otherchecks){
If ($first) {
Write-Output (-join ("Name, WindowsEmailAddress, old-SipAddress, new-SipAddress"))|Out-File -Append c:\tmp\Changed_EmailSIP_$d.txt
$first = $False}
If ($limiter -lt 25){
Write-Output (-join ($line.Name,", ", $line.WindowsEmailAddress,", ", $line.SipAddress,", ", $goodsip))|Out-File -Append c:\tmp\Changed_EmailSIP_$d.txt
#Errors Generated in following line for some $line.NAMES
Get-CsAdUser -Identity $line.Name|Set-CsUser -SipAddress $goodsip -ErrorAction Ignore -whatif
$limiter++}
If ($limiter -ge 25){break} #exit loop if 25 changes
} #end of IF Email and Sip
} #end of foreach
The error I'm getting is:
Get-CsAdUser : Management object not found for identity "person1".
At line:3 char:1
+ Get-CsAdUser -Identity $line.Name|Set-CsUser -SipAddress $goodsip -wh ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (person1:UserIdParameter) [Get-CsAdUser], ManagementException
+ FullyQualifiedErrorId : Identity,Microsoft.Rtc.Management.AD.Cmdlets.GetAdUserCmdlet
Thank you #TheIcorrigible for your comment.
The working code:
foreach ($line in $csv){
$goodsip = -join ("sip:", $line.WindowsEmailAddress)
$sipcheck = ($goodsip -ne $line.SipAddress)
$otherchecks
If ($emailcheck -And $otherchecks){
If ($limiter -lt 25){
try{
Get-CsAdUser -Identity $line.Name -ErrorAction Stop|Set-CsUser -SipAddress $goodsip -whatif
If ($first) {
Write-Output (-join ("Name, WindowsEmailAddress, old-SipAddress, new-SipAddress"))|Out-File -Append c:\tmp\Changed_EmailSIP_$d.txt
$first = $False}
Write-Output (-join ($line.Name,", ", $line.WindowsEmailAddress,", ", $line.SipAddress,", ", $goodsip))|Out-File -Append c:\tmp\Changed_EmailSIP_$d.txt
$limiter++}
catch{continue}
}
If ($limiter -ge 25){break}
}
}
I have pasted my code below and pulled out everything that is already working, so I only have the part that isn't working as intended.
I am trying to put the EmployeeID, from a csv, in front of the Description field in AD. I can get that part to work, but the beginning of the If statement where I try to check if the $ID is already in the description fails; it just keeps adding it every time the script runs.
I have tried making both the $ID and $Description type as string with Out-String, and I have left that out, but it's the same result. I have tried -notcontains, -notmatch, and -notlike (which I believe is the correct one to use), but none work. I have even put my variables in a text file to make sure they are pulling the correct information.
I am still learning all of the intricacies of Powershell. Can anyone see what I'm doing wrong?
# Get script Start Time (used to measure run time)
$startDTM = (Get-Date)
#Null out variables
$Users = $Null
$ID = $Null
$Users = Import-Csv .\ImportADUsers\Test-Import-user-data.csv
Import-Module ActiveDirectory
$path = Split-Path -parent ".\ImportADUsers\*.*"
#Create log date
$logdate = Get-Date -Format yyyy-MM-dd-THH.mm.ss
$logfile = $path + "\logs\$logdate.logfile.txt"
# Enumerate the users, one line at a time.
# This assumes the first line is a header line defining the fields.
ForEach ($User In $Users)
{
# Retrieve values from the csv.
$ID = $User.HRRef
# Retrieve the sAMAccountName of the user from AD.
$UserDN = (Get-ADUser -LDAPFilter "(employeeID=$ID)").sAMAccountName
$ID | Out-File $logfile -Append
$IDString = $ID | Out-String
#Retrieve the Description of the user from AD.
$Description = Get-ADUser -Identity $UserDN -Properties description
$Description = $Description.description | Out-String
$Description | Out-File $logfile -Append
# Make sure there is only one user with this employeeID.
If ($UserDN.Count -eq 1)
{
IF ($Description -notlike $IDString) {Set-ADUser -Identity $UserDN
-Description "$($ID) - $($Description)" }
}
Else {"User with ID $ID either not found, or more than one user found."
| Out-File $logfile -Append}
#Log error for users that are not in Active Directory or EmployeeID
#found more than once
}
#Finish
#The lines below calculates how long it takes to run this script
# Get End Time
$endDTM = (Get-Date)
# Echo Time elapsed
"Elapsed Time: $(($endDTM-$startDTM).totalminutes) minutes"
#Append the minutes value to the text file
"Import took $(($endDTM-$startDTM).totalminutes) minutes to complete." |
Out-File $logfile -Append
#SCRIPT ENDS
Your string comparison is incorrect. Below is how to fix it.
The change: -notlike $IDString => -notlike "*$ID*"
ForEach ($User In $Users)
{
# Retrieve values from the csv.
$ID = $User.HRRef
$ID | Out-File $logfile -Append
# Retrieve the SAMAccountName of the user from AD.
$UserDN = (Get-ADUser -LDAPFilter "(employeeID=$ID)").SAMAccountName
#Retrieve the Description of the user from AD.
$Description = (Get-ADUser -Identity $UserDN -Properties description).Description
$Description | Out-File $logfile -Append
# Make sure there is only one user with this employeeID.
If ($UserDN.Count -eq 1 -and $Description -notlike "*$IDString*")
{
Set-ADUser -Identity $UserDN -Description "$ID - $Description"
}
Else
{
"User with ID $ID either not found, or more than one user found." | Out-File $logfile -Append
}
}
I export a database into CSV. In the CSV there contains fields such as employeeid, first name, last name, email, position, description, and various fields. I am trying to populate those fields and all the other fields into Active Directory. The extracted CSV fields don't directly correlate to Active Directory. because of this, I need to check for double entries; if any.
To do this, I take the email address of a user in the CSV and do a search in Active Directory for the email address. I then try to take the same users employeeid and check to see if in Active Directory employeeid attribute is filled. If the employeeid attribute is filled, skip, if not, fill in the attribute from the CSV file.
I am having trouble inputting data from the CSV to Active Directory and also doing the check if employeeID exists in the attribute.
Import-Module ActiveDirectory
# ERROR REPORTING ALL
Set-StrictMode -Version latest
$newpath = "C:\Scripts\Test Files\book1.csv"
$log = "C:\Scripts\Test Files\import_employeeID.log"
$date = Get-Date
$addn = (Get-ADDomain).DistinguishedName
$dnsroot = (Get-ADDomain).DNSRoot
$i = 1
function Start-Commands {
Update-Users
}
function Update-Users {
"Processing started (on " + $date + "): " | Out-File $log -Append
"---------------------------------------" | Out-File $log -Append
Import-CSV $newpath | ForEach-Object {
$UserEmail = $_.EMAILID
$EmployeeID = $_.EMPLID
$LastName = $_.LAST_NAME
$FIRSTNAME = $_.FIRST_NAME
$UserEmail
} -Properties EmployeeID
$CheckUser = $user.employeeid
if ($CheckUser) {
Write-Host "$UserEmail $EmployeeID UPDATED"
"$UserEmail $EmployeeID UPDATED `r" | Out-File $log -Append
} else {
Get-ADUser -Identity $User | Set-ADUser -EmployeeID $EmployeeID
Get-ADUser -Identity $User | Set-ADUser -Replace #{info=$EmployeeID}
}
$i++
}
"--------------------------------------------" + "`r`n" | Out-File $log -Append
}
Write-Host "STARTED SCRIPT`r`n"
Start-Commands
Write-Host "STOPPED SCRIPT"
Hi I would like to find out where my AD group called BIDEV is located within my AD, as you can see on the pictures below.
It exists, but where is it?
Also, any example of how I could do this using Powershell?
#------------------------------
# first part search for a user
#------------------------------
Clear-Host
$SearchFor = "mmartin"
import-module activedirectory
Write-Host "Searching..."
$all_users_list=Get-ADUser -filter * -properties SamAccountName,sn,GivenName,mail,EmailAddress,LastLogonDate,Country,DistinguishedName,CanonicalName |
select-object SamAccountName,sn,GivenName,mail,EmailAddress,LastLogonDate,Country,DistinguishedName,CanonicalName -ErrorAction silentlycontinue
foreach($u in $all_users_list)
{
if($u.SamAccountName -like "*$SearchFor*")
{
$Output = $u.SamAccountName + " - " + $u.DistinguishedName
Write-Host $Output
}
}
Write-Host "Done"
#that will work
#just put what you want at the top in "SearchFor"
#mmartin my powershell guru - 16-july-2015
#------------------------------
# second part search for a group
#------------------------------
Clear-Host
$SearchFor = "BIDEV"
import-module activedirectory
Write-Host "Searching..."
$all_group_list=Get-ADGroup -filter * -properties * |
select-object * -ErrorAction silentlycontinue
foreach($u in $all_group_list)
{
if($u.SamAccountName -like "*$SearchFor*")
{
$Output = $u.SamAccountName + " - " + $u.DistinguishedName
Write-Host $Output
}
}
Write-Host "Done"