I want to modify the below PowerShell cmdlet to create bulk DLs with its members and its aliases.
Using the two cmdlets below:
https://learn.microsoft.com/en-us/powershell/module/exchange/new-distributiongroup?view=exchange-ps
https://learn.microsoft.com/en-us/powershell/module/exchange/set-distributiongroup?view=exchange-ps
I've managed to create just one DL when executed with the snippets below:
$paramNewDistributionGroup = #{
Name = $_.DisplayName
Alias = $_.Alias
PrimarySmtpAddress = $_.PrimarySmtpAddress
DisplayName = $_.DisplayName
RequireSenderAuthenticationEnabled = $False
Members = $_.Members
}
New-DistributionGroup #paramNewDistributionGroup
$paramSetDistributionGroup = #{
Identity = $_.Alias
EmailAddresses = #{ Add = $_.SecondarySMTPAddress }
}
Set-DistributionGroup #paramSetDistributionGroup
How to modify the above script so it takes the .CSV file which looks like the below:
Using the suggested code from #mklement below, it throws an error due to the multi-value entries on the below columns:
SecondarySMTPAddress column:
Write-ErrorMessage : Cannot process argument transformation on
parameter 'EmailAddresses'. Cannot convert value
"System.Collections.Generic.Dictionary`2[System.String,System.Object]"
to type "Microsoft.Exchange.Data.ProxyAddressCollection". Error: "The
address 'Execs#domain.com; boss#domain.com ' is invalid: The address
'Execs#domain.com; boss#domain.com' isn't a valid Unified Messaging
address, so a prefix must be specified."
Members column:
Write-ErrorMessage :
Ex94914C|Microsoft.Exchange.Configuration.Tasks.ManagementObjectNotFoundException|Couldn't
find object " Cella Cat; Maria Aya; Heni Amor; Dio O'meara". Please
make sure that it was spelled correctly or specify a different object.
Assuming this is on-prem Exchange?
$DLs = Import-Csv -Path <filepath>
$DLS | % {
$paramNewDistributionGroup = #{
Name = $_.DisplayName
Alias = $_.Alias
PrimarySmtpAddress = $_.PrimarySmtpAddress
DisplayName = $_.DisplayName
RequireSenderAuthenticationEnabled = $False
Members = $_.Members
}
New-DistributionGroup #paramNewDistributionGroup
$paramSetDistributionGroup = #{
Identity = $_.Alias
EmailAddresses = #{ Add = $_.SecondarySMTPAddress }
}
Set-DistributionGroup #paramSetDistributionGroup
}
I'm also going to assume the members within your CSV file match one of these AD attributes:
Name
Alias
Distinguished name (DN)
Canonical DN
Email address
GUID
$AllMeetUsers = $null
[array]$AllMeetUsers = gam report meet user all | ConvertFrom-Csv | Select-Object 'actor.email','id.time'
[array]$result = $AllMeetUsers | ForEach-Object {
$Email = $_.'actor.email'
If (-not([string]::IsNullOrWhiteSpace($Email))) {
$IDTime = $_.'id.time'
$FormatIDTime = Get-date($IDTime) -Format("MM-dd-yy")
[PSCustomObject]#{
Email = $Email
Time = $FormatIDTime
}
}
}
Makes an output table like the following
06-07-21 <Email>
09-29-21 <Email>
06-15-21 <Email>
07-12-21 <Email>
07-20-21 <Email>
07-14-21 <Email>
I would like to remove the full duplicate email address line.
but this line is not working
[array]$result = $result | Sort-Object -Property email | Select-Object time,email -Unique
and
[array]$result = $result | Sort-Object -Property email | Select-Object email -Unique
removes the time field while giving me unique email addresses.
How do I accomplish this?
Use a Dictionnary #{} instead of an array.
$results = #{}
if (-not $results.ContainsKey($Email)) {
$results.Add($Email, [PSCustomObject]#{
Email = $Email
Time = $FormatIDTime
})
}
$results.Values
#MathiasR.Jessen made a good point in the comments and I think my code probably needs a conceptual change. However with the answer I accepted from #Hazrelle above this is how the code came out.
$AllMeetUsers = $null
[array]$AllMeetUsers = gam report meet user all | ConvertFrom-Csv | Select-Object 'actor.email','id.time'
$results = #{}
$AllMeetUsers | ForEach-Object {
$Email = $_.'actor.email'
if (-not $results.ContainsKey($Email) -and -not([string]::IsNullOrWhiteSpace($Email))) {
$IDTime = $_.'id.time'
$FormatIDTime = Get-date($IDTime) -Format("MM-dd-yy")
$results.Add($Email, [PSCustomObject]#{
Email = $Email
Time = $FormatIDTime
})
}
}
$results.values
For more information.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-7.1
I have a PS script retrieving all the devices from AD with their OU information like below:
$UserList = Get-ADComputer -Filter * -Property * | Select-Object Name,DistinguishedName,LastLogonDate
$Results = foreach ($UL_Item in $UserList)
{
[array]$OuList = #($UL_Item.DistinguishedName.Split(',')).
Where({$_ -match 'OU='}).
ForEach({$_.Split('=')[-1]}).
Trim()
[PSCustomObject]#{
ComputerName = $UL_Item.Name
OU_1 = $OuList[0]
OU_2 = $OuList[1]
OU_3 = $OuList[2]
OU_4 = $OuList[3]
OU_5 = $OuList[4]
}
}
What I would like to do is to add a flag called IsServer to my variable: $Results and set it to True if any of the OU is equal to "Domain Servers", so I am looking for the correct syntax for something like:
...
OU_5 = $OuList[4]
IsServer = if ($OuList[0]="Domain Servers" OR
$OuList[1]="Domain Servers" OR
$OuList[2]="Domain Servers" OR
$OuList[3]="Domain Servers" OR
$OuList[4]="Domain Servers" OR ) then true else false end
What is the best way to manage this? Any help would be appreciated.
You can do:
IsServer = #{$true="true";$false="false"}[($OuList -contains "Domain Servers"]
I'm writing a powershell script that will search active directory and give me info on users like this:
$fname = Read-Host 'Enter first name'
$lname = Read-Host 'Enter Last Name'
$search = [adsisearcher]"(&(ObjectCategory=Person)(ObjectClass=User)(givenName=$fname)(sn=$lname))"
$users = $search.FindAll()
foreach($user in $users) {
$displayname = $user.Properties['displayname']
"$displayname"
}
That will return a list of users who have the same first and last names:
User1
User2
User3
User4
I'd then like to be able to select which user I want to show further info on, something like this:
Read-Host 'Enter user number'
#input 1 - 4
#returns exchange server name for the selected user:
$msExchHomeServerName = $user.Properties['msExchHomeServerName']
"Exchange server: $msExchHomeServerName"
I can't figure out how to return a selectable list that lets me get further details on that user.
This works for me. I'm more familiar with PSCustomObjects, but you could do this as a hashtable instead, I'm sure (although I think hashtables get funny if you try and use an integer as a key).
And I'm sorry, I'm too lazy to refactor this with ADSI, but hopefully the logic is clear.
If you wanted to, you could return the user properties you might need with your initial LDAP query and add them to the [PSCustomObject] you're creating for each user. Then just pull the properties out of $usertable rather than doing another AD query. (See the second example.)
However, I'm really adamant that if it's more than a few properties for more than a few users, don't try and grab everything at once. I get really sick of lazy LDAP filters with -properties * when you only want one property. In my environment, if I get all the properties on just my account, it's 74 KB. That starts to add up quickly when dragging stuff out of LDAP.
# sort user list by desired attribute below e.g. samaccountname, lastname, etc
$users = get-aduser -filter 'name -like "macdo*"' | sort samaccountname
# create an array to store the user results
$usertable = #()
$no = 0
$users | foreach {
$no++
$o = [PSCustomObject]#{
No = $no
Name = $_.samaccountname
}
$usertable += $o
}
$usertable |sort no
# this is what the table will look like on screen
No Name
-- ----
1 AKMacDonald
2 AMacDonald
3 BMacDonald
4 BMacdonnell
$myint = Read-Host 'Enter user number'
> Enter user number: 29
# Select desired user properties in Get-ADUser below
$ADuser = $usertable | where {$_.no -eq $myin} |select -ExpandProperty Name |
Get-Aduser -Properties msExchHomeServerName
$ADuser
#AD user output
DistinguishedName : CN=BMacDonald,OU=Accounts,DC=example,DC=com
Enabled : False
GivenName : Bruce
Name : BMacDonald
...
If you're grabbing a few extra attributes with your initial AD query, you can store them in the $usertable for quick retrieval.
# grab msExchHomeServerName in this query
$users = get-aduser -filter 'name -like "macdo*"' -properties msExchHomeServerName |
sort samaccountname
# create an array to store the user results
$usertable = #()
$no = 0
$users | foreach {
$no++
$o = [PSCustomObject]#{
No = $no
Name = $_.samaccountname
Exchsrv= $_.msExchHomeServerName
}
$usertable += $o
}
# do a "select" below if you don't want to display everything in $usertable
$usertable |sort no
# $usertable contents
No Name Exchsrv
-- ---- ----
1 AKMacDonald Exch1
2 AMacDonald Exch1
3 BMacDonald Exch2
4 BMacdonnell Exch3
$myint = Read-Host 'Enter user number'
> Enter user number: 29
# Select desired user properties from $usertable
$usertable | where {$_.no -eq $myint} | Select Name,Exchsrv
# output
Name Exchsrv
---- ----
AKMacDonald Exch1
You have to specify the properties that you'd like to load for each user. [adsisearcher] is a type accelerator for DirectorySearcher, so try this:
$filter = "(&(ObjectCategory=Person)(ObjectClass=User)(givenName=$fname)(sn=$lname))"
$propsToLoad = #('displayname', 'msExchHomeServerName')
$search = [System.DirectoryServices.DirectorySearcher]::new($filter, $propsToLoad)
If you want to avoid user selection error, you can use the PromptForChoice method :
$fname = (Read-Host 'Enter first name').Trim()
$lname = (Read-Host 'Enter Last Name').Trim()
$filter = "(&(samAccountType=805306368)(givenName=$fname)(sn=$lname))"
$propsToLoad = #('displayname','samaccountname', 'mail', 'l', 'department', 'msExchHomeServerName')
$search = [System.DirectoryServices.DirectorySearcher]::new($filter, $propsToLoad)
$results=$search.FindAll()
$results[$Host.UI.PromptForChoice( "Choose the namesake you want to see",`
"Type the corresponding SamAccountName", ($results | ForEach-Object `
{ New-Object System.Management.Automation.Host.ChoiceDescription( `
$_.Properties.samaccountname, $_.Properties.department) }), 0)].Properties.Values
This shows you this once you have typed givenName and surName :
Enter first name: Justine
Enter Last Name: Noix
Choose the namesake you want to see
Type the corresponding SamAccountName
[] JNoix [] JuNoix [?] Aide (la valeur par défaut est « JNoix ») : junoix
JuNoix
Justine Noix
LDAP://CN=Justine Noix,OU=R&D,OU=Tests,DC=someDomain,DC=adds
Justine.Noix.RD#someDomain.adds
R&D
SomeCity
mailserver.someDomain.adds
if you type a wrong samAccountName, it re-asks again.
if you don't care about any help or have no department setted in AD, simply replace the last line by :
$results[$Host.UI.PromptForChoice( "Choose the namesake you want to see",`
"Type the corresponding SamAccountName", ($results | ForEach-Object `
{ New-Object System.Management.Automation.Host.ChoiceDescription( `
$_.Properties.samaccountname, "") }), 0)].Properties.Values
I have a powershell script to get deactivated accounts from our SSO app but would like to filter it down to only those that were deactivated more than 90 days ago.
I then have another script to take the results and deletes those users from the SSO app.
Can you tell me how to add a filter to the below script to exclude results were the StatusChanged date is greater than 90 days from current date.
$users = oktaListDeprovisionedUsers -oOrg PREV
$toexport = New-Object System.Collections.ArrayList
Foreach ($u in $users)
{
$line = #{
status = $u.status
employeeid = $u.profile.employeeNumber
firstName = $u.profile.firstName
lastName = $u.profile.lastName
email = $u.profile.email
department = $u.profile.department
supervisor = $u.profile.manager
created = $u.created
lastUpdated = $u.lastUpdated
login = $u.profile.login
title = $u.profile.title
GroupName = $u.profile.Group_Name
Organization = $u.profile.organization
Location = $u.profile.workday_location
User_type = $u.profile.userType
StatusChanged = $u.StatusChanged
}
$obj = New-Object psobject -Property $line
$_c = $toexport.Add($obj)
}
#Path for utility will have to be changed to a more generic location.
$toexport | Select-Object "login", "StatusChanged", "employeeid", "firstName","lastName", "email", "title","supervisor","department","Organization","Location", "GroupName" | >Export-Csv -Path "C:\OktaExport\user-list.csv" -NoTypeInformation
You can filter the $users object by a Where-Object
$users = $users | Where-Object{((Get-Date) - $_.StatusChanged).TotalDays -gt 90}
Add this to the 2nd line of your script.