Hallo I got a question with my update script for my active directory
I am trying to update a user using .csv document
It’s for my understanding very simple but there is an error which I cant find out why it occurs.
My Script:
#Get CSV content
$CSVrecords = Import-Csv "C:\scripts\test.csv" -Delimiter ";"
#Create arrays for skipped and failed users
$SkippedUsers = #()
$FailedUsers = #()
#Loop trough CSV records
foreach ($CSVrecord in $CSVrecords) {
$upn = $CSVrecord.UserPrincipalName
$user = Get-ADUser -Filter "userPrincipalName -eq '$upn'"
if ($user) {
try {
$user | Set-ADUser -Department $CSVrecord.Department -Company $CSVrecord.Company -ErrorAction STOP
}
catch {
$FailedUsers += $upn
Write-Warning "$upn user found, but FAILED to update."
}
}
else {
Write-Warning "$upn not found, skipped"
$SkippedUsers += $upn
}
}
The Date that I am trying to use for the Update:
UserPrincipalName
Department
Company
test.nikola#test.local
Test
123
The Error message that I get: user found, but FAILED to update
Maybe I am blind but i cant find the error ...
As mentioned in the comments, your catch block is hiding all terminating exceptions. Since you never output or inspect the given exception, there's no way to tell what went wrong.
Change it to:
try {
$user | Set-ADUser -Department $CSVrecord.Department -Company $CSVrecord.Company -ErrorAction STOP
}
catch {
$FailedUsers += $upn
Write-Warning "$upn user found, but FAILED to update: $_"
}
Inside the catch block, $_ will refer to the exception that was caught, so at least you now get a chance to see the underlying error message.
Related
I'm working on a powershell script that will do the following:
Will log into our O365 instance
Read the CSV file and update the users attributes (such as department and title)
If the user isn't found, create a new one with those attributes.
If i comment out the New-AzureADUser section it will work fine and update the users that are found, but when i do call New-AzureADUser i get the following error.
New-AzureADUser : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'DisplayName'. Specified method is not supported.
I understand the meaning behind the error in that it wants a string, not an object but i'm a little unsure on next steps.
# Connect to AzureAD
Connect-AzureAD
# Get CSV content
$CSVrecords = Import-Csv bra_o365_import1.csv -Delimiter ","
#CSV contains UserPrincipalName,Department,DisplayName,FirstName,LastName,Title
# Loop trough CSV records
foreach ($CSVrecord in $CSVrecords) {
$upn = $CSVrecord.UserPrincipalName
$user = Get-AzureADUser -Filter "userPrincipalName eq '$upn'"
if ($user) {
try{
$user | Set-AzureADUser -Department $CSVrecord.Department -JobTitle $CSVrecord.Title
} catch {
Write-Warning "$upn user found, but FAILED to update."
}
}
else {
New-AzureADUser -DisplayName $CSVrecords.DisplayName -UserPrincipalName $CSVrecords.UserPrincipalName -AccountEnabled $true -Department $CSVrecord.Department -JobTitle $CSVrecord.Title
Write-Host $CSVrecords.DisplayName
}
}
I have been developing AzureAD licence script based on AD Group. So, Find users with a direct assigned, find them in AD, evaluate what group they should be a member of, add them to licensing group. I have hashtable with multiple values $SKUToGroupRev. I can not match hashtable with multiple values with if($ADGroup = $SKUToGroupRev[$SKU.SkuId]) .
From what I want to do :
if there are 18181a46-0d4e-45cd-891e-60aabd171b4e and 0c266dff-15dd-4b49-8397-2bb16070ed52 inside SKUs variable for below command then I will add AD group related to the inside hashtable such as O365_E1_Users
OR
if there are 6fd2c87f-b296-42f0-b197-1e91e994b900 and 0c266dff-15dd-4b49-8397-2bb16070ed52 inside SKUs variable for below command then I will add AD group related to the inside hashtable such as O365_E3_Users
e.g:
# Get licensed SKUs for the user
$aaduser = get-azureaduser -objectID $user.UserPrincipalName
$SKUs = $aaduser | Select UserPrincipalName,ImmutableID -ExpandProperty AssignedLicenses
e.g output:
UserPrincipalName ImmutableId DisabledPlans SKUId
----------------- ----------- ------------- -------------
User01#contoso.com x+MVG6EKEUWHi3r6zjgzCA== {041fe683-03e4-45b6-b1af-c0cdc516da4f... 6fd2c87f-b296-42f0-b197-1e91e994b900
User01#contoso.com x+MVG6EKEUWHi3r6zjgzCA== {} 0c266dff-15dd-4b49-8397-2bb16070ed52
Here is my script :
$CSVfile = "C:\temp\LicenseToGroupUsers.csv"
# Import the CSV file
try {
$users = import-csv $CSVfile
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
Break
}
write-warning "About to add the following users to license groups for complete SKU:"
foreach ($user in $users){
write-host $user.UserPrincipalName
}
Read-Host -Prompt "Press Enter to continue or CTRL+C to quit"
$e3 = -split "0c266dff-15dd-4b49-8397-2bb16070ed52 6fd2c87f-b296-42f0-b197-1e91e994b900"
$e1 = -split "18181a46-0d4e-45cd-891e-60aabd171b4e 0c266dff-15dd-4b49-8397-2bb16070ed52"
$TEAMS_EXPLORATORY = -split "710779e8-3d4a-4c88-adb9-386c958d1fdf 0c266dff-15dd-4b49-8397-2bb16070ed52"
#$FLOW_FREE_E3 = -split "f30db892-07e9-47e9-837c-80727f46fd3d 6fd2c87f-b296-42f0-b197-1e91e994b900 0c266dff-15dd-4b49-8397-2bb16070ed52"
foreach ($user in $users){
$groupsToAdd = #()
$groupsToRemove = #()
write-host "Processing" $user.UserPrincipalName
# Get licensed SKUs for the user
$aaduser = get-azureaduser -objectID $user.UserPrincipalName
#$SKUs = $aaduser | Select UserPrincipalName,ImmutableID -ExpandProperty AssignedLicenses
#Get the AD ObjectGuid for the group add (cannot use UPN)
$ImmutableID = "" #Null these out otherwise gets reused from previous
#Have to match using the guid
$ImmutableID = $aaduser.ImmutableID
if ($ImmutableID) {$objectGUID = ([GUID][System.Convert]::FromBase64String($ImmutableID)).Guid}
else {
write-warning "Error getting ImmutableID for $UPN, user is likely cloud only, skipping"
Break
}
# test 1
$licenses = $aaduser.AssignedLicenses.SkuId
$is_e1 = !($e1 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_e1 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to E1Group" -ForegroundColor Green
Write-Host "Test 1: $is_e1"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
$is_e3 = !($e3 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_e3 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to E3Group" -ForegroundColor Green
Write-Host "Test 3: $is_e3"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
$is_TEAMS_EXPLORATORY = !($TEAMS_EXPLORATORY | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_TEAMS_EXPLORATORY -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to (TEAMS_EXPLORATORY)E1Group" -ForegroundColor Green
Write-Host "Test 1: $is_TEAMS_EXPLORATORY"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}
<# $is_FLOW_FREE_E3 = !($FLOW_FREE_E3 | ForEach-Object { $licenses.Contains($_) }).Contains($false)
if($is_FLOW_FREE_E3 -eq "True"){
try {
write-host "Adding" $user.UserPrincipalName"to (FLOWFREE)E3Group" -ForegroundColor Green
Write-Host "Test 1: $is_FLOW_FREE_E3"
}
catch {
$errorZero = $Error[0]
write-host "Error: " $errorZero -ForegroundColor Red #Writes the latest error
}
}#>
}
To test agains a combination of SkuID's, using a lookup hashtable as in your first approach is not the easiest way I think. Your current approach looks much better to me, only I would not put the ID's in array variables, but test them literally against the ID's as they are found in the users AssignedLicenses.
Something like this:
$CSVfile = "C:\temp\LicenseToGroupUsers.csv"
# Import the CSV file
$users = Import-Csv -Path $CSVfile
Write-Warning "About to add the following users to license groups for complete SKU:"
$users.UserPrincipalName -join [environment]::NewLine
Write-Host
$answer = Read-Host -Prompt "Press Enter to continue or Q to quit"
if ($answer[0] -eq 'Q') { Clear-Host; exit }
foreach ($user in $users) {
Write-Host "Processing" $user.UserPrincipalName
$ImmutableID = $null # Null these out
$ADGroup = $null
# Get licensed SKUs for the user
$aaduser = Get-AzureADUser -objectID $user.UserPrincipalName
# Get the AD ObjectGuid for the group add (cannot use UPN)
# Have to match using the guid
$ImmutableID = $aaduser.ImmutableID
if (![string]::IsNullOrWhiteSpace($ImmutableID)) {
$objectGUID = ([GUID][System.Convert]::FromBase64String($ImmutableID)).Guid}
else {
Write-Warning "Error getting ImmutableID for $($user.UserPrincipalName), user is likely cloud only, skipping"
continue # skip this one and proceed with the next user
}
$licenses = #($aaduser.AssignedLicenses.SkuId) # force it to be an array
##########################################################################################
# Apparently, SkuId '0c266dff-15dd-4b49-8397-2bb16070ed52' is needed for all combinations,
# so we could already rule out users that do not have that ID in their $licenses..
# if that is indeed the case, you can simplify al other tests by not having to check
# for this ID every time..
# for now, this is an assumption, so commented out.
# if (!($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52')) {
# Write-Warning "Could not determine a group for user $($user.UserPrincipalName)"
# continue # skip this one and proceed with the next user
# }
##########################################################################################
# test E1: 'Microsoft 365 Audio Conferencing' and 'OFFICE 365 E1'
if ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '18181a46-0d4e-45cd-891e-60aabd171b4e') {
# Add this user to group 'O365_E1_Users'
$ADGroup = 'O365_E1_Users'
}
# test E3: 'Microsoft 365 Audio Conferencing' and 'OFFICE 365 E3'
elseif ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '6fd2c87f-b296-42f0-b197-1e91e994b900') {
if ($licenses -contains 'f30db892-07e9-47e9-837c-80727f46fd3d') { # also 'MICROSOFT FLOW FREE' ?
# Add this user to group 'FLOW_FREE_E3'
$ADGroup = 'FLOW_FREE_E3'
}
else {
# Add this user to group 'O365_E3_Users'
$ADGroup = 'O365_E3_Users'
}
}
# test 'Microsoft 365 Audio Conferencing' and 'MICROSOFT TEAMS EXPLORATORY'
elseif ($licenses -contains '0c266dff-15dd-4b49-8397-2bb16070ed52' -and
$licenses -contains '710779e8-3d4a-4c88-adb9-386c958d1fdf') {
# Add this user to group 'TEAMS_EXPLORATORY'
$ADGroup = 'TEAMS_EXPLORATORY'
}
# finished the conditions, now see if we can add the user to one of the groups
if (![string]::IsNullOrWhiteSpace($ADGroup)) {
try {
Write-Host "Adding $($user.UserPrincipalName) to $ADGroup" -ForegroundColor Green
# Add-ADGroupMember -Identity $ADGroup -Members $objectGUID
}
catch {
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
else {
Write-Warning "Could not determine a group for user $($user.UserPrincipalName)"
}
}
I am writing the script which should validate the user in the active directory and gets some AD information. I am struggling with the error handling in this script:
$user = (Read-Host -Prompt 'Enter your network id').ToUpper()
#check if the user exists in the AD database
$userid= Get-ADUser $user | Select SamAccountName
$userid = $user
if (($user -match $userid)) {
Write-Host $user "exists in AD"
}else{
write-host "user cannot be found"
}
If someone who uses the script will put incorrect userId (which doesn't exist in AD), the script will throw an error message :
Get-ADUser : Cannot find an object with identity: 'DUMMY' under: 'DC=company,DC=com'.
At line:9 char:11
+ $memoid = Get-ADUser $user | Select SamAccountName
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (DUMMY:ADUser) [Get-ADUser], ADIdentityNotF
oundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.
ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Even though incorrect userID was entered, I receive
= DUMMY exists in AD
How can I turn this exceptional error message into my custom message - "The user doesn't exist in AD"? Thank you in advance
For this, it is better not to use the -Identity parameter (which you imply in your code by using Get-ADUser $user)
Try
$userID = Read-Host -Prompt 'Enter your network id'
# check if the user exists in the AD database
# this will either return an ADUser object or $null
$user = Get-ADUser -Filter "SamAccountName -eq '$userID'" -ErrorAction SilentlyContinue
if ($user) {
Write-Host "$($user.SamAccountName) exists in AD" -ForegroundColor Green
}
else{
Write-Host "user $($user.SamAccountName) cannot be found" -ForegroundColor Red
}
You need to catch the exceptions using try/catch
In the error message, it is telling that "cannot find that object"
So, your first approach is to check whether the user exists or not in the If statement and then put them in try/catch like below
try{
$user = (Read-Host -Prompt 'Enter your network id').ToUpper()
#check if the user exists in the AD database
$userid= Get-ADUser $user | Select SamAccountName
$userid = $user
if (($user -match $userid)) {
Write-Host $user "exists in AD"
}else{
write-host "user cannot be found"
}
}
catch
{
#Your Custom Message in case of the error is coming in Std Out . $_.Exception.Message will catch the exact error message.
"Error Message: "+ "$_.Exception.Message"
}
The statement: $userid = $user needs to be deleted. As is it insures that you always have a match.
Next place your call to Get-ADUser in a Try/Catch construct to catch the error.
$user = (Read-Host -Prompt 'Enter your network id').ToUpper()
#check if the user exists in the AD database
Try {
$userid= Get-ADUser $user -EA "STOP" | Select SamAccountName
Write-Host $user "exists in AD"
}
Catch {
#*** Process errors here ***
write-host "user cannot be found"
Exit
}
#Continue your script here
Note: I don't have access to a Server so this is untested but should work in theory!
HTH
I have to delete users from my AD through Powershell. Powershell has to ask me who I want to delete, once I type in the username it should delete the account. Also when Powershell succesfully deleted the account or it should give me a message.
I'm kind of noob at this, but here is my code:
function aduser-remove($userremove){
Remove-ADUser -Identity $delete
if ($delete -eq $userremove){
return $true
}
else {
return $false
}
}
$delete = Read-host "Which user do you want to delete? (Type in username)."
aduser-remove $delete
if ($userremove -eq $true){
Write-Host $delete "deleted succesfully!" -ForegroundColor Green
}
elseif ($userremove -eq $false){
Write-Host "An error occured by deleting" $delete -ForegroundColor Red
}
else {
Write-Host $delete "does not exist." -ForegroundColor DarkGray
}
The result here is that Powershell does ask if I want to delete the account and it works. But Powershell keeps giving me the else message instead of the if message. Deleting the account was succesfull.
I have no idea what to now or if I'm missing something (I bet I am otherwise it would work).
I hope you guys can help me!
As commented, your code uses variables in places where they do not exist.
Also, I would recommend trying to find the user first and if you do, try and remove it inside a try/catch block, as Remove-ADUser creates no output.
Below a rewrite of your code. Please note that I have changed the name of the function to comply with the Verb-Noun naming convention in PowerShell.
function Remove-User ([string]$userremove) {
# test if we can find a user with that SamAccountName
$user = Get-ADUser -Filter "SamAccountName -eq '$userremove'" -ErrorAction SilentlyContinue
if ($user) {
try {
$user | Remove-ADUser -ErrorAction Stop -WhatIf
return $true
}
catch {
return $false
}
}
# if we get here, the user does not exist; returns $null
}
$delete = Read-host "Which user do you want to delete? (Type in username)."
# call your function and capture the result
$result = Remove-User $delete
if ($result -eq $true){
Write-Host "User $delete deleted succesfully!" -ForegroundColor Green
}
elseif ($result -eq $false){
Write-Host "An error occured while deleting user $delete" -ForegroundColor Red
}
else {
Write-Host "$delete does not exist." -ForegroundColor DarkGray
}
Note also that I have put in the -WhatIf switch. This switch ensures you will only get a message of what would happen. No user is actually deleted. Once you are satisfied the code does what you want, remove the -WhatIf switch.
Hope that helps
If you have rsat installed https://www.microsoft.com/en-us/download/details.aspx?id=45520
remove-aduser https://learn.microsoft.com/en-us/powershell/module/addsadministration/remove-aduser?view=win10-ps
So in my script, when a user changes their name, I rename their AD object accordingly, change their Exchange (2007) properties, and then based on those changes, I change the info store that it is in.
I store the new DistinguishedName in $newDN when retrieving the mailbox, explicitly try to use DC01.domain.local, and then when I attempt to do the move, it tries searching on DC02.domain.local, therefore not finding the object due to replication lag and receive this error below. Anyone have any ideas on this? Many thanks!
StatusCode : -1056749240
StatusMessage : Error occurred in the step: Approving object. Failed to open object 'LDAP://DC02.domain.local/CN=di matteo\, robert,OU=Users,DC=domain,DC=local' with error: There is no such object on the server.
$mailbox = Get-Mailbox -ID $newDN `
-DomainController DC01.domain.local
$mailbox | Move-Mailbox `
-TargetDatabase $targetIS `
-Confirm:$False `
-DomainController DC01.domain.local `
-GlobalCatalog DC01.domain.local
Sometimes the move works, but when it doesn't, it leaves the SourceDomainController property empty (like below), where as if it does work, it populates it correctly with DC01.domain.local.
SourceServer : CCR.domain.local
SourceDatabase : CCR\IS1\IS1
SourceGlobalCatalog : DC01.domain.local
SourceDomainController :
TargetGlobalCatalog : DC01.domain.local
TargetDomainController : DC01.domain.local
TargetMailbox :
TargetServer : CCR.domain.local
TargetDatabase : CCR\IS2\IS2
Baffled.
Well, I've got no idea why I'm getting the results that I am, but my workaround is here...Like I said before, I query/write all my AD changes to 'DC01.domain.local' But now, when I call my function, I do my mailbox lookup on 'DC02.domain.local'. If the lookup fails, increment the counter, sleep for about 20 seconds, and then retry. My initial testing, it has only had to loop once.
$dc = "DC01.domain.local"
Function moveDB ($targetIS, $newDN, $counter) {
$dn = (Get-Mailbox -ID $newDN -DomainController $dc).DistinguishedName
If (!(Get-Mailbox $dn -DomainController "DC02.domain.local")) {
$counter++
If ($counter -le 4) {
Write-Host "`nPlease wait while I search for the mailbox object...`n" -ForegroundColor Yellow -BackgroundColor Red
Start-Sleep -Seconds 20
moveDB $targetIS $dn $dbCounter
}
Else {
Write-Host "Mailbox was not moved! Please move manually to $targetIS..." -ForegroundColor Yellow -BackgroundColor Red
return
}
}
Else {
$dn | Move-Mailbox `
-DomainController $dc `
-GlobalCatalog $dc `
-TargetDatabase $targetIS `
-Confirm:$False
}
}