Thursday, 20 June 2019

Add user as owner of all Office 365 groups using Powershell

As you know modern Office 365 groups are being used as base service for other Office 365 workloads (Ex: Teams, Planner).So you have to first member of the group to manage and work with groups and its associated services, if you want to do some high privilege actions (ex: delete group, delete team, or delete planner plan) then you have to be added as a owner of the group.

With Global Admin privilege, sometimes you may wanted to delete a group or update some group settings, but without being a owner of the group you can't delete group even though you have global admin privilege. We can use Exchnage Online Powershell cmdlet Add-UnifiedGroupLinks to add user as owner and member of unified group.

Before proceed, first connect EXO Powershell module by using 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
The below commands add an user as owner and member of the specific group :
Add-UnifiedGroupLinks –Identity "TestO365Group" –LinkType Members –Links username@yourdomain.com
Add-UnifiedGroupLinks –Identity "TestO365Group" –LinkType Owners –Links username@yourdomain.com
Note : To get complete privilege, you have to add the user as owner and also as a member of the group.

Add user as owner of all Office 365 Groups :

To add an user as owner of all the available o365 groups in your organization, first you have to get all the unified groups using the Get-UnifiedGroup cmdlet and pipe the results to Add-UnifiedGroupLinks cmdlet to add user one by one.
$userToAddOwner = "username@yourdomain.com"
Get-UnifiedGroup -ResultSize Unlimited | ForEach-Object {
$o365group = $_
Add-UnifiedGroupLinks –Identity $o365group.Name –LinkType Members –Links $userToAddOwner
Add-UnifiedGroupLinks –Identity $o365group.Name –LinkType Owners –Links $userToAddOwner
}

Add user as owner of multiple groups from CSV :

Consider the csv file o365Groups.csv that includes the column GroupName which holds the name of groups in each row of the csv file.
$userToAddOwner = "username@yourdomain.com"
Import-CSV "C:\o365Groups.csv" | ForEach-Object {
$groupName = $_."GroupName"
Add-UnifiedGroupLinks –Identity $groupName –LinkType Members –Links $userToAddOwner
Add-UnifiedGroupLinks –Identity $groupName –LinkType Owners –Links $userToAddOwner
}
You can use the Remove-UnifiedGroupLinks cmdlet to remove membership and ownership of an user from Office 365 group.

Friday, 14 June 2019

Get info of all the configured Outlook profiles using Powershell

In Outlook client you can configure multiple email accounts as per your need. You can add your primary work email as default profile and configure personal email as secondary profile. Sometimes you may need to fetch details of all the configured profiles, you can use outlook client itself for this need, but an easiest way is Powershell to retrieve all the properties from multiple accounts.

Open the powershell console and run the below command to list DisplayName and SmtpAddress of all accounts.
$outlookApplication = New-Object -ComObject 'Outlook.Application'
$accounts = $outlookApplication.Session.Accounts
$accounts | Select DisplayName, SmtpAddress
Use below command to list all the available properties.
$accounts | FL
The below command returns the default profile name
$outlookApplication.Application.DefaultProfileName
Note: The above commands will work only in Outlook client installed machine as it uses the interface library "Microsoft.Office.Interop.Outlook.Application" which works under the logged-in user's outlook context.

Since the above commands are working under the logged-in user's outlook context, you have to open the powershell without Run as administrator privilege. If you have opened the powershell console with Run as administrator privilege, then you will get the below error :
PS C:\WINDOWS\system32> $outlookApplication = New-Object -ComObject 'Outlook.Application'
New-Object : Retrieving the COM class factory for component with CLSID {0006F03A-0000-0000-C000-000000000046} failed
due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005
(CO_E_SERVER_EXEC_FAILURE)).
At line:1 char:23
+ $outlookApplication = New-Object -ComObject 'Outlook.Application'
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [New-Object], COMException
    + FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand

Wednesday, 5 June 2019

Get Azure AD Users with their Registered Devices using Powershell

In this post I am going to share Powershell script to find and list devices that are registered by Azure AD users. We can use the Get-AzureADUserRegisteredDevice cmdlet to get the registered devices.

Before proceed run the below command to connect Azure AD Powershell module.
Connect-AzureAD
The below command gets the devices that are registered to the specified user.
$user = Get-AzureADUser -SearchString "UserName"
Get-AzureADUserRegisteredDevice -ObjectId  $user.ObjectId -All $true

