Powershell: Extract Exchange property and Display in array - powershell

I need to get all Exchange users into an Array, with a column for their SIP address and another column for all SMTP addresses (as seen in the EmailAddresses field).
So for now I am trying this against a single user and should that work out I can use "-ResultSize Unlimited" and do all. Although for now:
$list_UsersExtCloud =
Get-Recipient e12367 |
Select-Object Alias, EmailAddresses, #{Name = 'SIP'; Expression = { $_.EmailAddresses | Where-Object { $_ -like "*sip*" } -join ',' } }
I could extract the SIP by iterating using a FOR LOOP through each user properties with EmailAddresses | where {$_ -like "*sip*"}, but I'm trying to extract it in the EXPRESSION statement itself.
How can I get this to work?

You are on the right track, however you are trying to join the objects without referencing the sub-properties you are actually interested in. Try something like:
$list_UsersExtCloud =
Get-Recipient e12367 |
Select-Object Alias, EmailAddresses, #{ Name = 'SIP'; Expression = { ($_.EmailAddresses | Where-Object { $_.Prefix -eq "SIP" }).ProxyAddressString -join ',' } }
I changed the Where clause to use the Prefix. I grouped the address objects then unrolled the ProxyAddressString from them. This give good input to the -join. You can also do this with the AddressString property, I wasn't sure which you were really interested in.
Note: If you let this output without assigning to a variable the EmailAddresses property will likely bump the SIP property off the screen. I found that a little confusing while working this out, thought I'd mention it.
Warning: Get-Recipient has a known issue. When making very large queries it won't page properly and will return an LDAP cookie error. So this may blow up if you have enough recipients. An alternative is to query for mail enabled objects using Get-ADObject then customize the object similarly using Select-Object.

Related

PowerShell pipe ExpandProperty to another Select-Object

I want to get the aliases for all email recipients in my O365 tenant.
If I were doing this one traditional Exchange, the easiest is to Get-Recipient and pull out the SMTPAddress property using Exchange Manangement Console. (Note the Select piped into another Select; works like a champ.)
Get-Recipient | Select Name,SamAccountName -ExpandProperty EmailAddresses | Select Name,SamAccountName,SmtpAddress
The issue is when I try to do the same thing in EXO, the "EmailAddresses" property is output as a flat string and so when I try to pipe it to a 2nd select, the only Property is the Length, not the actual value of the string.
The following kind of works, but I feel like there has to be a better way?
Get-EXORecipient | Select Name -ExpandProperty EmailAddresses | % {Write-Output "$($_.Name),$($_)"}
What -ExpandProperty EmailAddresses expands to are strings, as you state.
The additional properties that these strings are decorated with if you also pass (positionally implied) -Property arguments, such as Name in your example, are present, but will typically not surface unless you explicitly access them on the now-decorated output strings.
If you want output objects that contain each email address as a property, more work is needed.
Get-EXORecipient | ForEach-Object {
foreach ($emailAddress in $_.EmailAddresses) {
[pscustomobject] #{
EmailAddress = $emailAddress
Name = $_.Name
# ... add further properties of interest here
}
}
}

ADSI query, I am trying to find the flag for identifying if a local account is disabled

To try get all possible values I attempted to print them all out, I thought this was a simple approach to get the values I am interested in. However I am interested in identifying if an account is disabled or not and it seems to me that this value isn't available for local accounts? That seems crazy so I must be missing something. Any help would be appreciated.
I have checked here but that doesnt define the flag, ive tried the obvious (Disabled, Enabled) but as I say no luck and I cant see anything obvious from the results from below.
$user_adsi = [ADSI]"WinNT://$ComputerName"
$users = $user_adsi.Children | where { $_.SchemaClassName -eq 'user' } | select *
try
{
foreach ($user in $users)
{
Write-Host $user
}
}
You will need to check UserFlags property for the binary bit that represents decimal 2 for disabled users.
$disabledUsers = $user_adsi.Children |
where { $_.SchemaClassName -eq 'user' -and $_.UserFlags[0] -band 2}
Since the UserFlags (works like UserAccountControl) is type PropertyValueCollection, you will need to index into its first element [0].
You could also use Where() method to create two lists of disabled and enabled users:
$DisabledUsers,$EnabledUsers = $user_adsi.children.where({$_.SchemaClassName -eq 'user'}).where({$_.UserFlags[0] -band 2},'Split')
The Split mode will output items that met the condition into the first variable ($DisabledUsers) and output the remaining items in the second variable ($EnabledUsers).

