Block bulk user accounts - powershell

Any way to block user account in Office365 by EmployeeID instead of UPN?
This is the script I've tried, but it can only block by UPN:
Import-Csv 'C:\BlockedUsers.csv' | ForEach-Object {
$upn = $_."UserPrincipalName"
Set-MsolUser -UserPrincipalName $upn -BlockCredential $true
}

If your csv file contains a column called EmployeeId, you can use that to get the UserPrincipalName property using the Get-AdUser cmdlet:
Import-Csv 'C:\BlockedUsers.csv' | ForEach-Object {
$user = Get-ADUser -Properties EmployeeID -Filter "EmployeeID -eq $($_.EmployeeID)"
if ($user) {
$upn = $user.UserPrincipleName
Set-MsolUser -UserPrincipalName $upn -BlockCredential $true
}
}
Edit
Judging by your comment, it seems the EmployeeID property is not always unique in your organization.
In that case, the below code should be able to handle that
Import-Csv 'C:\BlockedUsers.csv' | ForEach-Object {
$user = Get-ADUser -Properties EmployeeID -Filter "EmployeeID -eq $($_.EmployeeID)"
if ($user) {
foreach ($usr in $user) {
Write-Host "Blocking user $($usr.Name)"
$upn = $usr.UserPrincipleName
Set-MsolUser -UserPrincipalName $upn -BlockCredential $true
}
}
else {
Write-Host "User with EmployeeID $($_.EmployeeID) not found"
}
}
P.S. If your CSV can contain empty values for the EmployeeID column, change the first line into
Import-Csv 'C:\BlockedUsers.csv' | Where-Object {$_.EmployeeID -match '\S'} | ForEach-Object {
to get rid of empty or whitespace-only values.
Edit
If you are sure your CSV contains a column EmployeeId and you are not mistaking that with AD property EmployeeNumber, then perhaps this might work for you.
It uses Get-ADUser to get a collection of user objects that actually have something in their EmployeeId attribute and refines that by comparing to the ones you have read from the CSV using Where-Object.
Both EmployeeId and EmployeeNUmber are AD properties of type String. You can look that up here
# first read the CSV into an array containing only the values from the 'EmployeeID' column
$blockedUserIds = Import-Csv 'C:\BlockedUsers.csv' | Select-Object -ExpandProperty EmployeeId -Unique
# next get an array of user objects that have something in the EmployeeID attribute and only
# leave the users where the attribute can be matched to a value captured in the CSV array above
# use the '#(..)' syntax to force the result to be an array, even if only one item is found
$usersToBlock = #(Get-ADUser -Properties EmployeeID, Name, UserPrincipalName -Filter "EmployeeID -like '*'" |
Where-Object { $blockedUserIds -contains $_.EmployeeID })
# you can also use the '-LDAPFilter' parameter
# $usersToBlock = #(Get-ADUser -Properties EmployeeID, Name, UserPrincipalName -LDAPFilter "(employeeID=*)" |
# Where-Object { $blockedUserIds -contains $_.EmployeeID })
# you now should have an array of user objects that need to be blocked
if ($usersToBlock.Count) {
Write-Host "Blocking $($usersToBlock.Count) users.." -ForegroundColor Green
$usersToBlock | ForEach-Object {
Write-Host "Blocking user $($_.Name)"
Set-MsolUser -UserPrincipalName $($_.UserPrincipleName) -BlockCredential $true
}
}
else {
Write-Warning "No users found with an EmployeeId property that matches any of the values in BlockedUsers.csv"
}

Related

Need to update missing employee IDs in Active Directory by matching on Name in flat file

