Wednesday, 3 April 2019

Get a list of shared mailboxes and members using Powershell

In this is post, I am going to share powershell commands to get shared mailboxes and find users who have permissions (Full Access or Send as) in the shared mailboxes. The commands used in this post specifically tested in Exchange Online, however it should work for Exchange On-Premises (Exchange 2010 and 2013) as well. Actually shared mailbox don't have members, but nowadays Microsoft itself calls users as members who have been granted Full Access permission to the shared mailbox. Reference post: Add or remove members from a shared mailbox.

List shared mailboxes :

You can find and list shared mailboxes using the Exchange Powershell cmdlet Get-Mailbox by passing the input "SharedMailbox" for the parameter -RecipientTypeDetails.
Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited |
Select-Object Identity,Alias,DisplayName | Sort DisplayName

List shared mailboxes and users who have permissions :

After retrieving mailboxes, we can use the cmdlet Get-MailboxPermission to get the available permissions configured for the users in every mailbox.
Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | Get-MailboxPermission |
Select-Object Identity,User,AccessRights
By default, the Get-MailboxPermission command lists built-in and system account rights along with users permission. To exclude those entries, we can use the Where-Object command to filter rights only for mailbox user accounts.
Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | Get-MailboxPermission |
Select-Object Identity,User,AccessRights | Where-Object {($_.user -like '*@*')}

Export shared mailboxes and users with permissions :

The below powershell commands export shared mailboxes and its users' permission details to CSV file.
Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | Get-MailboxPermission |
Select-Object Identity,User,AccessRights | Where-Object {($_.user -like '*@*')} |
Export-CSV "C:\\SharedMailboxes.csv" -NoTypeInformation -Encoding UTF8
Read More...

Friday, 22 March 2019

Get all teams in Microsoft Teams using Microsoft Graph

As of now there is no unique graph endpoint for teams to list all Teams in an organization. Microsoft Teams uses Office 365 groups (Unified Group) as its base service for identity and some other features, so there is a one-to-one relationship between Office 365 groups and Teams. When you create a Team, the back-end will automatically create an Office 365 Group.

To list all teams in a tenant, first we have to find all unified groups and then in code find the groups that have a resourceProvisioningOptions property that contains "Team"

List all unified groups:

https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(a:a eq 'unified')

List only required properties for all unified groups:

The group object includes large number properties, so we can list only required properties using $select query
https://graph.microsoft.com/v1.0/groups?$filter=groupTypes/any(a:a eq 'unified')&$select=id,resourceProvisioningOptions

Sample output:

In below result, Teams enabled in one group and not enabled in the other group.
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups(id,resourceProvisioningOptions)", 
    "value": [ 
        { 
           "id": "08f62f70-9727-4e6e-63ef-8e0f2d9b7b23", #Teams not enabled
            "resourceProvisioningOptions": [] 
        }, 
        { 
            "id": "02cd9fd6-8f93-4756-87c3-1fb73740a315", #Teams enabled group
            "resourceProvisioningOptions": ["Team"]
        }, 
   ]
}
As of now (23-March-2019), $filter with the property resourceProvisioningOptions is not supported, but using the Beta APIs you can apply $filter with resourceProvisioningOptions to return only the groups that have teams.
https://graph.microsoft.com/beta/groups?$filter=resourceProvisioningOptions/Any(x:x eq 'Team')

Get Team specific information

Now you have got list of teams enabled groups and the group object includes only limited amount of teams related properties (for ex: id and name of the teams). To get information for the team in a particular group, call the below API and include the group ID.
https://graph.microsoft.com/v1.0/teams/{teamGroupId}

#For example: 

https://graph.microsoft.com/v1.0/teams/02cd9fd6-8f93-4756-87c3-1fb73740a315

Find teams in which current user is a member of

You can use the joinedTeams endpoint to list all the teams in which current user or specific user is member.
https://graph.microsoft.com/v1.0/me/joinedTeams

Find teams where a specific user is member of

https://graph.microsoft.com/v1.0/users/{id}/joinedTeams

#For example 

https://graph.microsoft.com/v1.0/users/63cd9fd6-8f93-4756-87c3-1fb63740a315/joinedTeams
Read More...

Friday, 15 March 2019