Filter Records on Multiple Values

I have to get a list of AD users where the Manager field contains one of the following names on my FilterValues list.
I see that someone recommended to use the Where-Object, however when I run the script nothing gets returned. I have tried many approaches but I can't seem to find where I am going wrong. Any advise will be greatly appreciated, TIA.
$FilterValues = $('Williams', 'Smith', 'Johnson')
Get-ADUser -Filter "extensionAttribute10 -like '1.0'" -Properties *
| Where-Object {$_.Manager -contains $FilterValues}
| Format-Table Name, Manager
*** If I run the script without the Where-Object portion I get values back.
The -contains is for testing values in an array, unlike the string .Contains() method. In this case, I'd suggest using the regex -match operator like this:
# an array of manager names
$FilterValues = 'Williams', 'Smith', 'Johnson'
# create a regular expression of the manager names by combining them with the regex OR symbol '|'
# the [regex]::Escape() is there to make sure characters that have special meaning in regex are escaped.
$regexManagers = ($FilterValues | ForEach-Object { [regex]::Escape($_) }) -join '|'
Get-ADUser -Filter "extensionAttribute10 -like '1.0'" -Properties Name, Manager |
Where-Object {$_.Manager -match $regexManagers } |
Format-Table
P.S. It is always a bad idea to search for ALL properties with -Properties * when you only want two properties returned.

PowerShell method Contains not working as expected

I am very new to PowerShell and I need to prepare some PowerShell commands to a assign users some roles in Exchange Online. I first need to check if the user is assigned the role already and if not, I'll assign the role. But I just can't figure out how to check if one email address is part of list of email addresses.
I found many discussions on -contains or .Contains method not working but their solutions never worked for me. My code is below.
$L1Group = Get-MsolGroup | Where-Object { $_.DisplayName -eq "TEST_GROUP"}
$L1Members = Get-MsolGroupMember -GroupObjectId $L1Group.ObjectId
$CurrentMembers = Get-RoleGroupMember "Recipient Management" |
Select -Property WindowsLiveID
foreach ($user in $L1Members) {
if (!$CurrentMembers.Contains($user.EmailAddress)) {
Add-RoleGroupMember "Recipient Management" -Member $user.EmailAddress
}
}
It works fine without the if statement and it assigns roles as expected, but I need to skip users who are already members of the role group. I just cant figure out how to make the if statement work. If I use echo $CurrentMembers it returns list of 4 email addresses, just as expected and even if I try
$CurrentMembers -contains 'MyEmail#MyDomain.com'
it always returns False but the address is in the list.
Your code doesn't work the way you expect because this statement
$CurrentMembers = Get-RoleGroupMember "Recipient Management" |
Select -Property WindowsLiveID
produces a list of custom objects with a single property WindowsLiveID, but your check expects a list of strings. Expand the property to get that list of strings:
$CurrentMembers = Get-RoleGroupMember "Recipient Management" |
Select -Expand WindowsLiveID
This is a common question. .contains and -contains are different. $CurrentMembers may contain sub-properties.
PS C:\Users\admin\foo> 'hi there'.contains('hi')
True
PS C:\Users\admin\foo> 'hi','there' -contains 'hi'
True
Does this work? Another common question is how to get just the value from the property.
if (! ($CurrentMembers.windowsliveid -Contains $user.EmailAddress) )
Hmm, interesting how .contains() works with arrays. It's more like -contains. More confusion!
PS C:\Users\js\foo> $a = 'one','two','three'
PS C:\Users\js\foo> $a.contains('one')
True
PS C:\Users\js\foo> $a.contains('o')
False
PS C:\Users\js\foo> $a.contains
OverloadDefinitions
-------------------
bool IList.Contains(System.Object value)
Solution is in comments - "Select -Property WindowsLiveID -> Select -Expand WindowsLiveID"
– Ansgar Wiechers 2 hours ago
Hopefully Angsar will post an answer so he can get credit...
Here's a link to the M$oft doc for the Select-Object cmdlet:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object?view=powershell-6

