Check a username list and if they already exist Powershell - powershell

I have a CSV with 100 Usernames i have to check now if they already exist. Whats the best way to do that?
And is there a possibility that if the Username "marmar" is already used the programm checks by its own if username "marmar1" or if that is used aswell "marmar2" is free?
Is it easier to read the Usernames through the csv or should i copy them into Powershell?
examples of Usernames:
marmar
langas
ianmow
lowbob
berret
lawpaw1
etc.
Open for ideas and tipps.$
Thanks very much

If your CSV file looks anything like
"UserName","OtherStuff"
"marmar","blah"
"langas2","blahblah"
"ianmow","blahblahblah"
"lowbob","blahblahblahblah"
"berret","blahblahblahblahblah"
"lawpaw1","blahblahblahblahblahblah"
You can do that with something like this:
$freeUserNames = Import-csv 'D:\UsersNamesToCheck.csv' | ForEach-Object {
#Check to see if the user already exists in AD
$name = $_.UserName
$dupes = Get-ADUser -Filter "SamAccountName -like '$name*'" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty SamAccountName
$index = 1
# check if the username is already in use and if so, increase the index number and test again
while ($dupes -contains $name) {
$name = '{0}{1}' -f ($name -replace '\d+$'), $index++
}
$name
}
# output on screen
Write-Host "Unused usernames:`r`n"
$freeUserNames
Possible output:
Unused usernames:
marmar
langas1
ianmow1
lowbob
berret1
lawpaw2

Related

Compare 2 ActiveDirectory properties using Powershell

My Goal is to List all ADusers where the property proxyAddresses does not contain the value from the mail property.
My first step is to get all users that have both values filled with:
$ADUser = Get-ADUser -Properties Name,Mail,proxyAddresses -Filter {proxyAddresses -like '*' -and mail -like '*'}
then i try to run it trough a foreach loop with an integrated if statement
$result = foreach ($User in $ADUser){
$proxystring = $User.proxyAddresses
$Mailstring = $User.Mail
$Mailstring = $Mailstring.ToString()
if ($proxystring -contains '*$Mailstring*'){
Write-Host 'läuft'
}
else{
Write-Output($User).Name
}
}
in the if statement i tried
if ($proxystring -contains '*$Mailstring*')
if ($proxystring -contains $Mailstring)
if ($proxystring -like $Mailstring)
if (($proxystring).contains($Mailstring))
As in the mainpart of the Code seen, I also tried to pass it to a string because i thought the format might be a problem.
Everywhere i looked a variable only gets matched with a string, not with other variables.
If anyone happens to know what my mistake is i would be grateful.
You would need to remove the preceding SMTP: / smtp: from each address in proxyAddresses for this to work properly:
$result = :outer foreach ($User in $ADUser){
foreach($address in $user.proxyAddresses) {
# remove the leading `smtp:` from each address
$mail = $address -replace '^smtp:'
# and compare, if the user's mail was in the `proxyAddresses` array
if($mail -eq $User.mail) {
# there is no need to keep checking, we can skip this user
# and go next
continue outer
}
}
# if the user's `mail` wasn't found in the `proxyAddresses` array
# output this user
$user
}
You could also use -notcontains to simplify the above code a lot but this requires prepending smtp: to user's mail attribute:
$result = foreach ($User in $ADUser){
if($user.proxyAddresses -notcontains ('smtp:' + $user.mail)) {
$User
}
}

How to speed up the process in PowerShell

