Using multiple if statemens in foreach loop - powershell

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.

Related

Powershell script providing false positives (Exchange Online)

I seem to be coming across issues with a check i have put in place to confirm a mailbox has ben converted from a users mailbox to shared mailbox.
Connect-ExchangeOnline -UserPrincipalName $UserCredential.UserName
Write-Host "checking mailbox has converted to a shared mailbox...."
$Mailboxcheck = Get-Mailbox "$username" | select isshared
if ($Mailboxcheck.IsShared -eq $False) {
[System.Windows.MessageBox]::Show("Mailbox for $($username) has NOT been converted to shared, please confirm.")
} else {
[System.Windows.MessageBox]::Show("Mailbox for $($username) has been converted to shared.")
}
the issue is sometimes this check will work and other times it won't (randomly). So we convert the mailbox to a shared mailbox via the above script then the check will sometimes come up as the $False message rather then the else message but when we go to manually check it after it's run the mailbox has been converted to shared.
The only things i can think of is to add the disconnect and reconnect to exchange online in case it's due to some syncing time, Possibly add a Start-sleep to the script to give it more time to sync, or its to do with the if statement and the variable $false as $mailboxcheck.isshared should only provide a value of "True" or "False"
if ($Mailboxcheck.IsShared -eq $False)
Another way i have made the script to check is with a switch statement but am unsure if that will be me any benefit and unsure if it's the right use case or should stick to the if statement
$Mailboxcheck = Get-Mailbox "$username" | select isshared
switch ($Mailboxcheck.isshared)
{
True {[System.Windows.MessageBox]::Show("Mailbox for $($username) has been converted to shared."); Break}
False {[System.Windows.MessageBox]::Show("Mailbox for $($username) has NOT been converted to shared, please confirm."); Break}
default {[System.Windows.MessageBox]::Show("Unable to check mailbox type for $($username). Please confirm it has been converted to shared.")}
}
Let me know your thoughts.
Try running this code along side the other one to see when the IsShared property actually changes:
$repeat = $true
do
{
$Mailboxcheck = Get-Mailbox "$username"
Write-Host "Date = $(get-date)" -for Green
write-host "RecipientTypeDetails = $($Mailboxcheck.RecipientTypeDetails)" -ForegroundColor Cyan
write-host "IsShared = $($Mailboxcheck.isShared)" -ForegroundColor yellow
""
sleep 10
}
while ($repeat -eq $true)

Creating Local Group and Adding A User To The Group

I have a PowerShell script that builds IIS sites and configures settings. Most of it works as expected except for a function to either add a domain user to a specific local group or if the group is not there to create the group than add the user. I get this error when adding to the group:
Exception calling "add" with "1" argument(s): "A member could not be added to or removed from the local group because the member does not exist.
I have PowerShell v1.0 so I do not have access to the Microsoft.PowerShell.LocalAccounts module so using Add-LocalGroupMember and New-LocalGroup are not an option.
function addEventLogWriter($appPoolUser) {
$user = $appPoolUser
$group = "Event Log Writers"
$description = "Members of this group can write event logs from local machine"
#try{
$groupObj =[ADSI]"WinNT://./$group,group"
$membersObj = #($groupObj.psbase.Invoke("Members"))
$members = ($membersObj | foreach {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
})
Write-Output "Adding Service Account To Event Log Writers..."
if ($members -contains $user) {
Write-Host "$user already exists in the group $group..."
} else {
$groupObj.add("WinNT://./$user,user")
Write-Output "$user added to $group"
}
}
At the moment the group 'Event Log Writers' has been created but in the case it is not (ie: new server builds etc..), I would like my function check to make sure the group is there, if not, create the group than add the user.
The issue is because ADSI requires a slash instead of a backslash like a typical username.
Also, how the group membership returns, in this case, it drops the domain name, so we have to split out the username when seeing if it exists.
So if your $appPoolUser is a credential object with the full username:
function addEventLogWriter($appPoolUser) {
$AdsiUsername = $appPoolUser.replace('\','/')
$user = $appPoolUser.Split('\')[1]
$group = "Event Log Writers"
$description = "Members of this group can write event logs from local machine"
#try{
$groupObj =[ADSI]"WinNT://./$group,group"
$membersObj = #($groupObj.psbase.Invoke("Members"))
$members = ($membersObj | foreach {
$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
})
Write-Output "Adding Service Account To Event Log Writers..."
if ($members -contains $user) {
Write-Host "$user already exists in the group $group..."
} else {
$groupObj.add("WinNT://./$AdsiUsername,user")
Write-Output "$user added to $group"
}
}

Exception Handling with AD 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/

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.

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