List registered devices of all Azure AD users :

To get a report of device list for all Azure AD users, first we need to get users by Get-AzureADUser cmdlet and pipe the users list to Get-AzureADUserRegisteredDevice cmdlet.
$Result=@()
$Users = Get-AzureADUser -All $true | Select UserPrincipalName,ObjectId
$Users | ForEach-Object {
$user = $_
Get-AzureADUserRegisteredDevice -ObjectId $user.ObjectId | ForEach-Object {
$Result += New-Object PSObject -property @{ 
DeviceOwner = $user.UserPrincipalName
DeviceName = $_.DisplayName
DeviceOSType = $_.DeviceOSType
ApproximateLastLogonTimeStamp = $_.ApproximateLastLogonTimeStamp
}
}
}
$Result | Select DeviceOwner,DeviceName,DeviceOSType,ApproximateLastLogonTimeStamp

Export Report to CSV file :

You can export the result to CSV file using the command Export-CSV.
$Result | Export-CSV "C:\\AzureADJoinedDevices.csv" -NoTypeInformation -Encoding UTF8

Tuesday, 4 June 2019

How to Set Property Bag Value in SharePoint Online using Powershell

The SharePoint property bag is a hash table, which is used to store data in key-value pairs and it is good place to store and retrieve meta-data or custom properties. We can set and get property bag value using CSOM or SharePoint Online PnP cmdlets. In this post I am going to share steps to update property bag value using PnP Powershell Module.

Before proceed install SharePoint PnP PowerShell Online module by running below command.
Install-Module SharePointPnPPowerShellOnline -Force
Run the below command to connect site with PnPOnline powershell.
$SiteURL = "https://MyTenant.sharepoint.com/sites/testsite"
Connect-PnPOnline $SiteURL
Once you have connected the required site, run the below command to set required property value.
Set-PnPPropertyBagValue -Key "myCustomProperty" -Value "customValue"
The above command works without any issue if the site setting NoScript disabled, or else you will get the below error message.
Set-PnPPropertyBagValue : Site has NoScript enabled, and setting property bag values is not supported
At line:1 char:1
+ Set-PnPPropertyBagValue -Key "myCustomProperty" -Value "customValue"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (SharePointPnP.P...ropertyBagValue:SetPropertyBagValue) [Set-PnPProper
   tyBagValue], Exception
    + FullyQualifiedErrorId : NoScriptEnabled,SharePointPnP.PowerShell.Commands.SetPropertyBagValue
To disable the NoScript setting, we need to set the property DenyAddAndCustomizePages as Disabled. Run the below command to disable NoScript setting for the given site.
$site = Get-PnPTenantSite -Detailed -Url $SiteURL 
$site.DenyAddAndCustomizePages = 'Disabled'
$site.Update()
$site.Context.ExecuteQuery()
-- OR -- You can also use the below command to set this value using Set-PnPTenantSite cmdlet in modern sharepoint sites.
Set-PnPTenantSite -Url $SiteURL  -NoScriptSite:$false
Now run the below command to re-connect the site and set required property bag value.
Connect-PnPOnline $SiteURL
Set-PnPPropertyBagValue -Key "myCustomProperty" -Value "customValue"

Get Property Bag value :

Use the below command to get the configured property value.
Get-PnPPropertyBag -Key "myCustomProperty"

Remove Property Bag value :

Run the below command to delete an existing property.
Remove-PnPPropertyBagValue -Key "myCustomProperty" -Force

Thursday, 30 May 2019

Fix "Access to OData is disabled" error when read posts from mailbox using Graph API

I have been working with Microsoft Planner using Graph API and getting the error message ErrorAccessDenied : Access to OData is disabled while reading messages from Office 365 group mailbox.
Request URL: https://graph.microsoft.com/v1.0/groups/<groupId>/threads/<conversationThreadId>/posts
Request Method: GET
Status Code: 403 Forbidden

{
  "error": {
    "code": "ErrorAccessDenied",
    "message": "Access to OData is disabled.",
    "innerError": {
      "request-id": "b4bbe2f4-81d1-46cb-8fee-d79d02257e64",
      "date": "2019-05-30T05:39:21"
    }
  }
}