Recently completed an Azure AD provisioning integration between SuccessFactors and On-Prem AD.
In order for some of our existing users to get 'scoped in' to the Update provisioning, they first need to match on employee id (we currently do not use the Create functionality).
There are about 400 users that we've identified need to be matched, and our HR team has provided us with a csv with the following attributes (Full Name, EmployeeID). I need to somehow compare this file with all users in AD who have no employee id, and if not, update EmployeeId with the contents from the HR provided file.
I'm a bit stuck on how to attack this. Need a Big Brain :)
#import HR file with required attributes "Formal Name, EmployeeId"
#returns ~6500 entries
$SFUsers = Import-Csv Z:\ExportsFromProd\Global_ActiveHeadcountReport_08292022.csv
#returns ~1400 entries
#some accounts never get an employee id
$users = Get-ADUser -Filter "*" -Properties EmployeeID | Where-Object {$_.employeeID -eq $null}
foreach ($account in $users) {
$accountName = $account.name
get-aduser -Filter {Name -eq $accountName} -Properties * | Select-Object samaccountname, displayName
#this is where i need help:
<#
try {
Lookup $SFUser.'Formal Name' in $SFUsers array???
Get $SFUser.'EmployeeID' | set-aduser $account -employeeId $SFUser.'EmployeeId'
}
catch {
}
finally {
}
#>
}
'''
You can use the faster -Filter or LDAPFilter parameters of Get-ADUser to find only users where the EmployeeID property is unset.
Also, your code could be done by using Get-ADUser only once:
#import HR file with required attributes "Formal Name, EmployeeId"
#returns ~6500 entries
$SFUsers = Import-Csv -Path 'Z:\ExportsFromProd\Global_ActiveHeadcountReport_08292022.csv'
#returns ~1400 entries
#some accounts never get an employee id
$users = Get-ADUser -Filter "employeeid -notlike '*'" -Properties DisplayName, EmployeeID
# or use LDAPFilter
# $users = Get-ADUser -LDAPFilter "(!employeeID=*)" -Properties DisplayName, EmployeeID
foreach ($account in $users) {
# try and find this user in the csv file either by .Name or .DisplayName property
$HRUser = $SFUsers | Where-Object { $_.'Formal Name' -eq $account.Name -or
$_.'Formal Name' -eq $account.DisplayName}
if ($HRUser) {
$account | Set-ADUser -EmployeeID $HRUser.EmployeeId
}
else {
Write-Warning "AD user $($account.Name) not found in the CSV file.."
}
}

Replace AD attribute value with csv file header values

I want to replace AD attribute "userPrincipalName" value according to CSV file header value
here is what csv file(group.csv) contains
sAMAccountName
--------------
test.user1
test.user2
below the script
$data = Import-Csv -Path .\group.csv -Header 'sAMAccountName'
foreach($user in $data){
Get-ADUser -Filter {sAMAccountName -eq "$($user.sAMAccountName)"} | Set-ADUser -Replace #{userPrincipalName="$($user.sAMAccountName)#RES.GROUP"}
}
here I want to replace AD attribute "userPrincipalName" with the value of sAMAccountName from csv file, something like sAMAccountName#RES.GROUP
this script does not work, can anyone please correct it?
Ok, since your comment shows the CSV file indeed does not have a header, I would suggest changing the code to:
$data = Import-Csv -Path .\group.csv -Header 'sAMAccountName'
foreach($user in $data) {
$adUser = Get-ADUser -Filter "SamAccountName -eq '$($user.sAMAccountName)'" -ErrorAction SilentlyContinue
if ($adUser) {
$newUPN = '{0}#res.group' -f $user.sAMAccountName
$adUser | Set-ADUser -UserPrincipalName $newUPN
}
else {
Write-Warning "No user with SamAccountName '$($user.sAMAccountName)' could be found.."
}
}
This way, any mistakes in the file will not make the code quit when a user with that samaccountname cannot be found. Instead, in that case you will see a warning about it and the code will continue with the rest of the data.
It might be worth mentioning that you can use parameter -Server on both the Get-ADUser and Set-ADUser cmdlets to make sure you use the same domain server (DC) to set the new UPN. Otherwise, you can set it on one DC, but are looking at another which doesn't show the change immediately because the servers need time to synchronize..
Now that we have cleared up the question about the CSV and to answer your comment:
If you want to do this as a two-script solution, here's how you can do that
step 1: get all users in the search OU that have a UserPrincipalName ending in '*#test.group'
$searchBase = "OU=Teams,OU=Prod,DC=RES,DC=TEST,DC=GROUP"
Get-ADUser -SearchBase $searchBase -Filter "UserPrincipalName -like '*#test.group'" |
# select ony the SamAccountName and write to CSV with column header
Select-Object SamAccountName | Export-Csv -Path .\group.csv -NoTypeInformation
step 2: read the csv created above and
$searchBase = "OU=Teams,OU=Prod,DC=RES,DC=TEST,DC=GROUP"
$data = Import-Csv -Path .\group.csv
$result = foreach($user in $data) {
$adUser = Get-ADUser -SearchBase $searchBase -Filter "SamAccountName -eq '$($user.sAMAccountName)'" -ErrorAction SilentlyContinue
# if we have a user object AND its UserPrincipalName is not as desired go ahead and change that
if ($adUser) {
if ($adUser.UserPrincipalName -notlike '*#res.test.group') {
$newUPN = '{0}#res.test.group' -f $user.sAMAccountName
$adUser | Set-ADUser -UserPrincipalName $newUPN
# output this user object to be collected in variable $result
$adUser
}
else {
Write-Host "User $($user.sAMAccountName) already has UPN '$($adUser.UserPrincipalName)'"
}
}
else {
Write-Warning "User with SamAccountName '$($user.sAMAccountName)' not found.."
}
}
# now that we have changed some users, create a second csv with all users that were actually changed
if (#($result).Count) {
$result | Select-Object SamAccountName | Export-Csv -Path .\Updatedgroup.csv -NoTypeInformation
}
else {
Write-Host 'No users needed updating'
}
It seems a waste writing only the users SamAccountName property to the csv files.. Especially since Get-ADUser by default already returns these properties: DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName

Set-ADUser -Manager entity with Contact

I have a csv with the following fields:
User | AD_Manager_ID | Dyn_Manager_ID
abc#mydomain.com | 1234 | 1455
The Dyn_Manager_ID field is the employeeID of another user.
99% of the time it corresponds to an actual user, but sometimes it corresponds to a contact
I can get the contact like this:
Get-ADObject -Filter "employeeID -eq '1455'"
but when I try to Set-ADUser -Manager with that object, it returns a 'Cannot find an object with idenity" error.
Here is the code for regular users (non contacts):
$csvimport = import-csv -Path C:\Users\ME\Desktop\AccountChangesCSV.csv
foreach ($User in $csvimport)
{
Get-aduser -filter "employeeID -eq '$($user.DYN_Mgr_ID)'" | select-object samaccountname -
OutVariable ManagersName
Get-ADUser -Filter "employeeID -eq '$($user.AD_ID)'" | set-aduser -Manager
$ManagersName.samaccountname
}
If someone's manager could be either another user or a contact, then do not use Get-ADUser to find the manager object, but Get-ADObject instead.
If this was a contact, there is no SamAccountName property, but instead, you can use the DistinguishedName or the ObjectGUID
Try
$csvimport = Import-Csv -Path 'C:\Users\ME\Desktop\AccountChangesCSV.csv'
foreach ($user in $csvimport) {
$manager = Get-ADObject -Filter "employeeID -eq '$($user.DYN_Mgr_ID)'" -ErrorAction SilentlyContinue
if ($manager) {
# now update the users Manager property with the DistinguishedName of the manager object
Get-ADUser -Filter "employeeID -eq '$($user.AD_ID)'" |
Set-ADUser -Manager $manager.DistinguishedName # or ObjectGUID instead of DistinguishedName
}
}
This works for both AD user objects and contacts alike
I think this post has the answer: updating an ADUser's Manager with a contact card
This is the code that finally worked for me:
$csvimport = Import-Csv -Path 'C:\Users\ME\Desktop\AccountChangesCSV.csv'
foreach ($user in $csvimport) {
$manager = Get-ADObject -Filter "employeeID -eq '$($user.DYN_Mgr_ID)'" -
ErrorAction SilentlyContinue
if ($manager) {
# now update the users Manager property with the DistinguishedName of the
manager object
$aduser = Get-ADUser -Filter "employeeID -eq '$($user.AD_ID)'"
Set-AdUser -Identity $aduser.SamAccountName -replace
#{manager="$($manager.distinguishedname)"}
}
}

Powershell Get ADUser filter

I have an object called $data. I want to loop through that object to get ADUsers then do some work with that user. The problem I'm having is that the filter is not returning anything. Here is what I have.
foreach($object in $data)
{
$ADuser = Get-ADUser -filter * -Properties * -SearchBase "$($object.ouPath)" |
? { $_.objectGUID -eq $object.GUID -and $_.employeeNumber -eq $object.personID } |
Select-Object employeeNumber,
SamAccountName,
Enabled
try
{}
catch
{}
}
$data contains the following information:
personID : 9408
firstName : John
lastName : Doe
GUID : dde044a6-b11a-4c23-a4c3-7dfe798a98ce
ouPath : OU=test,DC=my,DC=domain
If your query without the conditions in the Where-Object clause works, then there either is no user with that combination of attributes, OR you are mistaking EmployeeNumber with EmployeeID.
Also, getting all users first with all of their properties and filtering out the one user you seek after that is wasteful. Better use the -Filter parameter which gets things done way faster.
Something like:
foreach($object in $data) {
# check if you don't need the EmployeeID attribute instead of EmployeeNumber
$filter = "ObjectGUID -eq '$($object.GUID)' -and EmployeeNumber -eq '$($object.personID)'"
$ADuser = Get-ADUser -Filter $filter -Properties EmployeeNumber -SearchBase $object.ouPath -ErrorAction SilentlyContinue
if ($ADuser) {
# user found, do what needs to be done here. For demo, just output to console
$ADuser | Select-Object EmployeeNumber, SamAccountName, Enabled
}
else {
Write-Warning "Could not find user with ObjectGUID = '$($object.GUID)' and EmployeeNumber = '$($object.personID)'"
}
}

Script needs converting to export to CSV

I put together the below, which does the job. However, the output isn't very workable. So I wanted to output this all to a CSV using Export-Csv. Im aware I can do this by moving to a ForEach-Object query, but im not entirely sure how to achieve that.
I have added an attempt to convert it in hopes of a little help. I'm not sure how to specify the variable for each object. For example the first section calls all domains in the forest. How do i use each response in the next piped query? and so on.
$domains = (Get-ADForest).Domains
$controllers = #()
$worked = $false
foreach ($domain in $domains) {
$controller = Get-ADDomainController -Discover -ForceDiscover -DomainName $domain |
Select-Object HostName
$controllers += $controller
}
while (-not $worked) {
try {
foreach ($item in $controllers) {
$value = $item.HostName.Value
Write-Host $value
Write-Host 'Domain Admins'
Get-ADGroupMember -Identity 'Domain Admins' -Server $value |
Get-ADUser -Properties name, samaccountname, Description, EmailAddress |
Where {$_.Enabled -eq $true} |
Format-Table Name, SamAccountName, Description, EmailAddress -AutoSize
}
$worked = $true
} catch {}
}
Conversion Attempt
ForEach-Object{
(Get-ADForest).domains | Get-ADDomainController -Discover -ForceDiscover -DomainName $domain |Select-Object HostName | Get-ADGroupMember -identity 'Domain Admins' -Server $value | Get-ADUser -Properties samaccountname, Description, EmailAddress | Where {$_.Enabled -eq $true}
}| Export-Csv -Path "$HOME/Desktop/DomainAdmins.csv" samaccountname, Description, EmailAddress -AutoSize
If you can get the values from your Get-ADUser call and put them in an object, you can then pipe to convertto-csv.
Here's an example:
$arr = #([pscustomobject]#{name="name"; sam="samaccountname"}, [pscustomobject]#{name="name2"; sam="samaccountname2"});
$arr | ConvertTo-Csv -NoTypeInformation
"name","sam"
"name","samaccountname"
"name2","samaccountname2"
You could get rid of the Format-Table call. The code I've shown in the example pipes and array of objects into the convertto-csv cmdlet. So if Get-ADUser returns objects, you should be able to pipe right into ConvertTo-CSV or Export-Csv -append
The objects are hashtables that are cast to pscustomobjects, it's a nice quick way to illustrate the technique.
The result, as shown, will be csv headers that match your hashtable keys, and the hastable values will be the CSV values.
This is working fine in my local environment and storing the result in D:\Test_File.csv
$domains = (Get-ADForest).Domains
$controllers = #()
$worked = $false
foreach ($domain in $domains) {
$controller = Get-ADDomainController -Discover -ForceDiscover -DomainName $domain | Select-Object HostName
$controllers += $controller
}
while (-not $worked) {
try
{
foreach ($item in $controllers)
{
$value = $item.HostName.Value
Write-Host $value
Write-Host 'Domain Admins'
Get-ADGroupMember -Identity 'Domain Admins' -Server $value |
Get-ADUser -Properties name, samaccountname, Description, EmailAddress |?{$_.Enabled -eq $true}|Export-Csv -Append "D:\Test_File.csv"
}
#$worked = $true
}
catch
{
$Error_Message=$_.Exception.Message
}
}