Exception Handling with AD PowerShell - powershell

I am building a PowerShell script to create AD Groups (Global and DomainLocal) by Importing their names from a Csv file.
I am having a hard time handling exceptions that will be generated in case Groups already exist.
What I want to achieve is if the Groups do not exist by the name in Csv then PS should create them and show message "Groups have been created" and if they already exist then it should display "Groups already exist" line by line so that if one exists and the other one doesn't then it should display the corresponding message.
What is happening is that PS doesn't display a message when it has created groups and when exception does occur it displays message only for Global Group not Local.
Please advise
Here's the code -
Try {
New-ADGroup -Name TestGlobal -GroupCategory Security -GroupScope Global -ManagedBy TEMP01 -Description "Owner is TEMP01" -Path (Some OU)
} Catch [Microsoft.ActiveDirectory.Management.ADException] {
if ($_ -like "The specified group already exists") {
Write-Host “!!! GLOBAL GROUP ALREADY EXISTS !!!”
} elseif ($_ -eq $null) {
Write-Host " GLOBAL GROUP CREATED SUCCESSFULLY "
}
}
Try {
New-ADGroup -Name TestLocal -GroupCategory Security -GroupScope DomainLocal -ManagedBy TEMP02 -Description "Owner is TEMP02" -Path (Some OU)
} Catch [Microsoft.ActiveDirectory.Management.ADException] {
if ($_ -like "The specified group already exists") {
Write-Host “!!! LOCAL GROUP ALREADY EXISTS !!!”
} elseif ($_ -eq $null) {
Write-Host " LOCAL GROUP CREATED SUCCESSFULLY "
}
}

PowerShell is a bit strange in that, by default, errors are non-terminating. That means that errors will be output to the console, but it will just continue on to the next line of code as if nothing happened.
Unfortunately, Try blocks only respond to terminating errors.
You can change this behaviour. On both of your New-ADGroup lines, add this to the end:
-ErrorAction Stop
That will tell PowerShell that you want it to treat errors on that line as terminating.
If you want, you can do some more reading about it here:
https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/09/handling-errors-the-powershell-way/
https://blogs.technet.microsoft.com/heyscriptingguy/2014/07/05/weekend-scripter-using-try-catch-finally-blocks-for-powershell-error-handling/

Related

Using multiple if statemens in foreach loop