Powershell - keep specific word in a string

I'm doing AD extract and I sort the field "distinguishedname" and I want to keep only a specific part of the value that represent the "parent OU" of the user itself.
I'm running this command to do an add extract of all users:
import-module activedirectory
get-aduser -filter * -properties *| Select-Object -Property SamAccountName,CN,co,ExtensionAttribute10,extensionAttribute11,extensionAttribute12,EmailAddress,whenCreated,Enabled,LastLogonDate,accountexpirationdate,distinguishedname |Sort-Object -Property Name | Export-Csv -Delimiter ";" -path "u:\theOutFile_NOFILTER_July.txt"
The column "distinguishedname" look like this:
distinguishedname
CN=familly\, user,OU=Remote Users,OU=New York,OU=My,DC=Company,DC=Local
CN=nameless\, cat,OU=Remote Users,OU=Ottawa,OU=My,DC=Company,DC=Local
CN=Cameron\, James,OU=Regular Users,OU=Hollywood,OU=My,DC=Company,DC=Local
CN=Bon\, Jean,OU=regular Users,OU=Springfield,OU=My,DC=Company,DC=Local
Note July 10
some time I will hit those line:
CN=Dog\, Cesar,OU=Special Accounts,OU=Regular Users,OU=Alma,OU=My,DC=Company,DC=Local
CN=keys\, Alicia,OU=Special Accounts,OU=Regular Users,OU=Paris,OU=My,DC=Company,DC=Local
CN=Clansy\, Door,OU=Map Drives,OU=Remote Users,OU=Rome,OU=My,DC=Company,DC=Local
In those case I am getting result such Remote Users an Regular Users instead of the City. I've tried some modification in your command you gave but in vain.
But I would like the first command to return this result instead:
distinguishedname
New York
Ottawa
Hollywood
Springfield
I can't effort to find how.
thanks in advance
Select-Object has a very versatile feature to create calculated properties using a hash in the place of a property name, where the key "Name" is set to the name of the calculated property (effectively, the column heading), and "Expression" is set to a code block that determines the value of the property, for each object in the pipeline. This will do what you want:
Get-Aduser -Filter * -Properties * | Select-Object -Property SamAccountName,CN,co,ExtensionAttribute10,extensionAttribute11,extensionAttribute12,EmailAddress,whenCreated,Enabled,LastLogonDate,accountexpirationdate,#{Name='distinguishedname'; Expression={[regex]::match($_.distinguishedname,'OU=.+?OU=(.+?),(OU|DC)=').Groups[1].Value}} | Sort-Object -Property Name | Export-Csv -Delimiter ";" -Path "u:\theOutFile_NOFILTER_July.txt"
Here's a breakdown what's going on:
Name='distinguishedname' tells it to create a new column called 'distinguishedname'. I used that name to match your example of the output you're looking for, but it doesn't have to be the name of an existing property. It would probably make more sense to change the name to something more descriptive of the values you're calculating, e.g. Name="parentOU".
[regex]::match is used to extract the desired portion from $_.distinguishedname using the regular expression OU=.+?OU=(.+?),(OU|DC)=, which isolates the name of the second OU in the list using a match group.
.Groups[1].Value returns the value of the first match group (the part matched by the contents of the first set of parentheses). .Value on its own without .Groups[1] would return the entire matched string, from the first OU= to the = following name of the parent OU. The following would work just as well, using zero-width assertions instead of a match group: [regex]::match($_.distinguishedname,'(?<=OU=.+?OU=).+?(?=,(OU|DC)=)').Value