Find if a user is part of some distribution lists - powershell

I want to get a script working in powershell which takes a user's email and look it up against a few distribution lists to see if the user is a part of any of them. It should also check the nested distribution groups if any under the main distribution lists.
here's what I have but can't get it to work. Any help would be appreciated, I am fairly new to this.
# Prompt for user email address
$UserEmail = Read-Host -Prompt 'Please enter the user email address'
# Read the CSV file
$DistributionLists = Import-Csv -Path '.\DLs.csv'
# Loop through each Distribution List
foreach ($DL in $DistributionLists) {
# Get List of Distribution Group Members
$GroupMembers = Get-DistributionGroupMember -Identity $DL -ResultSize Unlimited
# Loop through each member
foreach ($Member in $GroupMembers) {
# Check if the user's email address matches
if ($Member.PrimarySmtpAddress -eq $UserEmail) {
# Output the matches
Write-Output "User $UserEmail is a part of $($DL.Name)"
}
}
}
but i get below error on execution:
Write-ErrorMessage : Cannot process argument transformation on parameter 'Identity'. Cannot convert value "" to type
"Microsoft.Exchange.Configuration.Tasks.DistributionGroupMemberIdParameter". Error: "Parameter values of type Microsoft.Exchange.Configuration.Tasks.DistributionGroupMemberIdParameter can't be empty. Specify a value, and try again.
Parameter name: identity"
At C:\Users\abcd\AppData\Local\Temp\tmpA_hrt0empv.vlz\tmpA_hrt0empv.vlz.psm1:1087 char:13
+ Write-ErrorMessage $ErrorObject
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-DistributionGroupMember], ParameterTransformationException
+ FullyQualifiedErrorId : [Server=BNxxxxxx5601,RequestId=abcdef5-1e51-d5f0-2a56-77b30f23bf3a,TimeStamp=Thu, 09 Feb 2023 14:04:01 GMT],Write-ErrorMessage
Error screenshot

The error statement informs us "-Identify $DL" is empty; $DL returns the entire object row and not just the name to be matched. To correct, refactor to $DL.DistributionLists where "DistributionLists" is the column header in the imported CSV file.
As we confirmed together you have already imported ExchangeOnlineManagement and made the connected to Exchange Online.... I've kept these in the code below for future reader reference.
# Pearl-script below:
# Import the ExchangeOnlineManagement module
Import-Module ExchangeOnlineManagement
# Connect to Exchange Online
Connect-ExchangeOnline
# Prompt for user email address
$UserEmail = Read-Host -Prompt 'Please enter the user email address'
# Read the CSV file
$DistributionLists = Import-Csv -Path '.\DLs.csv'
# Loop through each Distribution List
foreach ($DL in $DistributionLists) {
# Get List of Distribution Group Members
$GroupMembers = Get-DistributionGroupMember -Identity $DL.DistributionLists -ResultSize Unlimited
# Loop through each member
foreach ($Member in $GroupMembers) {
# Check if the user's email address matches
if ($Member.PrimarySmtpAddress -eq $UserEmail) {
# Output the matches
Write-Output "User $UserEmail is a part of $($DL.DistributionLists)"
}
}
}

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.

How to get Powershell to prompt for input parameter

I am fairly new to PowerShell. There is a command I run many times a day that checks if an AD user account belongs to a couple of AD security groups. Right now, I am pasting the user's account into the command from OneNote and then pasting that command into the PowerShell window. Ideally, I would love to be able to run a .ps1 file that would launch a popup where I could enter in the user's account and the popup would then provide the command output. If that is not possible, run the .ps1 file and have the PowerShell ask for input where I can paste the user's AD account and hit enter. Below is the command I am running. Thank you all in advance.
(Get-ADUser %ADACCOUNT% -Properties MemberOf).MemberOf | findstr /i %ADGROUP%
Here is an idea to get you started using InputBox function to get the input user, MessageBox.Show method in case the user was not part of any group and Out-GridView in case the user was member of at least one of the groups.
Usage is quite simple, you just name this script as whatever you want and then when calling it, you can do .\myScript.ps1 -ADGroups 'somegroup1', 'somegroup2', etc
param([string[]] $ADGroups)
Add-Type -AssemblyName Microsoft.VisualBasic, System.Windows.Forms
# Get user input
$choice = [Microsoft.VisualBasic.Interaction]::InputBox(
'Input User SamAccountName',
'Choose a Title for me'
)
# if the user didn't provide any input, exit script
if([string]::IsNullOrWhiteSpace($choice)) {
return
}
# get user membership and filter
$result = (Get-ADUser $choice -Properties memberOf).memberOf | Where-Object {
# where the DistinguishedName matches any of input AD Groups
foreach($group in $ADGroups) {
if($_ -match $group) { return $true }
}
}
# if no results found
if(-not $result) {
# show this message
[Windows.Forms.MessageBox]::Show(
"$choice was not a member of any AD Group",
'Choose a Title for me',
[Windows.Forms.MessageBoxButtons]::OK,
[Windows.Forms.MessageBoxIcon]::Warning
)
# and exit the script
return
}
# otherwise, show this grid that contains the list of DistinguishedNames
# the user is a member of
$result | Out-GridView