In this script, I am trying to make a group (if not exist) and add users thats are not already in the group.
But the problem is he only takes the first if statement I think, because it don't seems like he is taking the next statements in the loop.
#Tweede test met if
$teams = #Here comes the csv file.
Foreach($team in $teams)
{
$Test = (Get-UnifiedGroup $team.DisplayName)
if (Get-UnifiedGroup $team.DisplayName)
{
Write-Host -ForegroundColor Green "$($team.Displayname) already exists!"
}
elseif ($Test -eq "false")
{
$Group = New-UnifiedGroup -DisplayName $team.DisplayName -Alias $team.Alias -AccessType $team.AccessType
}
foreach($Member in $Members)
{
elseif (get-UnifiedgroepLinks $team.Links)
{
write-host -ForegroundColor Green "$($team.Links) already exists!"
}
else
{
Add-UnifiedGroupLinks -Identity $team.Identity -LinkType $team.Linktype -Links $team.Links
}
}}
OK so this is my current output form #Theo last improvement
Output
OK I have something very interesting, because when I looked at the output of
$existingMembers = #((Get-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Members).PrimarySMTPAddress)
I will get certain blank spots. And when I ran the script for one user it was working but for another one it did not, so I looked at the user that did not worked, and he does not have a license. So I tested it further. And in my conclusion now it's working. So when an acc is unlicensed, it is not seen like he is added to that specific group. So he is also throwing the second if statement, but also the second else statement.
Does this make sense to you #Theo?
### script name: Users_Verwijderen ###
### Datum updated: 14-12-2022 ###
### Auteur: Wessel Rouw ###
### Purpose script is to add groups and users in to groups in Azure. ###
#######################################################################
$teams = import-csv #Here your CSV
foreach($team in $teams) {
$team | Format-Table
$Check = (Get-UnifiedgroupLinks -Identity $team.Identity -LinkType $team.Linktype)
$existingMembers = #((Get-UnifiedGroupLinks -Identity $Group.DistinguishedName -LinkType Members).PrimarySMTPAddress)
$Group = (Get-UnifiedGroup $team.DisplayName)
if ($Group)
{
Write-Host "$($team.Displayname) already exists!" -ForegroundColor Green
}
else
{
Write-Host "Creating group $($team.Displayname)"
$Group = New-UnifiedGroup -DisplayName $team.DisplayName -Alias $team.Alias -AccessType $team.AccessType
}
if ($existingMembers -contains $team.Links)
{
Write-Host "$($team.Links) already exists!" -ForegroundColor Green
}
else
{
Write-Host "Creating group Links $($team.Links)"
Add-UnifiedGroupLinks -Identity $team.Identity -LinkType $team.Linktype -Links $team.Links
}
}
This is now my current script working with help from #Theo (Only, users that are not licensed will get the message that they are added even if they are already in the group).
Here is my input now in my csv.
I have changed username (Links) and the domain name (After the Test101 and the users (Links).
DisplayName,Alias,AccessType,Identity,Linktype,Links
Test101,Test101,private,Test101#domain.nl,Member,Hek_Sme#Domain.nl
Test101,Test101,private,Test101#domain.nl,Member,Mek_Lei#Domain.nl
Test101,Test101,private,Test101#domain.nl,Member,Wek_Bog#Domain.nl
This is another very helpful output. again same story as above with the changed domain and usernames.
Name DisplayName GroupType PrimarySmtpA
ddress
---- ----------- --------- ------------
Test101_(**Here comes a private number)** Test101 Universal Test101#1...
PS C:\WINDOWS\system32> $existingMembers
**Here comes the domain admin**
Hek_Sme#Domain.nl
Gek_Wel#Domain.nl
Gek_Wel#Domain.nl
Dir_Bog#Domain.nl
Wek_Bog#Domain.nl
PS C:\WINDOWS\system32> $inputMembers
Mek_Lei#Domain.nl
PS C:\WINDOWS\system32>
And as you can see some fields are empty and that are exactly the two users who don't own a licence and when I then run the command to get everyone who is not presenting in the get commando of users for that group it is specified to that users again.
I only don't know why this and if my thought is right?
Oke, so thanks already for the help. Now it works better. But in the second part I want to verify that if a user already exists in azure it displays the message, but if don't it has to be added? But this is now the problem.
This is now the output of my running script
VERBOSE: Returning precomputed version info: 3.0.0
VERBOSE: POST with -1-byte payload
VERBOSE: received 2945-byte response of content type application/json;charset=utf-8
VERBOSE: Returning precomputed version info: 3.0.0
VERBOSE: POST with -1-byte payload
VERBOSE: received 2906-byte response of content type application/json;charset=utf-8
Test105 already exists!
Creating group Links #Here stand the email (Links)
VERBOSE: Returning precomputed version info: 3.0.0
VERBOSE: POST with -1-byte payload
VERBOSE: received 386-byte response of content type application/json;charset=utf-8
The problem is when a user already exist it does not goes to the line that says that it already exits but instead it skips this part i think and goed directy to the else statement.
I think I am pretty close now.
`$teams = import-csv #CSV here
{
#$team | Format-Table #This was voor debugging
$Check = (Get-UnifiedgroupLinks -Identity $team.Identity -LinkType $team.Linktype)
$Group = (Get-UnifiedGroup $team.DisplayName)
if ($Group)
{
Write-Host "$($team.Displayname) already exists!" -ForegroundColor Green
}
else
{
Write-Host "Creating group $($team.Displayname)"
$Group = New-UnifiedGroup -DisplayName $team.DisplayName -Alias $team.Alias -AccessType $team.AccessType
}
if ($Check -contains $team.Links)
{
Write-Host "$($team.Links) already exists!" -ForegroundColor Green
}
else
{
Write-Host "Creating group Links $($team.Links)"
Add-UnifiedGroupLinks -Identity $team.Identity -LinkType $team.Linktype -Links $team.Links
}
}`
These are the columns of my csv.

Powershell try/catch/finally isn't executing right (or I've completely hosed it)