I've a simple script that generate orphan OneDrive report. It's working but it's very slow so I'm just wondering how could I modify my script to speed up the process. Any help or suggestion would be really appreciated.
Basically this is what I'm doing:
Get the owner email from "Owner" column and check it using AzureAD to see if I get any error
If I get an error then check it in on-prem ADGroup
If that owner is existed in the on-prem ADGroup then it's an orphan
Export only that user to a new csv file
$ImportData = "E:\scripts\AllOneDriveUser.csv"
$Report = "E:\scripts\OrphanOneDrive.csv"
$CSVImport = Import-CSV $ImportData
ForEach ($CSVLine in $CSVImport) {
$CSVOwner = $CSVLine.Owner
try{
Get-AzureADUser -ObjectId $CSVOwner
}catch{
$StatusMessage = $_.Exception.Message
if($Null -eq $StatusMessage){
Write-Host "User Found, Ignore from orphan list."
}else{
#Owner not found in AzureAD
$group = 'TargetGroup'
$filter = '(memberof={0})' -f (Get-ADGroup $group).DistinguishedName
$filterName = Get-ADUser -LDAPFilter $filter
$ModifiedOwner = $CSVOwner -split"#"[0]
if( $ModifiedOwner[0] -in $filterName.Name ){
Write-host "Adding it into orphaned list"
$CSVLine | Export-Csv $Report -Append -notypeinformation -force
}else{
Write-Host "Not orphaned"
}
}
}
}
I have over 8000 record in my import csv file and over 5000 member in my on-prem AD group so it taking very long.
You can greatly improve your script by using a HashSet<T> in this case, but also the main issue of your code is that you're querying the same group over and over, it should be outside the loop!
There is also the use of Export-Csv -Append, appending to a file per loop iteration is very slow, better to streamline the process with the pipelines so Export-Csv receives the objects and exports only once instead of opening and closing the FileStream everytime.
Hope the inline comments explain the logic you can follow to improve it.
$ImportData = "E:\scripts\AllOneDriveUser.csv"
$Report = "E:\scripts\OrphanOneDrive.csv"
# we only need to query this once! outside the try \ catch
# a HashSet<T> enables for faster lookups,
# much faster than `-in` or `-contains`
$filter = '(memberof={0})' -f (Get-ADGroup 'GroupName').DistinguishedName
$members = [Collections.Generic.HashSet[string]]::new(
[string[]] (Get-ADUser -LDAPFilter $filter).UserPrincipalName,
[System.StringComparer]::OrdinalIgnoreCase
)
Import-CSV $ImportData | ForEach-Object {
# hitting multiple times a `catch` block is expensive,
# better use `-Filter` here and an `if` condition
$CSVOwner = $_.Owner
if(Get-AzureADUser -Filter "userprincipalname eq '$CSVOwner'") {
# we know this user exists in Azure, so go next user
return
}
# here is for user not found in Azure
# no need to split the UserPrincipalName, HashSet already has
# a unique list of UserPrincipalNames
if($hash.Contains($CSVOwner)) {
# here is if the UPN exists as member of AD Group
# so output this line
$_
}
} | Export-Csv $Report -NoTypeInformation

Powershell problem with values comparison in ARS - false positive

I am updating mass info about users. The script is getting data from a file, comparing with the current data in ARS and changing if necessary.
Unfortunately for two parameters - "st" and "postOfficeBox" - it is updating data all the time altho the data is the same in the file and in AD.
first one is empty, the second one is not
I have checked directly -
PS> $user.$parameters.postofficebox -eq $userQuery.$parameters.postofficebox
True
How can I handle this? It is not an error, but it is annoying and not efficient updating the same data all the time.
#Internal Accounts
$Parameters = #("SamAccountName", "co", "company", "department", "departmentNumber","physicalDeliveryOfficeName","streetAddress","l","st","postalCode","employeeType","manager", "division", "title", "edsvaEmployedByCountry", "extensionAttribute4", "EmployeeID", "postOfficeBox")
#import of users
$users = Import-csv -Path C:\ps\krbatch.csv -Delimiter "," -Encoding UTF8
Connect-QADService -Proxy
#Headers compliance
$fileHeaders = $users[0].psobject.Properties | foreach { $_.Name }
$c = Compare-Object -ReferenceObject $fileHeaders -DifferenceObject $Parameters -PassThru
if ($c -ne $null) {Write-Host "headers do not fit"
break}
#Check if account is enabled
foreach ($user in $users) {
$checkEnable = Get-ADUser $user.SamAccountName | select enabled
if (-not $checkEnable.enabled) {
Write-Host $user.SamAccountName -ForegroundColor Red
}
}
#Main loop
$result = #()
foreach ($user in $users) {
$userQuery = Get-QADUser $user.sAMaccountName -IncludedProperties $Parameters | select $Parameters
Write-Host "...updating $($user.samaccountname)..." -ForegroundColor white
foreach ($param in $Parameters) {
if ($user.$param -eq $userQuery.$param) {
Write-Host "$($user.samaccountname) has correct $param" -ForegroundColor Yellow
}
else {
try {
Write-Host "Updating $param for $($user.samaccountname)" -ForegroundColor Green
Set-QADUser -Identity $user.SamAccountName -ObjectAttributes #{$param=$user.$param} -ErrorVariable ProcessError -ErrorAction SilentlyContinue | Out-Null
If ($ProcessError) {
Write-Host "cannot update $param for $($user.samaccountname) $($error[0])" -ForegroundColor Red
$problem = #{}
$problem.samaccountname = $($user.samaccountname)
$problem.param = $param
$problem.value = $($user.$param)
$problem.error = $($error[0])
$result +=[pscustomobject]$problem
}
}
catch { Write-Host "fail, check if the user account is enabled?" -ForegroundColor Red}
}
}
}
$result | Select samaccountname, param, value, error | Export-Csv -Path c:\ps\krfail.csv -NoTypeInformation -Encoding UTF8 -Append
And also any suggestions to my code, where I can make it better will be appreciated.
Similar to what Mathias R. Jessen was suggesting, the way you are testing the comparison doesn't look right. As debugging approaches either add the suggested Write-Host command or a break point such that you can test at run time.
Withstanding the comparison aspect of the question there's a loosely defined advisory request that I'll try to address.
Why are you you using QAD instead of the native AD module. QAD is awesome and still outshines the native tools in a few areas. But, (without a deep investigation) it looks like you can get by with the native tools here.
I'd point out there's an instance capability in AD cmdlets that allows for incremental updates even without comparison... ie you can run the Set-ADUser cmdlet and it will only write the attributes if they different.
Check out the help file for Set-ADUser
It would be inappropriate and time consuming for me to rewrite this. I'd suggest you check out those concepts for a rev 2.0 ... However, I can offer some advice bounded by the current approach.
The way the code is structured it'll run Set-QADUser for each attribute that needs updating rather than setting all the attributes at once on a per/user basis. Instead you could collect all the changes and apply in a single run of Set-QADUser per each user. That would be faster and likely have more compact logging etc...
When you're checking if the account is enabled you aren't doing anything other than Write-Host. If you wanted to skip that user, maybe move that logic into the main loop and add a Continue statement. That would also save you from looping twice.
Avoid using +=, you can use an [ArrayList] instead. Performance & scalability issues with += are well documented, so you can Google for more info. [ArrayList] might look something like:
$result = [Collections.ArrayList]#()
# ...
[Void]$result.Add( [PSCustomObject]$problem )
I'm also not sure how the catch block is supposed to fire if you've set -ErrorAction SilentlyContinue. You can probably remove If($ProcessError)... and and move population of $Result to the Catch{} block.