Solution :

After exploring some time, found that the exchange mailbox and calendar related graph api end-points are internally use EWS (Exchange Web Service) to fetch and update data in mailbox and calendar. You may received this error message either if the EWS access is disabled for all client applications or if EWS access is allowed only for particular applications.

You can check your current tenant EWS access policy by using the Exchange Online powershell cmdlet Get-OrganizationConfig. First, connect EXO powershell module and run the below command:
Get-OrganizationConfig | select EwsApplicationAccessPolicy, EwsAllowList, EwsBlockList
If you find any entries either for Allow access policy or Block access policy, then this might be the root cause for this error. If allow policy configured, then enusure that your client application is included for EWS access, or if block policy configured, then ensure that your client app is not included in block list.

Run the below command to remove the applied EWS access policy.
Set-OrganizationConfig -EwsApplicationAccessPolicy $null
You can refer below articles to know more about how to configure EWS access.

Wednesday, 29 May 2019

Block Read Access for Non-Admin Users to Azure AD Powershell and Graph API

In Office 365 tenant, by default any user can easily connect Azure AD powershell and run the command Get-MsolUser or Get-AzureADUser to list all other user details including users’ personal data (ex: phone no, address, password last set time, etc..), and also fetch this info using users (https://graph.microsoft.com/v1.0/users) Graph Api end-point . This design may not be problem in some organisations, but it will create some serious security issue in secured organisations.

We can use the Set-MsolCompanySettings cmdlet from Azure AD Powershell v1 module (MSOnline) to block this read access for non-admin users. You should have Global Admin permission to run this command. Before proceed run the below command to connect Azure AD module.
Connect-MsolService
Run the below command to disable users' permission to read other users data.
Set-MsolCompanySettings -UsersPermissionToReadOtherUsersEnabled $false
After running the above command you can still use Global Admin account without any issue to read all users data, but if you connect Azure AD powershell with non-admin user account and run the Get-MsolUser cmdlet, then you will get the error "Get-MsolUser : Access Denied. You do not have permissions to call this cmdlet".
PS C:\> Get-MsolUser
Get-MsolUser : Access Denied. You do not have permissions to call this cmdlet.
At line:1 char:1
+ Get-MsolUser
+ ~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [Get-MsolUser], MicrosoftOnlineException
    + FullyQualifiedErrorId : Microsoft.Online.Administration.Automation.AccessDeniedException,Microsoft.Online.Admini
   stration.Automation.GetUser

Azure AD Powershell v2 module :

When you run the Get-AzureADUser cmdlet you will get the error message "Authorization_RequestDenied : Insufficient privileges to complete the operation"
PS C:\> Get-AzureADUser
Get-AzureADUser : Error occurred while executing GetUsers
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
RequestId: 784ed01e-094f-4ecd-8bcd-6557e5bc7b58
DateTimeStamp: Wed, 29 May 2019 18:09:40 GMT
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed
At line:1 char:1
+ Get-AzureADUser
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-AzureADUser], ApiException
    + FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.GetUser

Graph Api - Users end-point :

You will also get Access Denied response when you connect users graph end-point using normal user account.
Request URL: https://graph.microsoft.com/v1.0/users
Request Method: GET
Status Code: 403 Forbidden

{
  "error": {
    "code": "Authorization_RequestDenied",
    "message": "Insufficient privileges to complete the operation.",
    "innerError": {
      "request-id": "b254adb3-8918-4921-b899-8c381b9ea611",
      "date": "2019-05-29T18:27:59"
    }
  }
}
Note: Blocking read access to other users' data may cause some problems in Microsoft Planner and Teams (ex: search users may not work when you add members to a plan).

Change local system user account password using Powershell

We can use the Get-LocalUser cmdlet to get local user account details and use the Set-LocalUser cmdlet to update local account information. In this post will share powershell commands to reset local user password and steps to force user to change password at next logon.

Note: Open the Powershell console with Run as administrator privilege.

Run the below command to list specific user details.
Get-LocalUser -Name "testuser" | FL

Change Password :