I have a script that checks for cyclic groups.
The script takes all groups in a domain (parent groups), checks the membership of those groups and adds any member with an objectClass of 'group' to an array (child groups).
The script then checks the child groups to see if the parent is a member of the child (yeah, it's allowed but still not a good idea).
I added a try/catch/finally block so I could get the actual group names instead of the truncated error message that PowerShell returns.
The problem is, the script stops at the first error it encounters instead of continuing on.
This is the first try/catch I've done, so please bear with me.
Here's the script:
$original_ErrorActionPreference = 'Continue'
$ErrorActionPreference = 'Stop'
Import-Module -Name ActiveDirectory
$domains = #('corp.com', 'dom1.corp.com', 'dom2.corp.com')
foreach($domain in $domains){
Write-Host $domain -ForegroundColor Yellow
$parents = Get-ADGroup -server $domain -Properties name,objectclass -Filter * #get all domain groups
write-host $parents.count
$table = #()
$pGroupCount = #($parents).Count
$record = #{
'Parent' = ''
'Child' = ''
'Nester' = ''
}
foreach($parent in $parents){
Write-Host $parent.name -ForegroundColor Green
The script works up to this point.
This is the part that fails-
try { #get members in the parent that are groups
$children = Get-ADGroupMember -Identity $parent | Where-Object{$_.ObjectClass -eq 'group'} | Select-Object name,distinguishedName,objectClass
} catch [Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember]{
Write-Host $parent.name ' must be checked manually' -ForegroundColor blue -BackgroundColor Yellow
$parent.distinguishedName | Out-String -Width 4096 | Out-File -FilePath "$env:USERPROFILE\desktop\$domain-manualCheck.txt" -Width 5120 -Append
} finally {
$pGroupCount = $pGroupCount - 1
write-host $children.count ' - ' $children.name -ForegroundColor Gray
Write-Host $pGroupCount ' groups to go' -foregroundColor yellow
foreach($child in $children){ #get members in the children that are groups AND that have the same name as the parent
$nested = Get-ADGroupMember $child.name | Where-Object {$_.objectClass -eq 'group' -and $_.name -eq $parent.name}
$nestedCount = #($nested).count
if ($nestedCount -gt 0){
foreach($nester in $nested){
Write-Host $parent.name -ForegroundColor White
Write-Host $nestedCount -ForegroundColor Magenta
Write-Host $nester.name -ForegroundColor Cyan
$record.'Parent' = $parent.name
$record.'Child' = $child.name
$record.'Nester' = $nester.name
$objRecord = New-Object psobject -Property $record
$table += $objRecord
}
}
}
$table | Export-Csv -Path "$env:USERPROFILE\desktop\$domain-Group-Report.csv" -NoTypeInformation
$error | out-string -width 4096 | Out-File -FilePath "$env:USERPROFILE\desktop\$domain-Errors.txt" -Width 5120 -Append
}
}
}
$ErrorActionPreference = $original_ErrorActionPreference
As soon as the script hits the first group that has an issue, this is the error that's returned (#comments are added):
PS C:\Users\admin_j\Desktop> .\gtest.ps1
corp.com #current domain
283 #total group count
Exchange Servers #current group
6 - Exchange Install Domain Servers Exchange Install Domain Servers Exchange Install Domain Servers Exchange Install Domain Servers Exchange Install Domain Servers #6 groups within the parent, groups are from sub-domains
Exchange Install Domain Servers
282 groups to go
Get-ADGroupMember : Cannot find an object with identity: 'Exchange Install Domain Servers' under: 'DC=corp,DC=com'.
At C:\Users\admin_j\Desktop\gtest.ps1:46 char:15
+ $nested = Get-ADGroupMember $child.name | Where-Object $_.objectClass -eq ' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Exchange Install Domain Servers:ADGroup) [Get-ADGroupMember], ADIdentityNotFoundException
+ FullyQualifiedErrorId : Cannot find an object with identity: 'Exchange Install Domain Servers' under: 'DC=corp,DC=com'.,Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember
Why, instead of writing the bad group (in this case 'Exchange Install Domain Servers' under: 'DC=corp,DC=com'.) to a file, did the script stop? The group does indeed exist.
Should I add another block to catch any 'object not found' errors and send those to a file?
Thank you!
As Will's comment implies, you have indeed hosed your catch clause by specifying a type literal not matching an exception you'd ever expect thrown.
The general syntax for a catch clause is as follows
catch [catch-type-list] <statement block>
Where [catch-type-list] is an optional list of exception types that the associated statement block will act as an exception handler for.
That means, that this catch clause:
catch [Microsoft.ActiveDirectory.Management.Commands.GetADGroupMem‌​ber] {
# ...
}
Will only ever handle errors caused by an exception of the type [Microsoft.ActiveDirectory.Management.Commands.GetADGroupMem‌​ber] - this is of course not an exception type, and so the associated statement block will never execute.
In order for your catch clause to make sense in this context, specify a relevant exception type:
try{
Get-ADGroupMember -Identity $parent
}
catch [Microsoft.ActiveDirectory.Management.ADServerDownException]{
# DC is unreachable, abort
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityResolutionException]{
# Group identity not resolved, add to list and continue
}
catch {
# Something else, completely unforeseen, happened, you might want to re-throw and return from your function
}
The last catch clause, in which the type list has been omitted is known as a general catch clause, and will handle any exception that didn't match any of the preceding catch clauses.

Catch error and restart the if statement