Add multiple users to multiple groups from one import csv (another follow up)

First I have to say I've this and this thread already, but couldn't figure out an answer from those.
I have a CSV file looking like this:
Username,Groups
User01,Group01;Group02;Group03
User02,Group10;Group24;Group08
User03,Group13;Group02;Group42
etc etc... There are hundreds of users and hundreds of different groups in total, so splitting individual users and/or groups to their own lines manually is not really an option.
I cannot figure out the logic how to process the lines with foreach while splitting the imported CSV twice with different delimiters and then foreach the groups per user again. Any ideas..?
You can split groups on ; character, so if you want add users to groups use this:
$src = Import-Csv yourfile.csv
foreach($line in $src){
$user = $line.Username
$groups = $line.Groups -split ";"
foreach($group in $groups){
Add-ADGroupMember -Identity $group -Members $user
# other code which uses $group and $user
}
}
You probably want something like
$Line = import-csv yourfile.csv
#Skip first line here
foreach ($Data in $Line)
{
$User = $Data.v1
$Group1 = $Data.v2
$Group2 = $Data.v3
$Group3 = $Data.v4
write-host "User: "$User
write-host "Group1: "$Group1
write-host "Group2: "$Group2
write-host "Group3: "$Group3
Write-Host ""
}

Compare two csv files and find discrepancies

I am new in powershell world , I got some project on powershell for inventory reconciling .
I am not sure how to proceed on this , I tried some basic steps and I am able to export
users/group/group membership.
Following are the requirements :
Now What I have achieved - Thanks to Govnah
AD query:
Get-QADUser -searchRoot $OuDomain -SizeLimit 0 |
Select-Object dn, sAMAccountName, #{Name="Groups";Expression={(Get-QADMemberOf $_ | Select-Object -expandProperty Name) -join ";"}} |
Sort-Object SamAccountName |
export-csv $FilePath
I have now two csv files likes AD_users.csv and Oracle_users.csv
I want to compare both files and redirect the difference like
AD users does not exist in Oracle
Oracle User does not exist in AD
Sample data
AD_users.csv
u388848993
K847447388
u994888484
Oracle_users.csv
k095848889
u388848993
I can query oracle database , AD query is also fine the only concern is that I am not able to compare the output.
I did it something like this in a script I wrote:
[System.Collections.ArrayList]$adlist = Get-Content c:\users\sverker\desktop\ad.csv |Sort-Object
[System.Collections.ArrayList]$oraclelist = Get-Content c:\users\sverker\desktop\oracle.csv |Sort-Object
$Matching_numbers = #()
ForEach ($number in $adlist)
{
if ($oraclelist.Contains($number))
{
$Matching_numbers += $number
}
}
ForEach ($number in $Matching_numbers)
{
$adlist.Remove($number)
$oraclelist.Remove($number)
}
now $Matching_numbers now contains the matching numbers
and $adlist contains only numbers from AD
and $oraclelist only numbers from Oracle
you can then loop through the list and display values:
Write-Host "Matches:"
ForEach ($value in $Matching_numbers)
{
$Message += $value + [Environment]::NewLine
}
Write-Host $Message
Write-Host "AD only:"
ForEach ($value in $adlist)
{
$MessageAd += $value + [Environment]::NewLine
}
Write-Host $MessageAd
Write-Host "Oracle only:"
ForEach ($value in $oraclelist)
{
$MessageOracle += $value + [Environment]::NewLine
}
Write-Host $MessageOracle
or simply by writing
$Matching_numbers
will output the list to console
You can output the $Message variables to a file or so..
No doubt, there is a nicer way to do it, but this worked for me for a certain type of file.