We have to pass the new password text as Secure String password for the parameter Password in Set-LocalUser cmdlet. The below command reset password for the user "testuser", you can copy the command and replace your own username and new password text.
$SecurePassword = ConvertTo-SecureString "P@ssword!" -AsPlainText -Force
$UserAccount = Get-LocalUser -Name "testuser"
$UserAccount | Set-LocalUser -Password $SecurePassword

Force user to change password at next logon :

We can't use Set-LocalUser cmdlet to set the flag User must change password at next logon and we can use the native interface (ADSI WinNT Provider) to set this flag. Actually we need to expire an user's password to force the user to change password at next login. The below command sets value for passwordExpired property as 1 to make the user's password to expire state.
$user=[ADSI]'WinNT://localhost/testuser';
$user.passwordExpired = 1;
$user.setinfo();

Tuesday, 28 May 2019

Hide mail enabled security group from GAL using Powershell

Mail-enabled security group is nothing but the security group which also act as a distribution list. The group's security related properties are controlled by Azure AD and Message distribution related stuffs are controlled by Exchange Online. So we can use the Exchange powershell cmdlet Set-DistributionGroup to hide its mail address from Global Address List.
Set-DistributionGroup "mail security group name" -HiddenFromAddressListsEnabled:$true
We are setting the attribute HiddenFromAddressListsEnabled as true to hide group mail id from global address book. You can use the following command to set this property for all mail-enabled security groups.
Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup | Set-DistributionGroup -HiddenFromAddressListsEnabled:$true
The below command lists all groups with GAL visible status:
Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup | Select DisplayName,HiddenFromAddressListsEnabled

Find Owners and Members of Mail-Enabled Security Groups using Powershell

Mail-enabled security group is nothing but the security group which also act as a distribution list. In Office 365 environment this group can be used to distribute messages as well as to grant access permissions to SharePoint resources.

Since this group is being used for dual purpose, Security (controlled by Azure AD) and Message distribution (controlled by Exchange Online), the group object will be maintained in both places Azure AD and Exchange Online. You can use Azure AD Admin portal (and Azure AD Powershell module) to manage azure ad related properties and use Exchange Online Admin center (and Exchange Online powershell module) to update exchange related attributes.

Note: Before proceed connect both Azure AD and Exchange Online powershell modules.

List mail-enabled security groups:

We can use the Get-AzureADGroup cmdlet to list only mail enabled security groups.
Get-AzureADGroup -Filter "SecurityEnabled eq true and MailEnabled eq true"
We can also use the Exchange Online powershell command Get-DistributionGroup to list mail enabled security groups.
Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup

Find Owners of mail-enabled security groups

We can use the Azure AD powershell command Get-AzureADGroupOwner to list owners of security groups, but it will not list mail-enabled security group owners. So we can extract owners info from ManagedBy attribute in Get-DistributionGroup cmdlet.
Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup |
Select DisplayName,ManagedBy

Find Members of mail-enabled security groups

We can use the Get-AzureADGroupMember cmdlet to retrieve members of Azure AD groups.
$group = Get-AzureADGroup -SearchString "TestSecurityGroup"
Get-AzureADGroupMember -ObjectId $group.ObjectId |select DisplayName, UserPrincipalName
You can use the below command to list members of all mail-enabled security groups.
$mailGroups = Get-AzureADGroup -Filter "SecurityEnabled eq true and MailEnabled eq true"
$Result = @()
$mailGroups | ForEach-Object {
$group = $_
Get-AzureADGroupMember -ObjectId $group.ObjectId | ForEach-Object {
$member = $_
$Result += New-Object PSObject -property @{ 
GroupName = $group.DisplayName
Member = $member.DisplayName
UserPrincipalName = $member.UserPrincipalName
}
}
}
$Result | Select GroupName,Member,UserPrincipalName
We can also use the Exchange powershell cmdlet Get-DistributionGroupMember to list members.
$mailGroups = Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup
$Result = @()
$mailGroups | ForEach-Object {
$group = $_
Get-DistributionGroupMember -Identity $group.Identity | ForEach-Object {
$member = $_
$Result += New-Object PSObject -property @{ 
GroupName = $group.DisplayName
Member = $member.DisplayName
PrimarySmtpAddress = $member.PrimarySmtpAddress
}
}
}
$Result | Select GroupName,Member,PrimarySmtpAddress
You can export the result to CSV file using the command Export-CSV.
$Result | Export-CSV "C:\\Mail-Security-Group-Members.csv" -NoTypeInformation -Encoding UTF8