I have a powershell script that adds a computer to a domain. Sometimes, when I run the script I get the following error and when I run it for the second time it works.
How can I make the script to check if I get this error, and if so then to retry adding it to the domain?
I have read that it is hard to try and catch errors like that. Is that correct? Is there a better/different way to catch the error?
Thank you!
Code:
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
Add-Computer -DomainName my-domain.local | out-null
} else {...}
Error:
This command cannot be executed on target computer('computer-name') due to following error: The specified domain either does not exist or could not be contacted.
You can use the built in $Error variable. Clear it before executing code, then test if the count is gt 0 for post error code.
$Error.Clear()
Add-Computer -DomainName my-domain.local | out-null
if($Error.count -gt 0){
Start-Sleep -seconds 5
Add-Computer -DomainName my-domain.local | out-null}
}
You could setup a function to call itself on the Catch. Something like:
function Add-ComputerToAD{
Param([String]$Domain="my-domain.local")
Try{
Add-Computer -DomainName $Domain | out-null
}
Catch{
Add-ComputerToAD
}
}
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
Add-ComputerToAD
} else {...}
I haven't tried it to be honest, but I don't see why it wouldn't work. It is not specific to that error, so it'll infinitely loop on repeating errors (i.e. another computer with the same name exists in AD already, or you specify an invalid domain name).
Otherwise you could use a While loop. Something like
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
While($Error[0].Exception -match "The specified domain either does not exist or could not be contacted"){
Add-Computer -DomainName my-domain.local | out-null
}
}

Suppress Exception in Office365 powershell

I have a script which adds members of an Active Directory group to an Office 365 distribution group. Many members of the AD group will also be members of the distribution group already, which causes the script to display the error:
Adding user#domain.com to distribution group GROUP
The recipient "user#domain.com" is already a member of the group "GROUP".
+ CategoryInfo : NotSpecified: (user#domain.com:RecipientWithAdUserGroupIdParameter`1)
[Add-DistributionGroupMember], MemberAlreadyExistsException
+ FullyQualifiedErrorId : [Server=HKNPR04MB0531,RequestId=84dc77fb-8cf4-4e2f-882e-0ce66b735d08,TimeStamp=9/02/2015 6:55:13 AM] [FailureCategory=Cmdlet-MemberAlreadyExistsException] 7CEFF683,Microsoft.Exchange.Management.RecipientTasks.AddDistributionGroupMember
+ PSComputerName : pod51055psh.outlook.com
I would like to suppress these errors, as I don't care if the members already exist.
I have tried catching the MemberAlreadyExistsException, setting -ErrorAction SilentlyContinue and catching all errors and writing "Error!" instead of the actual exception, however this does not seem to have taken effect.
Currently, my Try-Catch block looks like this:
try
{
Add-DistributionGroupMember -Identity $DistributionGroupName -Member $MemberEmail
}
Catch [System.Management.Automation.RemoteException]
{
if($_.FullyQualifiedErrorId -match 'AlreadyExists')
{
Write-Output "`t $emailaddress is already a member of $DistributionGroupName."
}
else
{
Write-Output "`t $_.Exception"
}
}
I believe that this should alert me when a user already exists, however I still receive an exception message.
Thanks to #mjolinor, I was able to catch the exception and provide a more user-friendly message. My corrected code is below:
try
{
Add-DistributionGroupMember -Identity $DistributionGroupName -Member $EmailAddress -ErrorAction Stop
}
Catch [System.Exception]
{
if($_.FullyQualifiedErrorId -match 'AlreadyExists')
{
Write-Output "`t $emailaddress is already a member of $DistributionGroupName."
}
else
{
Write-Output "`t $_.Exception"
}
}
I added the -ErrorAction Stop as suggested, which allowed me to Catch the exception. I also modified the exception type to catch all exceptions. Interestingly (in my opinion), the Catch block failed if I did not put an exception type in there.
Program output is now:
Adding user#domain.com to distribution group GROUP
user#domain.com is already a member of GROUP.

Checking if Distribution Group Exists in Powershell

I am writing a script to quickly create a new distribution group and populate it with a CSV. I am having trouble testing to see if the group name already exists.
If I do a get-distributiongroup -id $NewGroupName and it does not exist I get an exception, which is what I expect to happen. If the group does exist then it lists the group, which is also what I expect. However, I can not find a good way to test if the group exists before I try to create it. I have tried using a try/catch, and also doing this:
Get-DistributionGroup -id $NewGroupName -ErrorAction "Stop"
which makes the try/catch work better (as I understand non-terminating errors).
Basically, I need to have the user enter a new group name to check if it is viable. If so, then the group gets created, if not it should prompt the user to enter another name.
You can use SilentlyContinue erroraction so that no exception/error shows:
$done = $false
while(-not $done)
{
$newGroupName = Read-Host "Enter group name"
$existingGroup = Get-DistributionGroup -Id $newGroupName -ErrorAction 'SilentlyContinue'
if(-not $existingGroup)
{
# create distribution group here
$done = $true
}
else
{
Write-Host "Group already exists"
}
}
This should do the trick:
((Get-DistributionGroup $NewGroupName -ErrorAction 'SilentlyContinue').IsValid) -eq $true