Move multiple users to multiple OUs importing users from CSV and filtering by Active Directory "Office" attribute using Wildcard lookups

I'm trying to move users from an onboarding CSV file to several different OUs after the account creation but I'm having issues with the syntax. Is it possible to use a wildcard lookup for a certain keyword such as "Remote" on the users Active Directory office attribute? Below is a snippet of the code.
$map = #{
'China' = "China OU DistinguishedName"
'Russia' = "Russia OU DistinguishedName"
'US - Miami' = "Miami OU DistinguishedName"
'US - Tampa' = "Tampa OU DistinguishedName"
'US - Reno' = "Reno OU DistinguishedName"
'US - Charleston' = "Charleston OU DistinguishedName"
}
foreach($line in Import-Csv "C:\Test\Test Files\AD_Test.csv") {
$firstname = $line.'Legal First Name'.Trim()
$preferred_firstname = $line.'Preferred First Name'.Trim()
if($preferred_firstname){
$firstname = $preferred_firstname
}
$lastname = $line.'Last Name'.Trim()
$displayname = $firstname + " " + $lastname
$param = #{
# create a filter for this user
# try to find him either by CommonName OR SamAccountName OR DisplayName
LDAPFilter = "(|(cn=$displayName)(samAccountName=$displayName)(displayName=$displayName))"
Properties = "Office"
}
# if the user can be found in AD
if($user = Get-ADUser #param) {
# if the user's Office cannot be found in `$map`
if(-not $map.ContainsKey($user.Office)) {
Write-Warning "Office for '$displayName' could not be determined, skipping."
# go to next line in Csv
continue
}
# if the user's Office can be found in `$map`, move it to the destination OU
$user | Move-ADObject -TargetPath $map[$user.Office]
# and after moving it, skip below logic, go next
continue
}
# if the user could not be found in AD
Write-Warning "'$displayName' could not be found in AD."
}
As explained in previous answer, the hash table should be used for exact lookups, however you can still use it, but you would need to add more conditions in case the value for Office of the users couldn't be found in $map. For this you can use a switch to evaluate multiple conditions.
To understand the use of the :outer label, see about_Continue.
$map = #{
# stays as-is, only exact values here
}
# set `outer` label for this loop
:outer foreach($line in Import-Csv "C:\AD_Test.csv") {
# `$displayname` and `$param` code stays as-is here
# if the user could not be found in AD
if(-not ($user = Get-ADUser #param)) {
# display the warning
Write-Warning "'$displayName' could not be found in AD."
# and skip next logic
continue
}
# if the user can be found in AD, switch on `$user.Office`
$destination = switch($user.Office) {
# if the value is found on `$map` hashtable
# get the destination OU, and break the switch loop
{ $map.ContainsKey($_) } { $map[$_]; break }
# if the value contains "Remote", output this OU and break the loop
{ $_ -like "*Remote*" } { 'OU=Remote Here,DC=DOMAIN,DC=com'; break }
# if above conditions were `$false`, the Default action is
# display the warning message and go to next line of Csv
Default {
Write-Warning "Office for '$displayName' could not be determined, skipping."
continue outer
}
}
# if we are here, we can assume `$destination` is populated
# hence we can move the user
$user | Move-ADObject -TargetPath $destination -WhatIf
}

How to automate removing Exchange Contacts in Office365

I am writing a powershell script that:
Compares two CSV files
Output files for: Changes, added, removed contacts
Update and add contacts
Remove contacts
The problem is when I try and removed contacts. Which is done by:
#Check for Removed Contacts
foreach($row in $File1_Data )
{
$data_found=0
foreach($id in $emails_id)
{
if ($row.ExternalEmailAddress -eq $id)
{
$data_found=1
}
}
if($data_found -eq 0 ) #Email Not Found
{ $row|Select-Object -Property ExternalEmailAddress|Export-Csv -Path $Removed_Contact -Append -NoTypeInformation}
}
Now I have a file with only the email addresses. The error comes when I try and run the command connected on the exchange server.
$RemoveContacts = Import-CSV ".\Removed Contacts_$((Get-Date).ToString('MMddyyyy')).csv"
$RemoveContacts | ForEach { Remove-MailContact -identity $_ -confirm:$false}
But I get the following error:
Cannot process argument transformation on parameter 'Identity'. Cannot convert the
"#{ExternalEmailAddress=testuser#testcompany.com}" value of type "Deserialized.System.Management.Automation.PSCustomObject"
to type "Microsoft.Exchange.Configuration.Tasks.MailContactIdParameter".
+ CategoryInfo : InvalidData: (:) [Remove-MailContact], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Remove-MailContact
+ PSComputerName : outlook.office365.com
$File_Data structure is in the format Microsoft requires.
and
$emails_id is the function that compares the two csv files. But that's not where the script breaks, that's just how i create the file.
What am I missing?
The error message is telling you that it can't convert the value of $_ to what it needs for -Identity parameter. Generally the -Identity parameter for most PS commandlets is going to be the human readable unique name of something. In this case, it would be an email address. With that said the error message is telling you that instead of $_ containing the string version of an email address, it contains a hash or dictionary object that contains a single property, ExternalEmailAddress.
So to make this work, change your $_ to $_.ExternalEmailAddress and now the call to Remove-MailContact will use the value of the ExternalEmailAddress property of the object in your ForEach loop.

Line break issue when configuring "send on behalf of"

I have a script to set send on behalf of permissions in Exchange Management Shell, but when you try and use it it fails because the output of the first part is too long and truncates over 2 lines.
First thing we do is build our array from lists of people and put them into some variables to pass:
function Add-Send ($mailbox, $target) {
#"Granting send on behalf for $mailbox to $target"
Set-Mailbox -Identity $mailbox -GrantSendOnBehalfTo #{ Add = $target }
}
We pass a long list as the $target and the maibox name is $mailbox and if we output the text we get:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson" }
All fine and good but if there are more than N characters in the output then we get a line break:
Set-Mailbox -Identity "mr.jeff" -GrantSendOnBehalfTo #{ Add = "alan.alanson", "bob.bobson", "steve.stevenson", ...
..., "cath.cathdotir" }
When you run this script with the overlength output, then command fails as the output which should be passed to the CLI is passed over more than one line. PowerShell treats each line as a separate command, and they obviously fail with bad syntax.
Our string is output from an array that we build like this:
function Send-Array ($mailbox) {
$target = Get-Content ".\list\dpt1.txt"
$target += Get-Content ".\list\$mailbox.txt"
$target += Get-Content ".\list\dpt2.txt"
$target = $target | Select-Object -Unique
$separator = '", "'
$target= $target -replace '^|$','"' -join ','
Add-Send $mailbox $target
}
This gives us an array with strings that look like:
"alan.alanson", "bob.bobson", "steve.stevenson"
From here I am at a loss any ideas would be much appreciated.
The obvious solution would be to pass the names one at a time, but due to a gotcha with Exchange Server every time you set send on behalf of permissions with PowerShell it wipes the existing permissions, so you only end up with he last person granted permissions being able to send on behalf of.
See this link for help with your underlying issue.
Very basically, you will have to:
get the DistinguishedName of the user you need to add
store the current value of GrantSendOnBehalfTo in a variable
append the new user's distinguished name to the list
replace GrantSendOnBehalfTo with the new list
Afterwards you should not need to pass endless strings to the EMS (I hope so).