Monday, 27 May 2019

Find and List Security Groups and Members in Office 365 using Powershell

Two types of security groups are supported in Office 365, normal security group and mail-enabled security group. Both groups are mainly used for granting access to SharePoint resources, the mail-enabled security group can be used to distribute messages as well as to grant access permissions to resources. In this post, I am going to share powershell script to list and export both security groups and their owners and members.

We can use the Azure AD powershell cmdlet Get-AzureADGroup to list all type of groups, by applying proper Filter with this command we can retrieve both type of security groups.

Before proceed run the below command to connect Azure AD powershell module.
Connect-AzureAD

List all security groups:

The below command lists both normal security groups and mail-enabled security groups.
Get-AzureADGroup -Filter "SecurityEnabled eq true" | Select DisplayName,MailEnabled,ObjectId

List mail-enabled security groups:

We need to add the field MailEnabled in filter to list only mail enabled security groups.
Get-AzureADGroup -Filter "SecurityEnabled eq true and MailEnabled eq true"

List pure security groups alone:

Get-AzureADGroup -Filter "SecurityEnabled eq true and MailEnabled eq false"

Find owners of all security groups:

We can use the command Get-AzureADGroupOwner to retrieve owners of each group.
$group = Get-AzureADGroup -SearchString "TestSecurityGroup"
Get-AzureADGroupOwner -ObjectId $group.ObjectId |select DisplayName, UserPrincipalName
Run the below command to retrieve all security groups and their owner details.
$groups = Get-AzureADGroup -Filter "SecurityEnabled eq true"
$Result = @()
$groups | ForEach-Object {
$group = $_
$Owners = Get-AzureADGroupOwner -ObjectId $group.ObjectId |select DisplayName
$Result += New-Object PSObject -property @{ 
GroupName = $group.DisplayName
Owners = $Owners.DisplayName -join ","
}
}
$Result | Select GroupName,Owners
Note: The command Get-AzureADGroupOwner lists only owners of security groups and it will not list mail-enabled security group owners. We can use the Exchange Online powershell cmdlet Get-DistributionGroup to get owners of mail enabled groups.
Get-DistributionGroup -Identity "MailSecGroup" | Select DisplayName,ManagedBy
List owners of all mail-enabled groups :
Get-DistributionGroup -RecipientTypeDetails MailUniversalSecurityGroup | Select DisplayName,ManagedBy

Export members of all security groups:

We can use the command Get-AzureADGroupMember to retrieve members of an Azure AD group.
$group = Get-AzureADGroup -SearchString "TestSecurityGroup"
Get-AzureADGroupMember -ObjectId $group.ObjectId |select DisplayName, UserPrincipalName
You can use the below command to list members of all security groups.
$groups = Get-AzureADGroup -Filter "SecurityEnabled eq true"
$Result = @()
$groups | ForEach-Object {
$group = $_
Get-AzureADGroupMember -ObjectId $group.ObjectId | ForEach-Object {
$member = $_
$Result += New-Object PSObject -property @{ 
GroupName = $group.DisplayName
Member = $member.DisplayName
UserPrincipalName = $member.UserPrincipalName
}
}
}
$Result | Select GroupName,Member,UserPrincipalName
You can export the result to CSV file using the command Export-CSV.
$Result | Export-CSV "C:\\Security-Group-Members.csv" -NoTypeInformation -Encoding UTF8

Friday, 24 May 2019

How to get Password Last Set time for Azure AD Users

There are two easy ways to retrieve Office 365 User properties, Azure AD Powershell module and Microsoft Graph API. Initially Microsoft released SOAP based MSOnline powershell module (Azure AD v1) to work with Office 365 users, later they introduced the new Graph API based Azure AD v2 powershell module which still requires more improvement and some of the important features are still not available in this new module which are available in old module (MSOnline). The user attribute LastPasswordChangeTimestamp is one of the missed feature in new module.

List all Office 365 users last password change date :

