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