Saturday, 10 August 2019

Move SharePoint Online Sites using Powershell

You can now swap your SharePoint Online site with another site using the Invoke-SPOSiteSwap Powershell cmdlet. When the swap is initiated, the target site is moved to the archive location and the source site is moved to the target location.

To use this new cmdlet, you need to use SharePoint Online Powershell version 16.0.8812.1200 or later (Download Link: https://www.microsoft.com/en-us/download/details.aspx?id=35588). You can install the latest SPO Powershell by running below command.
Install-Module -Name Microsoft.Online.SharePoint.PowerShell -MinimumVersion "16.0.8812.1200"

Current Limitations :

  • The target site can only be the root site (https://tenant-name.sharepoint.com) or the search center (https://tenant-name.sharepoint.com/search.).
  • The source or target sites can't be associated with an Office 365 Group (team) or a hub site. If the site is a associated to a hub site, you can remove the association, perform the swap and then re enable the association.
  • If the target is the root site at https://tenant-name.sharepoint.com then the source site must be either a Team Site (STS#0), a Modern Team Site (STS#3), or a Communication Site (SITEPAGEPUBLISHING#0).
  • If the target is the search center site at https://tenant-name.sharepoint.com/search then the source site must be either a Search Center Site (SRCHCEN#0) or a Basic Search Center Site (SRCHCENTERLITE#0).
The below commands archives the existing root site and moves the CommunicationSite to root site.
Connect-SPOService -Url "https://<tenant-name>-admin.sharepoint.com"
$SourceSite = "https://<tenant-name>.sharepoint.com/sites/CommunicationSite"
$TargetSite = "https://<tenant-name>.sharepoint.com"
$AcrhiveSite = "https://<tenant-name>.sharepoint.com/sites/Archive"
Invoke-SPOSiteSwap -SourceUrl $SourceSite -TargetUrl $TargetSite -ArchiveUrl $AcrhiveSite
Note: Before proceed replace the parameter "<tenant-name>" with your tenant name in commands.

You can refer this post for more details.

Monday, 5 August 2019

Get Microsoft Graph API Access Token using ClientID and ClientSecret

In some cases, apps or users might want to acquire Microsoft Graph access token by using the ClientID (Azure AD Application ID) and ClientSecret instead of providing their own credentials. In many cases, these are background services or automation jobs which require to authenticate a script without user interaction (Unattended Authentication). I would also recommend you to read the post Get access without a user.

Note: Assume that you have already registered an App in Azure AD through App Registration and you have the Client ID, Client Secret, and your Tenant Domain Name (or Tenant ID).

Required Parameters :

  • ClientID - AppId of your Azure AD Application.
  • ClientSecret - A secret code that you get from the registered app.
  • Tenant - Provide your tenant id or tenant domain name (ex: xxxxx.onmicrosoft.com). Refer this post to find your tenant id.

Get Access Token :

In the OAuth 2.0 client credentials grant flow, you can acquire an access token by sending a POST request to the /token identity platform endpoint with required parameters :
Http Method : POST
Endpoint URL : https://login.microsoftonline.com/Tenant/oauth2/v2.0/token
Content-Type : application/x-www-form-urlencoded
Body : scope=https://graph.microsoft.com/.default&grant_type=client_credentials&client_id=535fb089-9ff3-47b6-9bfb-4f1264799865&client_secret=qWgdYAmab0YSkuL1qKv5bPX

Get Graph Access Token Using Powershell :

In Powershell, you can use the Invoke-RestMethod cmdlet to send the post request to the /token identity endpoint. Use the below commands after replacing your own values for ClientID, ClientSecret and TenantId.
#This is the ClientID (Application ID) of registered AzureAD App
$ClientID = "535fb089-9ff3-47b6-9bfb-4f1264799865"
#This is the key of the registered AzureAD app
$ClientSecret = "qWgdYAmab0YSkuL1qKv5bPX"
#This is your Office 365 Tenant Domain Name or Tenant Id
$TenantId = "m365xxxxx.onmicrosoft.com"
#$TenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$Body = @{client_id=$ClientID;client_secret=$ClientSecret;grant_type="client_credentials";scope="https://graph.microsoft.com/.default";}
$OAuthReq = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token -Body $Body
$TokenType = $OAuthReq.token_type
$AccessToken = $OAuthReq.access_token

Call Graph API Using Powershell :

The below command retrieves all the Azure AD user details by passing the acquired access token.
$apiUrl = "https://graph.microsoft.com/v1.0/users"
$users = Invoke-RestMethod -Headers @{Authorization = "Bearer $AccessToken"} -Uri $apiUrl -Method Get
Note : Before using the above end-point (https://graph.microsoft.com/v1.0/users), you should have added the Application permission User.Read.All (or User.ReadWrite.All) in your Azure AD app and you should have already provided Admin consent for your app.

Fix - AADSTS90002: Tenant 'xxxxxx' not found. This may happen if there are no active subscriptions for the tenant.

Problem :

Recieived the below error when I try to get Microsoft Graph access token with my Azure AD Application using OAuth 2.0 client credentials grant flow.
Token identity endpoint URL : https://login.microsoftonline.com/xxxxxx/oauth2/v2.0/token

"error":"invalid_request","error_description":"AADSTS90002: Tenant 'xxxxxx' not found. This
may happen if there are no active subscriptions for the tenant. Check with your subscription administrator

Fix/Solution :

We need to provide either TenantID (Guid) or Tenant DomainName (ex: xxxxx.onmicrosoft.com) in token identity endpoint URL to get access token. But in my case, I have just provided tenant name alone instead of tenant domain name/tenantId, the problem solved after providing complete tenant domain name.
#Token endpoint URL with tenant domain name
https://login.microsoftonline.com/xxxxxx.onmicrosoft.com/oauth2/v2.0/token

#Token endpoint URL with tenant id (guid)
Token identity endpoint URL : https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/v2.0/token
To find your tenant id, you can refer this post : How to find your Office 365 Tenant ID

How to find your Office 365 Tenant ID

Office 365 Tenant ID is a globally unique identifier (GUID) value for your Azure AD Tenant. You can find your Tenant ID in the following methods.

1. From Azure AD Portal

You can find your tenant ID in the Azure AD portal if you have Azure AD administrator privilege.
  • Log in to Azure AD Portal (https://portal.azure.com).
  • In the Azure portal, click Azure Active Directory in the left-side navigation box.
  • Under Manage, click Properties. You can retrieve the tenant id from the Directory ID box.
How to retrieve your Office 365 Tenant ID


2. Use Azure AD PowerShell

If you have already installed Azure AD Powershell V2 module, then you can get TenantId while running the Connect-AzureAD cmdlet.
PS C:\> Connect-AzureAD | FL

Account      : UserName@DomainName.onmicrosoft.com
Environment  : AzureCloud
Tenant       : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
TenantId     : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
TenantDomain : DomainName.onmicrosoft.com

3. Use Azure CLI

If you have Azure CLI setup, you can run the command "azure account show" to get your tenant id.
$ azure account show

data:    Name                        : Subscription Name
data:    ID                          : yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
data:    State                       : Enabled
data:    Tenant ID                   : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
data:    Is Default                  : true
data:    Environment                 : AzureCloud
data:    Has Certificate             : No
data:    Has Access Token            : Yes
data:    User name                   : kevin@xxxxxxx.onmicrosoft.com
You can fine tune the result by running below commands.
azure account show --json | jq -r '.[0].tenantId'

or 

az account show --subscription a... | jq -r '.tenantId'
az account list | jq -r '.[].tenantId'

Related Posts :

Wednesday, 31 July 2019

Get all Public Folders and Permissions using Powershell

You can get a list of all public folders with the Exchange powershell cmdlet Get-PublicFolder and you can easily extract the permissions applied to the public folder by using the Get-PublicFolderClientPermission cmdlet.

Before proceed run the below commands to connect Exchange Online (EXO) powershell.
$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 list all the public folders in your organization.
Get-PublicFolder -Recurse -ResultSize Unlimited
The below command returns the specific folder "Support" and all the sub-folders located under this folder.
Get-PublicFolder -Identity "\Support" -Recurse -ResultSize Unlimited
The below command list only first level sub-folders alone.
Get-PublicFolder -Identity "\Support" -GetChildren -ResultSize Unlimited
Run the below command to list the applied permissions in a public folder.
Get-PublicFolderClientPermission -Identity "\Support" | Select User, AccessRights
The below command returns all the folders and the permissions applied to each folder.
Get-PublicFolder -Recurse | Get-PublicFolderClientPermission | Select Identity, User, AccessRights

Export all Public Folder Permissions

The below commands fetch all folders and permissions applied to the folders and export the result to CSV file.
$Result=@()
$allFolders = Get-PublicFolder -Recurse -ResultSize Unlimited
$totalfolders = $allFolders.Count
$i = 1 
$allFolders | ForEach-Object {
$folder = $_
Write-Progress -activity "Processing $folder" -status "$i out of $totalfolders completed"
$folderPerms = Get-PublicFolderClientPermission -Identity $folder.Identity
$folderPerms | ForEach-Object {
$Result += New-Object PSObject -property @{ 
Folder = $folder.Identity
User = $_.User
Permissions = $_.AccessRights
}}
$i++
}
$Result | Select Folder, User, Permissions |
Export-CSV "C:\\PublicFolderPermissions.CSV" -NoTypeInformation -Encoding UTF8

Thursday, 25 July 2019

Create a new public folder in Office 365 using Powershell

Public folders are used to share information and collaborate with other people in your organization. Once the admin enables public folders they are automatically shown in all users' Outlook client. The content is organized in a hierarchy which makes browsing very easier for users.

Things To Know Before Proceed :

  • Public folder content can include email messages, posts, documents, and eForms.
  • Public folder architecture uses specially designed mailboxes (Public folder mailbox) to store both the public folder hierarchy (folder structure) and the content.
  • Before creating a public folder, you must first create a public folder mailbox.
  • There are two types of public folder mailboxes: the primary hierarchy mailbox and secondary hierarchy mailboxes. Both types of mailboxes can contain content.
  • Primary hierarchy mailbox: The first public folder mailbox you create will be the primary hierarchy mailbox in your organization. This is the only mailbox containing a writable (read/write) copy of the public folder structure. The public folder hierarchy is copied to all other public folder mailboxes, but these will be read-only copies.
  • Secondary hierarchy mailboxes: Any additional public folder mailboxes you create will be secondary mailboxes. The secondary hierarchy mailboxes contain public folder content and a read-only copy of the public folder hierarchy.

Create a new public folder mailbox using Powershell

We can use the New-Mailbox cmdlet to create a public folder mailbox. Before proceed run the below commands to connect Exchange Online (EXO) powershell.
$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 first mailbox you create will be the primary hierarchy mailbox in your organization.
New-Mailbox -PublicFolder -Name "Master-PFM"
Once you created a public folder mailbox (primary), any additional public folder mailboxes you create will be secondary mailboxes.
New-Mailbox -PublicFolder -Name "PFM2"
You can get your primary public folder mailbox by running the following command.
Get-OrganizationConfig | Format-List RootPublicFolderMailbox

Create a new public folder using Powershell

Once you created required public folder mailbox, you can use the New-PublicFolder cmdlet to create a public folder. The below command creates the public folder Support in the root of the public folder.
New-PublicFolder -Name "Support"
The below command creates the public folder Product1 under the existing folder \Support.
New-PublicFolder -Name "Product1" -Path "\Support"
The below command creates the public folder FAQs under the existing folder \Support\Product1.
New-PublicFolder -Name "FAQs" -Path "\Support\Product1"
The below command creates the public folder Marketing in the specific mailbox PFM2.
New-PublicFolder -Name "Marketing" -Mailbox "PFM2"

Tuesday, 23 July 2019

Fix : The query cannot be completed because the number of lookup columns exceeds the threshold limit

Problem

You might have received the below error when you use SharePoint Rest API to retrieve list items.
Code: Microsoft.SharePoint.SPQueryThrottledException
Message: "The query cannot be completed because the number of lookup columns it contains exceeds the lookup column threshold enforced by the administrator."
In my case I have received the same error for the following queries :
https://Tenant.sharepoint.com/sites/MySite/_api/web/lists/getByTitle('MyList')/items?$select=*

https://Tenant.sharepoint.com/sites/MySite/_api/web/lists/getByTitle('MyList')/items

Cause

As error message clearly indicates, this problem occurs since the problematic list contains lookup columns more than the List View Lookup Threshold limit. In SharePoint On-premises, the List View Lookup Threshold default limit is 8 and it can be changed on the Resource Throttling page in Central Administration. In SharePoint Online, this limit is 12 lookup columns and increasing the List View Threshold is not supported in SharePoint Online.

What columns are classified as Lookup columns

The following column types are classified as lookup columns: (Source: List view Lookup threshold uncovered)
  • Standard lookup columns
  • Managed metadata (single and multi-value)
  • People and group (single and multi-value)
  • Workflow status Created by (people and group)
  • Modified by (people and group)
Additionally following columns shows on list view also work as lookup columns : Name ( linked to Document) , Link (Edit to edit item) , Name ( linked to Document with edit menu), type ( icon linked to document).

Workaround

In Rest API, you can fix this problem by limiting the number columns to be returned using Select option. If you do not use the select option (or if you use select=*), then the rest query try to retrieve all fields, so you can limit the columns by providing only required columns in select option.
https://Tenant.sharepoint.com/sites/MySite/_api/web/lists/getByTitle('MyList')/items?$select=Title,Id
Note : Your select query should not include more than 12 (List View Lookup Threshold) lookup columns.

You can apply the same workaround if you face the issue in Microsoft Flow and PowerApps. For SharePoint views, you can just modify your view to list only required columns so that there will be no more than 12 lookup columns inside your view.

Monday, 22 July 2019

Fix : Connect-SPOService : Could not authenticate to SharePoint Online using OAuth 2.0

Problem :

You might have received the below error when you try to connect SPO site using Connect-SPOService cmdlet.
Connect-SPOService : Could not authenticate to SharePoint Online https://TenantName.sharepoint.com/sites/SiteName
using OAuth 2.0
At line:1 char:1
+ Connect-SPOService -Url https://TenantName.sharepoint.com/sites/SiteName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Connect-SPOService], AuthenticationException
    + FullyQualifiedErrorId : Microsoft.Online.SharePoint.PowerShell.AuthenticationException,Microsoft.Online.SharePoi
   nt.PowerShell.ConnectSPOService

Fix/Soution:

In my case, I have provided my site URL as opposed to my SharePoint Admin Site URL. The URL parameter of Connect-SPOService cmdlet accepts only the URL of SharePoint Online Administration Center site. My problem solved after providing Admin site URL.
Connect-SPOService -url https://TenantName-admin.sharepoint.com
If you face the problem even with Admin site URL, then pass the -Credential parameter to bypass ADAL/Modern authentication and use legacy authentication.
$PSCred = Get-Credential
Connect-SPOService -url https://TenantName-admin.sharepoint.com -Credential $PSCred
Note: The legacy authentication will not work MFA enabled user account.

If you still face the issue, try to re-install the SPO Powershell module, reboot machine and check the case again.

Sunday, 21 July 2019

Fix : Connect-SPOService : Current site is not a tenant administration site

Problem :

You might have received the below error when you try to connect your SharePoint Online site using Connect-SPOService cmdlet.
Connect-SPOService : Current site is not a tenant administration site.
At line:1 char:1
+ Connect-SPOService -Url https://TenantName.sharepoint.com/sites/SiteName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Connect-SPOService], ServerException
    + FullyQualifiedErrorId : Microsoft.SharePoint.Client.ServerException,Microsoft.Online.SharePoint.PowerShell.Conne
   ctSPOService

Fix/Soution:

The URL parameter of the Connect-SPOService cmdlet accepts only the url of SharePoint Online Administration Center site. To work with any of your site using SharePoint Online PowerShell module, you have to first establish a connection with SPO tenant site which is the admin site of your SharePoint tenant in Office 365, once this connection is established you can access any SPOSite using Get-SPOSite cmdlet.
Connect-SPOService -Url https://TenantName-admin.sharepoint.com
Once you connected your Admin site, you can get your required SPO site details using the below command.
Get-SPOSite -Identity https://TenantName.sharepoint.com/sites/SiteName
You can set required details in SPO site using the below command
Set-SPOSite -Identity https://TenantName.sharepoint.com/sites/SiteName -Owner username@domain.com -NoWait
For more details read How to Connect SharePoint Online PowerShell Module.

Saturday, 20 July 2019

Get a list of all Azure AD Integrated Applications using Powershell

In this post, I am going to share powershell script to find and retrieve the list of Azure AD Integrated apps (Enterprise Applications) with their API permissions and users who are authorized to use the app. In Azure AD, the integrated apps or Enterprise applications are nothing but an instance (ServicePrincipal object) or mirror of the apps (Application object) which are generally published in other company tenants (or in your own tenant). We can use the Get-AzureADServicePrincipal cmdlet to fetch all the integrated apps.

Before proceed install Azure AD Powershell Module V2 and run the below command to connect the Powershell module:
Connect-AzureAD
By default the Get-AzureADServicePrincipal cmdlet returns all the service principal objects, we can filter the result by using the Tags property to list only integrated applications.
Get-AzureADServicePrincipal -All:$true | ? {$_.Tags -eq "WindowsAzureActiveDirectoryIntegratedApp"}
The below command returns limited fields alone.
Get-AzureADServicePrincipal -All:$true |?{$_.Tags -eq "WindowsAzureActiveDirectoryIntegratedApp"}|
Select-Object ObjectId,AppDisplayName,AppId,PublisherName
  • ObjectId - This is the unique id for the service principal object (ServicePrincipalId). We need to use this id to get resources related to the service principal object.
  • AppDisplayName - Name of the Application.
  • AppId - The id of the Application. The AppId is unique across all related Azure AD objects (Application object and ServicePrincipal object). If you are the owner or the app registered in your tenant, then you can use the Get-AzureADApplication cmdlet to get the registered apps (Application objects).This id will be used as ClientId while acquiring access token to access resources.

Get the list of Delegated permissions granted to the application

We can use the Get-AzureADServicePrincipalOAuth2PermissionGrant cmdlet to fetch OAuth delegated permissions which have been granted to the application either by end-user (User Consent) or Admin user (Admin Consent).
#$ServicePrincipalId = (Get-AzureADServicePrincipal -Top 1).ObjectId
#Provide ObjectId of your service principal object
$ServicePrincipalId = "5614c8c4-22bb-45c7-9be3-47491152703d"
Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId $ServicePrincipalId | FL
This command gets an oAuth2PermissionGrant object and it includes the following fields.
  • ClientId - The id of the service principal object.
  • ConsentType - Indicates if consent was provided by the administrator (on behalf of the organization) or by an individual. The possible values are AllPrincipals or Principal.
  • ObjectId - Unique id for this object.
  • PrincipalId - If ConsentType is AllPrincipals this value is null, and the consent applies to all users in the organization. If ConsentType is Principal, then this property specifies the id of the user that granted consent and applies only for that user. You can use this id with Get-AzureADUser cmdlet to get the user data.
  • ResourceId - Specifies the id of the resource service principal to which access has been granted.
  • Scope - Specifies the value of the scope claim that the resource application should expect in the OAuth 2.0 access token. For example, User.Read.

Get the list of Application permissions granted to the application

The Get-AzureADServicePrincipalOAuth2PermissionGrant cmdlet retrieves all delegated permissions for a service principal object, but you can't use this command to retrieve the application permissions. Application permission assignments are represented as AppRoleAssignments in the directory, you can use the Get-AzureADServiceAppRoleAssignedTo cmdlet to list what application permissions (AppRoleAssignment) have been assigned to the service principal object.
$AppPermissions =@()
$ResourceAppHash = @{}
#Provide ObjectId of your service principal object
$ServicePrincipalId = "5614c8c4-22bb-45c7-9be3-47491152703d"
$AppRoleAssignments = Get-AzureADServiceAppRoleAssignedTo -ObjectId $ServicePrincipalId
$AppRoleAssignments | ForEach-Object {
$RoleAssignment = $_
$AppRoles = {}
If ($ResourceAppHash.ContainsKey($RoleAssignment.ResourceId)) {
$AppRoles = $ResourceAppHash[$RoleAssignment.ResourceId]
} Else {
$AppRoles = (Get-AzureADServicePrincipal -ObjectId $RoleAssignment.ResourceId).AppRoles
#Store AppRoles to re-use.
#Probably all role assignments use the same resource (Ex: Microsoft Graph).
$ResourceAppHash[$RoleAssignment.ResourceId] = $AppRoles
}
$AppliedRole = $AppRoles | Where-Object {$_.Id -eq $RoleAssignment.Id}  
$AppPermissions += New-Object PSObject -property @{
DisplayName = $AppliedRole.DisplayName
Roles = $AppliedRole.Value
Description = $AppliedRole.Description
IsEnabled = $AppliedRole.IsEnabled
ResourceName = $RoleAssignment.ResourceDisplayName
}
}
$AppPermissions | FL

Get users who are associated with the application

You can get the list of users who are involved with the application by using the Get-AzureADServiceAppRoleAssignment cmdlet.
#Provide ObjectId of your service principal object
$ServicePrincipalId = "5614c8c4-22bb-45c7-9be3-47491152703d"
Get-AzureADServiceAppRoleAssignment -ObjectId $ServicePrincipalId | Select ResourceDisplayName,PrincipalDisplayName

Wednesday, 17 July 2019

Fix : BadRequest - Invalid value specified for property 'mailNickname' of resource 'User'

Problem:

You might have received the error "Invalid value specified for property 'mailNickname' of resource 'User'" error when you create a new Azure AD user.

Cause/Solution:

As the error message indicates the provided mail alias name is not in correct format or it includes invalid special characters. So try the below cases to fix this problem.
  • Remove white spaces in mailNickname (mail alias, email address).
  • Remove special characters in mailNickname (Ex: Space and "(),:;<>@[\]).

Valid and Invalid characters in mailNickname/mailAlias:

The mailNickname or mail alias of the email address may use any of these ASCII characters RFC 5322 Section 3.2.3:
  • Uppercase and lowercase English letters (a–z, A–Z) (ASCII: 65-90, 97-122) - Digits 0 to 9 (ASCII: 48-57).
  • Characters !#$%&'*+-/=?^_`{|}~ (ASCII: 33, 35-39, 42, 43, 45, 47, 61, 63, 94-96, 123-126).
  • Character . (dot, period, full stop) (ASCII: 46) provided that it is not the first or last character, and provided also that it does not appear two or more times consecutively (e.g. John..Doe@example.com is not allowed.).

Special characters with restrictions:

Special characters are allowed with restrictions. They are: - Space and "(),:;<>@[\] (ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91-93).

The restrictions for special characters are that they must only be used when contained between quotation marks, and that 3 of them (The space, backslash \ and quotation mark " (ASCII: 32, 92, 34)) must also be preceded by a backslash \ (e.g. "\ \\\"").

Note : You can also apply the same fix for group creation issue (group mail alias issue) - Invalid value specified for property 'mailNickname' of resource 'Group'.

Source : What are valid and invalid email address characters

Monday, 15 July 2019

Difference between App Registration and Enterprise Application in Azure AD

Applications that are registered through Azure Portal (or programmatically) in your Azure Tenant is App Registration apps or Home Tenant Apps. Enterprise Applications are generally registered at another tenant (the one their publisher uses), when you consume the other tenant apps your Azure AD instance just provides service principal object for this app in your directory, and adds required permissions to the service principal object, and then assigns users.

When you create the App Registration (Application) in your tenant, it will create an Application object in your tenant directory. Then when another tenant user wants to consume your app, they login and grant required permissions for your app and the Enterprise Application (Service Principal) is created in their tenant. This service principal object effectively mirrors your application in their tenant.

App Registration (Application):

  • Your own Applications that are registered in App registrations.
  • When you create a new app in your tenant, it will create an Application object in your tenant directory.
  • Registered or Owned Apps.
  • You can change Reply URL for this app as it registered and owned by you.
  • You can use the Get-AzureADApplication cmdlet to list all the registered apps.
Get-AzureADApplication -All:$true
#Web Apps
Get-AzureADApplication -All:$true | Where-Object { $_.PublicClient -ne $true } | FT
#Native Client (Desktop/Mobile device) Apps
Get-AzureADApplication -All:$true | Where-Object { $_.PublicClient -eq $true } | FT

Enterprise Application (Service Principal):

  • Enterprise Applications are Service Principal objects that mirror the apps which are generally published by other companies.
  • When you grant permission for other tenant application to access resources in your tenant (upon registration or consent), a service principal object (Enterprise Application) will be created.
  • You can also grant permission for your own apps which also creates a service principal object in your tenant.
  • Integrated or Consumed Apps.
  • You can't configure Reply URL for the apps that are registered in other company tenants.
  • You can use the Get-AzureADServicePrincipal cmdlet to list all the Enterprise Applications.
Get-AzureADServicePrincipal -All:$true | ? {$_.Tags -eq "WindowsAzureActiveDirectoryIntegratedApp"}

Friday, 12 July 2019

How to find your tenant name in Office 365

You might have heard the terms tenant name and domain name in Office 365 and Azure AD. You may feel both are the same, but this is not correct. When you sign up for Office 365, you will be asked for your organization name (i.e., contoso). Based on this organization name, Azure AD service will allocate a "tenant name" and it will also create a default domain for your tenant, the domain name will be the same as your tenant name, but with the suffix domain ".onmicrosoft.com".

For example, if you have created organization with the name "contoso", then

Your tenant name is : contoso
Default domain name is : contoso.onmicrosoft.com

You can purchase and add custom domains with different names under this domain, but you can't change the tenant name.

Why tenant name is important :

The tenant name will be used in your SharePoint and OneDrive Site URL.
SharePoint URL : https://tenant_name.sharepoint.com
SPO Site URL : https://tenant_name.sharepoint.com/sites/site_name
SPO Admin Site URL : https://tenant_name-admin.sharepoint.com/
OneDrive URL : https://tenant_name-my.sharepoint.com/personal/username_domain_com/_layouts/15/onedrive.aspx
So if you planned to use these services, then you have to carefully choose your organization name. For example, if you chose "contoso" as your organization name during Office 365 signup, then contoso will become your "tenant name". Even if you add custom domain "contosotech.com", you cannot change tenant name in your SharePoint URL to "contosotech.sharepoint.com".

How to retrieve your Office 365 tenant name :

As of now (at least when I am writing this post), there is no direct Graph API or Powershell support to get this property. But you can extract this value from other properties, i.e., SharePoint URL, OneDrive URL and License SKU name.

From OneDrive Site URL :

Open your OneDrive for Business site in a web browser and your browser URL will look like below URL. The first part of the URL before -my.sharepoint is tenant name.
https://tenant_name-my.sharepoint.com/personal/username_domain_com/_layouts/15/onedrive.aspx
How to find your tenant name from OneDrive URL


From SharePoint Site URL :

Open one of your SharePoint Online site in a web browser and your browser URL will look like below URL. Here the first part of the URL before .sharepoint is tenant name.
https://tenant_name.sharepoint.com/sites/site_name
How to find my tenant name from SharePoint Site URL


From License SKU ID using Powershell:

The license SKU names are prefixed with your tenant name, so you can list the available license SKUs by running the Get-MsolAccountSku cmdlet and the first part of the AccountSkuID is the tenantname.

Open Powershell with "Run as administrator" privilege and run the below command to install the MSOnline Powershell module if you have not already installed.
Install-Module MSOnline
Run the below commands to list the available license SKUs.
Connect-MsolService
Get-MsolAccountSku
How to find my tenant name using Powershell

Monday, 8 July 2019

Full Access Mailbox Permissions Report using Powershell

In this post, we will explore how to list users who have full access permission in other users' mailbox. We can use the Exchange Powershell command Get-MailboxPermission to extract assigned permissions from a particular mailbox.

Before proceed connect Exchange Online Powershell module or Exchange Management Shell for On-premise environment.

Run the below command to list specific mailbox permissions
Get-MailboxPermission "Aldo Muller" | Select Identity,User,AccessRights
The above command not only list explicitly assigned full access permissions to a mailbox, it will also list inherited permissions, built-in system groups and the mailbox's SELF access, these extra permissions are unnecessary entries for our current report, so we can filter them using Where logic operation.
Get-MailboxPermission "Aldo Muller" | Where { ($_.IsInherited -eq $False) -and ($_.AccessRights -like "*FullAccess*") -and -not ($_.User -like "NT AUTHORITY\SELF") } |
Select Identity, User, AccessRights
You can also list access rights only for a specific user on a specific mailbox. You can provide the required user account with the parameter -User in Get-MailboxPermission cmdlet.
$Mailbox = "Aldo Muller"
$UserToCheck = "Alex Wilber"
Get-MailboxPermission -Identity $Mailbox -User $UserToCheck | Select Identity,User,AccessRights

List all mailboxes in which a specific user has Full Access permissions

In some scenarios, you may need to extract all mailboxes in which a given user account has full access permission. For this need, first we have to fetch all mailboxes and pipe the result to Get-MailboxPermission cmdlet.
Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission  -User "Alex Wilber" | Select Identity,User,AccessRights

List all mailboxes with Full Access permissions

The below command retrieves mailboxes and users with full access permission.
Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission |
Where { ($_.IsInherited -eq $False) -and ($_.AccessRights -like "*FullAccess*") -and -not ($_.User -like "NT AUTHORITY\SELF") } |
Select-Object @{n="Mailbox"; e={$_.Identity}},@{n="UserHasFullAccess"; e={$_.User}},@{n="Access"; e={$_.AccessRights}} 

Export Result to CSV :

You can export the report to csv file by running below commands.
Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission |
Where { ($_.IsInherited -eq $False) -and ($_.AccessRights -like "*FullAccess*") -and -not ($_.User -like "NT AUTHORITY\SELF") } |
Select-Object @{n="Mailbox"; e={$_.Identity}},@{n="UserHasFullAccess"; e={$_.User}},@{n="Access"; e={$_.AccessRights}}  |
Export-CSV "C:\\FullAccessPermissionsReport.csv" -NoTypeInformation -Encoding UTF8

Thursday, 4 July 2019

Flow Tips: Create Folder In SharePoint Library Using Microsoft Flow

In this post, I am going to explain how to create a new folder under root directory (or sub folder) in a SharePoint document library using Microsoft Flow. You may have this requirement in automatic trigger from some other activity in Office 365 resource, here I have explained with manual trigger, but you can use the same action in your automatic flow trigger by just passing the required parameters.

Required Flow Action

We can use the Send an HTTP request to SharePoint action to create a folder in SharePoint List.

Required Input Parameters

  • Site Address
  • Relative Folder Path 
  • New Folder Name

Create Folder under Root Folder of the Document Library

In my case I am trying to add folder in default document library (Documents) and its root folder name is "Shared Documents".

1. Go to Microsoft Flow page.
2. Select My flows -> click New -> Instant - from blank.
3. Name your flow as "Create Folder" -> choose the trigger option From Microsoft Flow -> click Create.
4. Click Next step -> select SharePoint -> choose the action Send an HTTP request to SharePoint
5. In action parameter box, enter Site Address, select request method as POST, set Uri with your relative root folder path, set relative new folder path in request Body and set Headers.

Site Address : https://YourTenant.sharepoint.com/sites/TestSite
Method : POST

Uri :
_api/web/GetFolderByServerRelativePath(decodedurl='Shared Documents')/Folders
Headers :
accept : application/json;odata=verbose
content-type : application/json;odata=verbose
Body:
{ '__metadata': { 'type': 'SP.Folder' }, 'ServerRelativeUrl': 'Shared Documents/New Folder'}
Create List In SharePoint Library Using Microsoft Flow

Create Folder under Sub Folder of the Document Library

You just need to provide the relative path of your sub folder in Uri and request Body, other parameters are same.

Uri :
_api/web/GetFolderByServerRelativePath(decodedurl='Shared Documents/Sub Folder')/Folders
Body:
{ '__metadata':{ 'type':'SP.Folder' },'ServerRelativeUrl':'Shared Documents/Sub Folder/New Folder'}
Create Sub Folder In Document Library Using Microsoft Flow

Note: Ensure that your Sub Folder was already created, in my testing the flow runs continuously if the sub folder not available in the specified location.

Here I am using default document library (Documents), and its root folder name is "Shared Documents". If you try to create folder in another library (ex: DocumentLib1), then by default your root folder name is same as the library name. In this case you have to provide following parameters.

Uri :
_api/web/GetFolderByServerRelativePath(decodedurl='DocumentLib1')/Folders
Body:
{ '__metadata':{ 'type':'SP.Folder' },'ServerRelativeUrl': 'DocumentLib1/New Folder'}

Wednesday, 3 July 2019

Get Drive Item and List Item by File Name, Path and Guid using Graph API

You might have already known the resources ListItem and File if you have worked with SharePoint files with CSOM. In Graph API, the sharepoint files are represented by another resource DriveItem. The driveItem resource represents a file, folder, or other item stored in a drive. All file system objects in OneDrive and SharePoint are returned as driveItem resources. You can retrieve driveItem resource by following ways.

Get by driveItem unique identifier :

#From SharePoint Online Site
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/items/{itemId}
#From Office 365 Group associated SPO Site
https://graph.microsoft.com/v1.0/groups/{groupId}/drive/items/{itemId}
#From User's OneDrive
https://graph.microsoft.com/v1.0/me/drive/items/{item-id}

By file name :

The below request queries the given file name in root folder alone. If you want to query in sub folder, then you have to provide your folder name in the api url (Refer below example)
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/root:/TestFile.txt
 
https://graph.microsoft.com/v1.0/groups/{groupId}/drive/root:/TestFile.txt

By file system path :

The below request queries the given file name in TestFolder.
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/root:/TestFolder/TestFile.txt
You can refer this post for more details : Get a DriveItem resource

Get ListItem from DriveItem resource :

The driveItem resource includes the extended relationship with ListItem. The below graph api request retrieves the associated document library list item for the corresponding driveItem.
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/items/{itemId}/listItem

Get DriveItem by File ID (Guid) using Graph API :

Using above methods, you can get driveItem resource by file name, file path and drive item id. There may be a requirement to get this driveItem by file's actual guid. This guid will be used with document URL in some cases. Actually I was in the same need with below file URL.
"https://MySPOTenant.sharepoint.com/sites/MySite/_layouts/15/Doc.aspx?sourcedoc={52173197-354A-532K-96BB-D4A5CDA8AF15}&file=TestFile.xlsx&action=default&mobileredirect=true"
Here my need was to find driveItem resource by using its document ID which is available in the document url. We can't able to use this guid with the above endpoint (ex: sites/{siteId}/drive/items/{itemId}), because it supports only drive item unique id. So here my alternative approach is Search endpoint, we can provide this guid in search query and get the associated driveItem resource.
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/root/search(q='52173197-354A-532K-96BB-D4A5CDA8AF15')
Actually searching by file guid will not provide perfect result in some cases, because it searches entire file system metadata, so you may get wrong result if the same guid text available as name of another file. As a work-around, once we get driveItem resource using above request, we can get the associated document library list item by providing driveItem id. The listItem resource includes the property eTag which includes the file guid, you can compare this eTag with file guid to ensure that you have found the correct resource. You can also cross-check the file name to get better result.
#Get the itemId from above search result items
https://graph.microsoft.com/v1.0/sites/{siteId}/drive/items/{itemId}/listItem

#ListItem result snippet 
"@odata.etag": "\"52173197-354A-532K-96BB-D4A5CDA8AF15,3\"",
"createdDateTime": "2019-07-02T12:11:44Z",
"eTag": "\"52173197-354A-532K-96BB-D4A5CDA8AF15,3\"",
Note : I am just sharing this method as a work-around, if you find any mistake or better method, then please post the same in below comments section.

Tuesday, 2 July 2019

AADSTS54005: OAuth2 Authorization code was already redeemed

Problem :

I have been working with application that uses Device Code Flow to authenticate Office 365 user to consume Graph API resources. My code was working fine until today, but unfortunately today I got the below error.
error: "invalid_grant"
error_codes: [54005]
error_description: "AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.

Solution :

As you see, the error message itself is self explanatory message, so I have tried to find the solution in that way. Finally found the real problem is with my code, my recent changes in the code leads to call get token api two times, in first call we are getting valid token, but when we use the same device code in second call, then we are getting the above error message. The problem solved after removing extra call for the get token endpoint with the same code.

Fix for OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token

Monday, 1 July 2019

Upload files to OneDrive for Business site using PowerShell

OneDrive for Business site (ODFB) is built on top of SharePoint Online (SPO). Users' personal OneDrive site is nothing but a special site collection in SharePoint, so if you have enough permission on the required user's OneDrive site, then you can do whatever operations (as like you can do with SPO site) in Powershel with the help of CSOM and SharePoint Online module. In this post, I am going to share CSOM based powershell script to fetch documents from local folder and upload into an user's OneDrive location.

Permissions Required :

By default every users have full access permission on their personal OneDrive site. If you are going to upload in your own drive, then you don't need extra permission. If you are going to upload files into another user's OneDrive, then you should add yourself as a site collection admin of the particular user's OneDrive site. Refer this post for more details : Add Site Collection Admin to OneDrive Users

Required details to upload files into OneDrive document library :

Before proceed you need to replace the following input parameters in below script.

$LocalFolder - Specify your local folder path.
$AdminAccount - Provide admin user account.
$AdminPass - Provide admin password.
$OneDriveURL - User's OneDrive site URL.
$FolderName - OneDrive folder where you want to upload. Leave empty if you want to upload in root folder.
#Add required references to SharePoint client assembly to use CSOM 
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")  

# Specify local folder path
$LocalFolder = "C:\Users\Username\Documents\MyFiles"

# Specify the User account for an Office 365 global admin in your organization
$AdminAccount = "admin@<your tenant name>.onmicrosoft.com"
$AdminPass = "admin_password"

# Specify User's OneDrive Site URL and Folder name
$OneDriveURL = "https://<your tenant name>-my.sharepoint.com/personal/username_domainame_com"
$DocumentLibrary ="Documents"
$FolderName ="" #Leave empty to target root folder

# Connect and Load OneDrive Library and Root Folder
$SecPwd = $(ConvertTo-SecureString $AdminPass -asplaintext -force) 
$Ctx = New-Object Microsoft.SharePoint.Client.ClientContext($OneDriveURL) 
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount,$SecPwd) 
$Ctx.credentials = $Credentials
$List = $Ctx.Web.Lists.GetByTitle("$DocumentLibrary")
$Ctx.Load($List)
$Ctx.Load($List.RootFolder)
$Ctx.ExecuteQuery()
$RootFolderURL = $List.RootFolder.ServerRelativeUrl

#Get files from local folder and Upload into OneDrive folder
$i = 1
$Files = (Dir $LocalFolder -File)
$TotoalFiles = $Files.Length
$Files | ForEach-Object {
Try {
$File = $_
Write-Progress -activity "Uplading $File" -status "$i out of $TotoalFiles completed"
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $File
If($FolderName) {
$targetFolder = $Ctx.Web.GetFolderByServerRelativeUrl($RootFolderURL+"/"+$FolderName)
$Upload = $targetFolder.Files.Add($FileCreationInfo);
} Else {
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
}
$Ctx.Load($Upload)
$Ctx.ExecuteQuery()
} catch {}
$i++
}

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