Before proceed run the below command to connect MSOnline module.
Connect-MsolService
You can run the below command to retrieve PwdLastSet value for all Azure AD users.
Get-MsolUser -All | Select DisplayName,UserPrincipalName,LastPasswordChangeTimeStamp
Use the below command to list all users who has changed password more than 90 days before.
Get-MsolUser -All | Where {$_.LastPasswordChangeTimeStamp –lt ([System.DateTime]::Now).AddDays(-90)}|
Sort-Object LastPasswordChangeTimeStamp -Descending | Select DisplayName,LastPasswordChangeTimeStamp
Use the below command to export this details to a CSV file:
Get-MsolUser -All | Select DisplayName,UserPrincipalName,LastPasswordChangeTimeStamp | 
Export-CSV "C:\\LastPasswordChangeInfo.csv" -NoTypeInformation -Encoding UTF8
Note: As already said we can't extract password last set time using the Azure AD v2 module (Get-AzureADUser) and also it is not supported in Microsoft Graph API (https://graph.microsoft.com/v1.0/users).

How to store and read user credentials from Windows Credentials manager

I have got a need to store my credentials in Windows Credentials manager and get the stored username and password to use in a Powershell script which is used in unattended scheduled task. While exploring I have noticed some people used the command Get-StoredCredential. After seeing this command name, I thought this is a built-in Powershell command and used it in my script, but I got the error "The term 'Get-StoredCredential' is not recognized as the name of a cmdlet" while running my script.

After exploring some more time found that this cmdlet is not a built-in command and comes under the Powershell module CredentialManager. So we need to install this module before using the commands New-StoredCredential and Get-StoredCredential.
Install-Module -Name CredentialManager
Run the below command to store credentials in Windows Credentials manager.
New-StoredCredential -Target "MyPSUserInfo" -UserName "username" -Password "mypwd"
You can read the stored user credential from Windows Credentials manager using below command.
$psCred = Get-StoredCredential -Target "MyPSUserInfo"
------ Use $psCred object with your command ------
Connect-MSolService -Credential $psCred

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

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

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.

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

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

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++
}

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

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

Tuesday, 5 February 2019

Find and Export Disabled Office 365 Users using Powershell

In this post, I am going share powershell commands to find the list of disabled or sign-in blocked Azure AD users and export them to CSV file. We can use the Azure AD Powershell command Get-AzureADUser to get user details and this command includes the property AccountEnabled which indicates the user account status.

Before proceed install Azure Active Directory PowerShell for Graph module and run the below command to connect Azure AD PowerShell module:
Connect-AzureAD
The below command checks the given user account is enabled or disable.
$user = "username@o365domain.com"
$accountEnabled = (Get-AzureADUser -ObjectId $user).AccountEnabled
If ($accountEnabled) {
Write-Host "$user : account enabled" -foreground Green
} Else {
Write-Host "$user : account disabled" -foreground Red
}

Find and List All Disabled Office 365 Users :

Get-AzureADUser -All $True | Where-Object { $_.AccountEnabled -eq $false}

Export Disabled Users to CSV file :

Get-AzureADUser -All $True | Where-Object { $_.AccountEnabled -eq $false} |
Select-Object UserPrincipalName, DisplayName |
Export-CSV "C:\\DisabledO365Users.csv" -NoTypeInformation -Encoding UTF8

Monday, 21 January 2019

Set Language and TimeZone in Office 365 Mailboxes using Powershell

Mailbox users can easily change their regional settings from Outlook Web App (OWA). But in some scenarios, we may need to change language and time zone settings for bulk mailboxes. We can use the exchange powershell cmdlet Set-MailboxRegionalConfiguration to set mailbox regional configuration. We can also use the same command for Exchange on-premise mailbox.

Before proceeding 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
Run the below command to set the language “German” and time zone “W. Europe Standard Time”.
Set-MailboxRegionalConfiguration -Identity "alexw@contoso.com" -Language 1031 -TimeZone "W. Europe Standard Time" -DateFormat "dd.MM.yyyy" -TimeFormat "HH:mm"
You can get the required language id from this source: Language Locale ID Values and you can get the time zone name from this source: Time Zone Values.

You can retrieve the existing regional configuration by running below command.
Get-MailboxRegionalConfiguration -Identity "alexw@contoso.com"
You can also set language and time zone values individually.
Set-MailboxRegionalConfiguration -Identity "alexw@contoso.com" -TimeZone "W. Europe Standard Time"
Set-MailboxRegionalConfiguration -Identity "alexw@contoso.com" -Language 1031 -DateFormat "dd.MM.yyyy" -TimeFormat "HH:mm"
You have to set supported date format for the corresponding language. When you set the language without date time format, you will get the error like 'DateFormat "M/d/yyyy" isn't valid for current language setting "de-DE"' if the existing date time format do not support the new language setting.