Microsoft Planner Task : Can't able to Post Comment

Today I have created a demo tenant to test Microsoft Planner features and logged-in to the Planner Portal with a test account and tried to post a comment in a Planner task, the comment was placed successfully but it was reverted immediately and the comment removed with some unknown technical error.

Actually a Planner plan's comments feature is connected with its associated group's conversation (Modern Office 365 Group Conversation). So I have tried to check the problematic plan's group conversation is really works or not by clicking triple-dots (...) >> Conversation.

Microsoft Planner can not able to post comment

But I received the below error while accessing group conversation page.
:-( Something went wrong
We couldn’t find a mailbox for this recipient. Either they don’t have a mailbox or don’t have a license assigned.
X-OWA-Error: Microsoft.Exchange.Clients.Owa2.Server.Core.OwaUserHasNoMailboxAndNoLicenseAssignedException
Planner O365 Group Conversation Mailbox

Solution :

As I already said the Planner comments feature is powered by Office 365 Groups conversation, so to enable this feature your tenant should have Exchange Online license first and the user who is trying to post a comment should assigned valid Exchange Online license. In my case, the user account don't have a license and the problem was solved after assigning the license.

Without Exchange Online license you can't use this feature as of now. You can't use On-Premise Exchange service since the modern unified group conversation is supported only through Exchange Online mailbox.

You may still face issue to post comment (and error something like below while accessing conversation page) after assigning Exchange Online license but if the mailbox was not created for the user.
:-( Something went wrong
A mailbox couldn't be found for user@domain.com.
X-OWA-Error Microsoft.Exchange.Data.Storage.UserHasNoMailboxException
When a new Office 365 account is granted an exchange online license, it might take few moments for the mailbox provision. The maximum wait time is 48 hours.

Please try logging in OWA (https://outlook.office.com/owa/) later to see if the issue persists.

You can also change to another browser and use the incognito or private mode to check if there are any improvements.
Read More...

Tuesday, 26 February 2019

Powershell String Comparisons : Case-Sensitive and Case-Insensitive (Ignore Case)

Always there is more amount of chance to work with string value in Powershell. I am also worked with string values and used lot of string compare checks in my scripts. We all know this is an easy job, but sometimes we need to think the comparison check is actually considering the case-sensitive or ignore case. So in the post, I am going to list the set of samples for string comparison.

You can use the below examples both in IF statement and Where-Object.
$strVal ='Hello world'
#If check statement 
if($strVal -eq 'hello world') { //do something }
#where object check statement
Get-Process | Where-Object { $_.Name -eq 'svchost' }

Equal Check - Ignore Case

The normal powershell -eq operator is designed to perform case insensitive comparison and it will ignore the case while comparing the string values.
"Hello World" -eq "hello world" # return True

"Hello World" -eq "Hello World" # return True
Even though the -eq operator performs string comparison in case-insensitive way, you may still want to ensure a case insensitive comparison for some cases, in that place you can use the operator -ieq. The usage of this operator is very less because most people use -eq which does the same job.
"Hello World" -ieq "hello world" # return True

Equal Check - Case-Sensitive

As the normal powershell -eq operator is designed to perform case insensitive comparison, you may need to enforce case-sensitive string compare in some cases, for this case you can use the operator -ceq which compare two string values with case sensitive check.
"Hello World" -ceq "hello world" # return False

"Hello World" -ceq "Hello World" # return True

Contains Check - Ignore Case

We can use the -like operator for contains check with case insensitive operation.
"Hello World" -like "*world*" # return True

"Hello World" -like "*World*" # return True
Note: You can not use the comparison operator contains to check the contains string, because it's designed to tell you if a
powershell array object includes ('contains') a particular object

Contains Check - Case-Sensitive

To perform a case sensitive comparison just prefix the word "c" with like operator ("clike").
"Hello World" -clike "*world*" # return False

"Hello World" -clike "*World*" # return True

Startswith - Ignore Case

We can use the same operator "like" for starts with comparison by just putting the wildcard character (*) at the end.
"Hello World" -like "hello*" # return True

"Hello World" -like "Hello*" # return True

Startswith - Case-Sensitive

"Hello World" -clike "hello*" # return False

"Hello World" -clike "Hello*" # return True

Endswith - Ignore Case

For ends with check, we need to put the wildcard character (*) at the start of the string.
"Hello World" -like "*world" # return True

"Hello World" -like "*World" # return True

Endswith - Case-Sensitive

"Hello World" -clike "*world" # return False

"Hello World" -clike "*World" # return True

Check Array Contains String - Ignore Case

We can use the operator contains to check whether a powershell string array includes a string word or not.
@("abc", "def") -contains "ABC" # return True

@("abc", "def") -contains "abc" # return True

Check Array Contains String - Case-Sensitive

@("abc", "def") -ccontains "ABC" # return False

@("abc", "def") -ccontains "abc" # return True
Read More...

Thursday, 14 February 2019

Manage Office 365 Groups using Azure AD Powershell module

Earlier you can manage modern Office 365 Groups (or Unified Groups) through Exchange Online Powershell module. Now the Azure AD Powershell team introduced new AzureADMSGroup cmdlets to provide the functionality of Microsoft Graph to create and manage unified groups, which includes creating modern O365 groups and dynamic groups through Powershell.

Before proceed, run the below command to connect Azure AD Powershell for Graph module:
Connect-AzureAD

Create new Office 365 Group:

In exchange module we need to run New-UnifiedGroup cmdlet to create an Office 365 Group, here you have to use the New-AzureADMSGroup cmdlet to create a new Office 365 Group.
New-AzureADMSGroup -DisplayName "Test O365 Group" -MailNickname "TestO365Group" -GroupTypes "Unified" -Description "This is a test group" -MailEnabled $true -SecurityEnabled $true
Note: When you create group using New-UnifiedGroup, the mailbox will be created immediately. When you use New-AzureADMSGroup, first the group object will be created in AzureAD and the group object synchronized with Exchange Online, which then creates the group mailbox, so there may be some delay in setting up group mailbox for the new group that was created by New-AzureADMSGroup.

Get a list of all Office 365 Groups:

In exchange module, you have to use the command Get-UnifiedGroup to retrieve all unified groups, with Azure AD Powershell you can achieve the same using the Get-AzureADMSGroup cmdlet.

By default the Get-AzureADMSGroup cmdlet gets information about all type of available groups in Azure Active Directory.
Get-AzureADMSGroup  -All:$true
We need to apply filter to list only Office 365 groups alone.
Get-AzureADMSGroup -Filter "groupTypes/any(c:c eq 'Unified')" -All:$true

Export report to CSV file:

Get-AzureADMSGroup -Filter "groupTypes/any(c:c eq 'Unified')" -All:$true |
Select-Object DisplayName, Mail, Visibility |
Export-CSV "C:\\O365Groups.csv" -NoTypeInformation -Encoding UTF8

Find members and owners of an Office 365 Group:

With exchange module you can list group members and owners by using the Get-UnifiedGroupLinks cmdlet, here you have to use the command Get-AzureADGroupMember to find members and need to run the command Get-AzureADGroupOwner to list owners.
Get-AzureADGroupMember -ObjectId (Get-AzureADGroup -SearchString "<GroupName>").ObjectId

List owners for the given group:

Get-AzureADGroupOwner -ObjectId (Get-AzureADGroup -SearchString "<GroupName>").ObjectId
Read More...

Wednesday, 13 February 2019

Copy Members from Distribution Group to Office 365 Group in PowerShell

In this post, I am going to write powershell script to add users into Office 365 group by importing members from distribution list. We can use the Exchange powershell cmdlet Get-DistributionGroupMember to get members from distribution group and use the command Add-UnifiedGroupLinks to add user as a member into existing Unified group.

Before proceed run the following command to connect Exchange Online powershell module.
$365Logon = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $365Logon -Authentication Basic -AllowRedirection
Import-PSSession $Session
The below powershell command retrieves members from a given distribution group.
Get-DistributionGroupMember -Identity "YourDG" -ResultSize Unlimited
Use the below command to add users into an existing Office 365 group.
Add-UnifiedGroupLinks –Identity "O365Group" –LinkType Members  –Links username@domain.com

Copy members from distribution list to Office 365 group:

#Source - Provide distribution group
$DistGroup = "TestDG"
#Target - Provide office 365 group
$O365Group = "TestO365Group"
$DG_members = Get-DistributionGroupMember -Identity $DistGroup -ResultSize Unlimited
$totalMembers = $DG_members.Count
$i = 1 
$DG_members | ForEach-Object {
Write-Progress -activity "Processing $_" -status "$i out of $totalMembers members added"
Add-UnifiedGroupLinks –Identity $O365Group –LinkType Members  –Links $_.PrimarySmtpAddress
$i++
}
Read More...

Thursday, 7 February 2019

Find Disabled Users in Office 365 Group using Powershell

In this post, I am going to share powershell script to find and list disabled users that are still a member of Office 365 Groups. In Azure AD environment, the disabled users are nothing but the sign-in access blocked users. You can retrieve Office 365 group members using the Exchange Online powershell command Get-UnifiedGroupLinks and find members' account status by using the Azure AD powershell command Get-AzureADUser. So we need to first connect both powershell modules before running the script.

First connect Exchange Online powershell module by running below commands:
$365Logon = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $365Logon -Authentication Basic -AllowRedirection
Import-PSSession $Session
Run the below command to import AzureAD module:
Connect-AzureAD

Find and list disabled users who are still a member in a given Office 365 group:

$Result=@()
#Replace your group name
$o365Group = "YourO365Group"
$groupMembers = Get-UnifiedGroupLinks -Identity $o365Group -LinkType Members -ResultSize Unlimited
$groupMembers | ForEach-Object {
$memberId = $_.ExternalDirectoryObjectId
$user = Get-AzureADUser -ObjectId $memberId -ErrorAction SilentlyContinue
If ($user -ne $Null) 
{
If ($user.AccountEnabled -eq $true) {
$userStatus = "Enabled"
} Else {
$userStatus = "Disabled"
} 
$Result += New-Object PSObject -property @{ 
UserName = $user.DisplayName
UserPrincipalName = $user.UserPrincipalName
AccountStatus = $userStatus
}
}
Else
{
#Write-Host "User not found: $_.DisplayName"
}
}
$Result |Where-Object {$_.AccountStatus -eq "Disabled"} | Select-Object UserName,UserPrincipalName

Export result to CSV file:

You can export disabled members of the given Office 365 Group to CSV file by running below command.
$Result | Where-Object {$_.AccountStatus -eq "Disabled"} |
Select-Object UserName,UserPrincipalName |
Export-CSV "C:\\DisabledO365GroupMembers.csv" -NoTypeInformation -Encoding UTF8

Find enabled users alone in Office 365 Group:

You can run the below command to list only enabled users that are member of the given O365 group.
$Result | Where-Object {$_.AccountStatus -eq "Enabled"} | Select-Object UserName,UserPrincipalName
Read More...

How to map Mailbox object with AzureAD user object using Powershell

Recently I wrote a Powershell script to find disabled users that are associated with particular set of mailboxes, for this need, I have to first get mailboxes using the Exchange Online powershell cmdlet Get-Mailbox, then I need to find Azure AD object for required mailbox using Get-AzureADUser cmdlet. The Get-AzureADUser cmdlet accepts ID parameter only as a UPN or ObjectId of a user in Azure AD. After exploring Mailbox object attributes, I don't find any attribute with the name UserPrincipalName or ObjectId and the properties Id, Guid and Identity are not suitable here as they hold different values and finally found the attribute ExternalDirectoryObjectId perfectly holds same value as its equivalent Azure AD object's ObjectId value.

Note: You might have noticed the properties WindowsEmailAddress and PrimarySmtpAddress got the value as same UserPrincipalName in Azure AD, but I have not preferred any of these two fields as it may or may not be equivalent with UPN in all cases.
$mailbox = Get-Mailbox -Identity "Alex Wilber"
$azureADuser = Get-AzureADUser -Object $mailbox.ExternalDirectoryObjectId

$mailbox.ExternalDirectoryObjectId
$azureADuser.ObjectId
How to find AzureAD user object for its equivalent mailbox object in Powershell
You can also find the attribute ExternalDirectoryObjectId with other Exchange powershell cmdlets like Get-Recipient.
$mailbox = Get-Recipient -Identity "Alex Wilber"
$azureADuser = Get-AzureADUser -Object $mailbox.ExternalDirectoryObjectId
Read More...