I’ve got this code which should remove the user from all the groups a user is member of in azureAD.
Some of the groups I can’t remove due to restrictions which result in this type of error messages
Remove-AzureADGroupMember : Error occurred while executing RemoveGroupMember
Code: Request_BadRequest
Message: Unable to update the specified properties for objects that have originated within an external service.
RequestId: fc9382f2-4441-417e-a6e1-bb3bd05ef9d1
DateTimeStamp: Wed, 15 Apr 2020 06:11:45 GMT
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed
At line:9 char:34
My question is how do I catch these errors so that these are not shown on the screen. can this be put in an error log?
my code is
[pre]
#connect to azureAD
Connect-AzureAD #read file with users (email address)
$users = import-csv c:\temp\toRemove.csv
foreach ($user in $users) { #get the users objectID from Azure
$UserObjectID =get-AzureAdUser -objectId $user.SamAccountName |select objectID #grab the clean objectID from the user
$SelectUserObjectID= $userObjectID.objectID #find all the groups a user is member off
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $SelectUserObjectID
foreach ($group in $UserObjectIDGroupMemberShip) { #remove the user from each indivudual group
$removeAzureAdGroupMember = Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $SelectUserObjectID
}
}
[/pre]
if someone is interested here’s the final working script
[pre]
#connect to azureAD
Connect-AzureAD #read file with users (email address)
$users = import-csv c:\temp\toRemove.csv
$ErrorLog = “c:\temp\groupdeletionErrors.txt”
foreach ($user in $users) { #get the users objectID from Azure
$UserObjectID =get-AzureAdUser -objectId $user.SamAccountName |select objectID #grab the clean objectID from the user
$SelectUserObjectID= $userObjectID.objectID #find all the groups a user is member off
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $SelectUserObjectID
foreach ($group in $UserObjectIDGroupMemberShip) { #remove the user from each indivudual group
try {
$removeAzureAdGroupMember = Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $SelectUserObjectID
}
catch { #the groups that cannot be removed are safed in the error log
“Error removing $group” + “:” + “$_” |Add-Content $ErrorLog
}
finally { #output on screen
Write-host "user is removed from " + “-” + $group.DisplayName
}
}
}
Just as an aside note: You declare the variable $removeAzureAdGroupMember but you never use it. And you should do yourself and all others a favor and indent your code to make it easier readable. You may read the Powershell Best Practice and Style Guide.
Just as an aside note: You declare the variable $removeAzureAdGroupMember but you never use it. And you should do yourself and all others a favor and indent your code to make it easier readable. You may read the Powershell Best Practice and Style Guide.
[/quote]
don’t quite understand your remark on the $removeAzureAdGroupMember because when I check the user in question the groups that can be removed are removed. concerning the the readability of the code I copy pasted it from my original powershell window and the indents are there
I don’t understand why it got removed but here’s the code again
[pre]
#connect to azureAD
Connect-AzureAD #read file with users (email address)
$users = import-csv c:\temp\toRemove.csv
$ErrorLog = “c:\temp\groupdeletionErrors.txt”
foreach ($user in $users) { #get the users objectID from Azure
$UserObjectID =get-AzureAdUser -objectId $user.SamAccountName |select objectID #grab the clean objectID from the user
$SelectUserObjectID= $userObjectID.objectID #find all the groups a user is member off
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $SelectUserObjectID
foreach ($group in $UserObjectIDGroupMemberShip) { #remove the user from each indivudual group
try {
$removeAzureAdGroupMember = Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $SelectUserObjectID
$removeAzureAdGroupMember
}
catch { #the groups that cannot be removed are safed in the error log
“Error removing $group” + “:” + “$_” |Add-Content $ErrorLog
}
finally { #output on screen
Write-host "user is removed from " + “-” + $group.DisplayName
}
}
}
here’s the code again and I’ve added the variable again however what I don’t understand at this point is why it’s working even without adding the second $removeAzureAdGroupMember
[pre]
#connect to azureAD
Connect-AzureAD #read file with users (email address)
$users = import-csv c:\temp\toRemove.csv
$ErrorLog = “c:\temp\groupdeletionErrors.txt”
foreach ($user in $users) { #get the users objectID from Azure
$UserObjectID =get-AzureAdUser -objectId $user.SamAccountName |select objectID #grab the clean objectID from the user
$SelectUserObjectID= $userObjectID.objectID #find all the groups a user is member off
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $SelectUserObjectID
foreach ($group in $UserObjectIDGroupMemberShip) { #remove the user from each indivudual group
try {
$removeAzureAdGroupMember = Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $SelectUserObjectID
$removeAzureAdGroupMember
}
catch { #the groups that cannot be removed are safed in the error log
“Error removing $group” + “:” + “$_” |Add-Content $ErrorLog
}
finally { #output on screen
Write-host "user is removed from " + “-” + $group.DisplayName
}
}
}
[/pre]
ps don’t know what is wrong with the indents but can’t get it working correctly mea culpa
You should avoid to comment obvious things. If the command is Connect-AzureAD even an unexperienced Powersheller knows that this command connects to an Azure AD. Powershell is quite self-explanatory.
In your try block you assign the output of Remove-AzureADGroupMember to a variable. Does this cmdlet actually produce any output? I wouldn’t expect it to by default. Even if it does - you assign a variable and output this variable right away and do not use it any further. So it’s not needed at all - that’s what I meant before.
What editor do you use to write your scripts? (Just out of my curiosity)
Logs have their place, but you’re taking all of the analysis functionality of Powershell if you are not using objects. If you do something like this:
Connect-AzureAD
$users = import-csv c:\temp\toRemove.csv
$results = foreach ($user in $users) {
$UserObjectID = get-AzureAdUser -objectId $user.SamAccountName | Select-Object -Property objectID
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $($userObjectID.objectID)
if ($UserObjectID) {
foreach ($group in $UserObjectIDGroupMemberShip) {
try {
Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $SelectUserObjectID
[PSCustomObject]@{
User = $user.SamAccountName
Group = $group.Name
Status = 'Success'
}
}
catch {
[PSCustomObject]@{
User = $user.SamAccountName
Group = $group.Name
Status = 'Failed - {0}' -f $_
}
}
}
}
else {
[PSCustomObject]@{
User = $user.SamAccountName
Group = $NULL
Status = 'Failed - User not found.'
}
}
}
$results
After you have the results, you can do analysis paralysis with Where-Object and Group-Object
#Mock data
$results = @()
$results += [PSCustomObject]@{
User = 'User123'
Group = 'Group123'
Status = 'Success'
}
$results += [PSCustomObject]@{
User = 'User123'
Group = 'Group124'
Status = 'Failed - Permission Denied'
}
$results += [PSCustomObject]@{
User = 'User125'
Group = $null
Status = 'Failed - User Not Found.'
}
#Count by status
$results | Group-Object -Property Status
#Investigate failures
$results | Where{$_.Status -ne 'Success'}
#All failures grouped by user
$results | Where{$_.Status -ne 'Success'} | Group-Object -Property User
Output:
Count Name Group
----- ---- -----
1 Failed - Permission Deni… {@{User=User123; Group=Group124; Status=Failed - Permission Denied}}
1 Failed - User Not Found. {@{User=User125; Group=; Status=Failed - User Not Found.}}
1 Success {@{User=User123; Group=Group123; Status=Success}}
User : User123
Group : Group124
Status : Failed - Permission Denied
User : User125
Group :
Status : Failed - User Not Found.
1 User123 {@{User=User123; Group=Group124; Status=Failed - Permission Denied}}
1 User125 {@{User=User125; Group=; Status=Failed - User Not Found.}}
@Rob thanks for your help however when I run your version there is nothing that is removed I get these errors
[pre]
User Group Status
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
user1 Failed - Error occurred while executing RemoveGroupMember …
{@{User=User123; Group=Group123; Status=Success}}
{@{User=User123; Group=Group124; Status=Failed - Permission Denied}}
{@{User=User125; Group=; Status=Failed - User Not Found.}}
User123 Group124 Failed - Permission Denied
User125 Failed - User Not Found.
{@{User=User123; Group=Group124; Status=Failed - Permission Denied}}
{@{User=User125; Group=; Status=Failed - User Not Found.}}
[/pre]
when I run my version the groups do get removed correctly can it be that this has something to do with the PScustomobject?
It was a suggestion, not tested code. When you do a direct lookup on an Id, it either returns the object or fails, so it needs to be wrapped in a try\catch with the -ErrorAction set to stop. Tested the following:
$creds = Get-Credential -UserName 'rob.simmers@mycompany.com' -Message 'Enter your credentials'
Connect-AzureAD -Credential $creds
#Emulate CSV
$users = @()
$users += [pscustomobject]@{SamAccountName = 'rob.simmers@mycompany.com'}
$users += [pscustomobject]@{SamAccountName = 'dont.exist@mycompany.com'}
$users += [pscustomobject]@{SamAccountName = 'john.smith@mycompany.com'}
#$users = import-csv c:\temp\toRemove.csv
$results = foreach ($user in ($users | Select -ExpandProperty SamAccountName)) {
try {
$UserObjectID = get-AzureAdUser -objectId $user | Select-Object -Property objectID -ErrorAction Stop
$UserObjectIDGroupMemberShip = get-AzureAdUserMembership -objectID $($userObjectID.objectID)
foreach ($group in $UserObjectIDGroupMemberShip) {
try {
Remove-AzureADGroupMember -ObjectId $group.objectID -MemberId $UserObjectID -ErrorAction Stop
[PSCustomObject]@{
User = $user
Group = $group.DisplayName
Status = 'Success'
}
}
catch {
[PSCustomObject]@{
User = $user
Group = $group.DisplayName
Status = 'Failed - Group Removal. {0}' -f $_
}
}
}
}
catch {
[PSCustomObject]@{
User = $user
Group = $NULL
Status = 'Failed - User lookup. {0}' -f $_
}
}
}
$results
Output:
User Group Status
---- ----- ------
rob.simmers@mycompany.com Everyone Success
rob.simmers@mycompany.com All Company Success
rob.simmers@mycompany.com Strategic Vision Team Success
rob.simmers@mycompany.com Information Technology Success
dont.exist@mycompany.com Failed - User lookup. Error occurred while executing GetUser ...
john.smith@mycompany.com Everyone Success
john.smith@mycompany.com All Company Success
john.smith@mycompany.com Marketing & Sales Success
john.smith@mycompany.com Information Technology Success