Set Regional Configuration for all Mailboxes:

Get-Mailbox -ResultSize Unlimited | Set-MailboxRegionalConfiguration -Language en-US -TimeZone "Pacific Standard Time" -DateFormat  "M/d/yyyy" -TimeFormat "h:mm tt"

Set language and time zone for multiple users from CSV:

Use the below powershell commands to set regional settings for bulk office 365 mailbox users by importing users from CSV file. Consider the CSV file MailBoxUsers.csv which contains set of mailbox users with the csv column headers UserPrincipalName, TimeZone, Language, DateFormat and TimeFormat.
Import-Csv 'C:\MailboxUsers.csv' | ForEach-Object {
$mailbox = $_."UserPrincipalName"
$language = $_."Language" # Use language code (Ex: de-DE) as input. don't use language id here.
$timeZone = $_."TimeZone"
Set-MailboxRegionalConfiguration -Identity $mailbox -Language $language -TimeZone $timeZone -DateFormat $_."DateFormat" -TimeFormat $_."TimeFormat"
}
You can list regional config of all mailboxes by running below command.
Get-Mailbox -ResultSize Unlimited | Get-MailboxRegionalConfiguration
You can also export the results to csv file by running below command.
Get-Mailbox -ResultSize Unlimited | Get-MailboxRegionalConfiguration | Export-CSV "C:\\Mailbox-Regional-Configs.csv" -NoTypeInformation -Encoding UTF8
Note: Setting regional settings through powershell will not reflect immediately in all services, it may takes few mins to hours to sync in all services.

Saturday, 19 January 2019

Set up Manager for Office 365 Users

Every organization should have a hierarchy set up for their employees to run day-to-day to work smoothly. Office 365 introducing many advanced features (ex: Office 365 Groups, Flow, Planner ,Teams, and etc.) to reduce the hurdles in collaboration and communication between employees and their manager. So, setting up manager for users is important to use advanced features like Flow and Workflow.

In this post, we are going to explain how to update manager field for Azure AD users by following three different ways.

Set Manager via Exchange Online Admin center

You can follow the below steps to set a manager in required mailbox user through Exchange Online Admin center.
  • Go to Office 365 Admin center.
  • In the left navigation, expand Admin centers, and then select Exchange.
  • In the Exchange Administration Center (EAC), navigate to recipients > mailboxes.
  • Select required user to update manager field and then click on Edit icon.
  • In Edit Uer Mailbox popup, go to organization tab and you can set manager field as shown in below image.
Add manager from Exchange Admin Center

Set Manager via Azure AD portal

Follow the below steps to configure manager from Azure AD Portal.
  • Go to Azure AD Portal.
  • In the left navigation, click Azure Active Directory and click Users.
  • Select (click on user name hyperlink) required user, click on Edit under Job info section and then add or remove manager field as shown in below image.
Add or Remove manager from office 365 user in Azure AD Portal

Set or Remove Manager using PowerShell

Powershell is always a good tool for Administrators to manager Azure Ad objects. We can use the Azure AD powershell cmdlet Set-AzureADUserManager to set manager field and Remove-AzureADUserManager to remove manager.

Before proceed install Azure Active Directory PowerShell for Graph and run the below command to connect Azure AD PowerShell module:
Connect-AzureAD
You can run following command to add manager after replacing required user’s and manager’s UPN or ObjectId.
$User  = "username@domain.com"
$Manager  = "managername@domain.com"
$ManagerObj = Get-AzureADUser -ObjectId $Manager
Set-AzureADUserManager -ObjectId $User -RefObjectId $ManagerObj.ObjectId
You can run following command to remove or clear manager field.
Remove-AzureADUserManager -ObjectId "username@domain.com"
You can check and get users' existing manager value by running following command.
Get-AzureADUserManager -ObjectId "username@domain.com"
Note: Setting up manager field in one place does not immediately reflect in other places or in Delve and you have to wait few mins to hours for a full crawl of Active Directory by the SharePoint User Profiles.