Wednesday, 15 February 2017

Read Multiple Users Profile Properties From SharePoint Online Using CSOM

This post is follow-up of the article http://www.morgantechspace.com/2016/09/read-sharepoint-user-profile-properties-csom.html, in previous post I have clearly explained about how to read current user profile properties, specific user (other user) properties and how to read only required profile properties using client object model (CSOM). One of our user asked the question "How to get a specific profile property (path to profile picture for example) for all of my Sharepoint's website users in one request", so I am writing this post to help every users.

Summary

Get All Profile Properties for Multiple SharePoint Online Users

In the below C# code, I have passed only list of SharePoint Online users, you can fetch all SharePoint Online users using your own best method and use it in below code. You can read users using Azure AD powershell cmdlet Get-MsolUser or you can fetch from your own csv file.
public static void GetMultipleUsersProfileProperties()
{
    string siteUrl = "https://spotenant-admin.sharepoint.com";

    var passWord = new SecureString();
    foreach (char c in "pass@word1".ToCharArray()) passWord.AppendChar(c);
    var credentials = new SharePointOnlineCredentials("admin@spotenant.onmicrosoft.com", passWord);
           
    // Connect to the sharepoint site client context.
    ClientContext clientContext = new ClientContext(siteUrl);
    clientContext.Credentials = credentials;

    // Get the PeopleManager object.
    PeopleManager peopleManager = new PeopleManager(clientContext);

    // Get multiple users
    List<string> Users = new List<string> { "admin@spotenant.onmicrosoft.com",
"alexw@spotenant.onmicrosoft.com", "benw@spotenant.onmicrosoft.com" };

    var results = new Dictionary<string, PersonProperties>();
    foreach (var user in Users)
    {
        string loginName = "i:0#.f|membership|" + user;  //claim format login name
        var personProperties = peopleManager.GetPropertiesFor(loginName);
        clientContext.Load(personProperties, p => p.AccountName, p => p.DisplayName,
                           p => p.UserProfileProperties);
        results.Add(loginName, personProperties);
    }
    clientContext.ExecuteQuery();

    foreach (var kvp in results)
    {
        if (kvp.Value.ServerObjectIsNull.HasValue && !kvp.Value.ServerObjectIsNull.Value)
        {
            Console.WriteLine(kvp.Value.DisplayName);
            Console.WriteLine("---------------------------------");
            foreach (var property in kvp.Value.UserProfileProperties)
            {
                Console.WriteLine(string.Format("{0}: {1}",
                    property.Key.ToString(), property.Value.ToString()));
            }                    
        }
        else
        {
            Console.WriteLine("User not found:"+kvp.Key);
        }
        Console.WriteLine("------------------------------");
        Console.WriteLine("          ");
    }
}

Get Specific Profile Properties for Multiple SharePoint Online Users

The below csom based C# code read only specific set of properties for set of SharePoint Online users.
public static void GetSpecificProfilePropertiesForAllUsers()
{
    string siteUrl = "https://spotenant-admin.sharepoint.com";

    var passWord = new SecureString();
    foreach (char c in "pass@word1".ToCharArray()) passWord.AppendChar(c);
    var credentials = new SharePointOnlineCredentials("admin@spotenant.onmicrosoft.com", passWord);

    // Connect to the sharepoint site client context.
    ClientContext clientContext = new ClientContext(siteUrl);
    clientContext.Credentials = credentials;

    // Get the PeopleManager object.
    PeopleManager peopleManager = new PeopleManager(clientContext);

    // Get multiple users - you can provide all users by fetching with different service
    // Ex: from Get-MsolUser powershell cmdlet
    List<string> Users = new List<string> { "admin@spotenant.onmicrosoft.com",
"alex2w@spotenant.onmicrosoft.com", "benw@spotenant.onmicrosoft.com" };

    var results = new Dictionary<string, IEnumerable<string>>();
    foreach (var user in Users)
    {
        string loginName = "i:0#.f|membership|" + user;  //claim format login name
        // Retrieve specific properties by using the GetUserProfilePropertiesFor method.  
        string[] profilePropertyNames = new string[] { "PersonalSpace", "PictureURL", "SPS-JobTitle" };
        UserProfilePropertiesForUser profilePropertiesForUser = new UserProfilePropertiesForUser(
            clientContext, loginName, profilePropertyNames);

        IEnumerable<string> profilePropertyValues = peopleManager.GetUserProfilePropertiesFor(profilePropertiesForUser);

        // Load the request for the set of properties. 
        clientContext.Load(profilePropertiesForUser);
        results.Add(loginName, profilePropertyValues);
    }
    clientContext.ExecuteQuery();

    foreach (var kvp in results)
    {
        if (kvp.Value != null && kvp.Value.Count() > 0)
        {
            Console.WriteLine("User :" + kvp.Key);
            // Returned collection contains only property values 
            foreach (var value in kvp.Value)
            {
                Console.WriteLine(value);
            }
        }
        else
        {
            Console.WriteLine("User not found:" + kvp.Key);
        }
    }
}
Read More...

Tuesday, 14 February 2017

Disable AD User based on specific attribute using Powershell

In this article, I am going write powershell script to disable Active Directory user account by using user's specific property like employeeNumber, employeeID, etc...You can disable an ad user account by using the Active Directory powershell cmdlet Disable-ADAccount.
Disable-ADAccount -Identity <adaccount>
The Identity parameter specifies the Active Directory user that you want to disable. You can identify an account by its distinguished name (DN), GUID, security identifier (SID), or samAccountName.

Using the above command, you can not find user by using other AD attributes. So, we need to use another cmdlet Get-ADUser to find user using specific attribute and then we can pipe the result to Disable-ADAccount command to disable.

The following command search an AD user by user's EmployeeID using SQL like filter and disable the user.
Import-Module ActiveDirectory
Get-ADUser -Filter 'employeeID -like "1200547"' | Disable-ADAccount
You can also find an user by using well-known LDAP Filter. The following command find user by LDAP filter using user's EmployeeID and disable the user.
Import-Module ActiveDirectory
Get-ADUser -LDAPFilter '(employeeID=1200547)'  | Disable-ADAccount

Disable Bulk AD Users from CSV by User's EmployeeID

The following powershell script import AD users from csv file and disable by using user's EmployeeID property. Consider the CSV file Users.csv which contains set of AD users to disable with the attribute EmployeeID as one of the csv column header.
Import-Module ActiveDirectory
Import-Csv "C:\Users.csv" | ForEach-Object {
$employeeID = $_."EmployeeID"
Get-ADUser -LDAPFilter "(employeeID=$employeeID)"  | Disable-ADAccount
Write-Host "User $employeeID disabled"
}
Read More...

Monday, 13 February 2017

Get the list of External users in SharePoint Online using Powershell

We can get the list of all external users in a SharePoint Online tenant using SharePoint Online Powershell cmdlet Get-SPOExternalUser and we can also find and list all the Office 365 guest users by using the Azure AD Powershell cmdlet Get-MsolUser. In this post, I am going to write script to export list of all the external user details to csv file.

Summary:


Get all the External users using Get-SPOExternalUser cmdlet

The below script list the external users from first page. You have to specify your SharePoint Online Admin Center url and Office 365 Admin Credentials to run the following commands.
#Connection to SharePoint Online
$SPOAdminSiteUrl="https://<YourDomain>-admin.sharepoint.com/" 
$365Logon = Get-Credential
Connect-SPOService -Url $SPOAdminSiteUrl -Credential $365Logon  

Get-SPOExternalUser -Position 0 -PageSize 50 | Select DisplayName,Email | FT
If you want to retrieve users from second page, you have to set the position as 1. The below command returns first 10 external users from the second page of the collection.
Get-SPOExternalUser -Position 1 -PageSize 10
You can also specify the parameter SiteUrl to retrieve external users only for a specific site.
Get-SPOExternalUser -Position 0 -PageSize 50 -SiteUrl <YourSiteUrl>

Fetch all the Office 365 External (Guest) users using Get-MsolUser cmdlet

The above command Get-SPOExternalUser will be very helpful if you have minimum number of external users. But it will be difficult if you have 100s of users as you have to fetch users page by page. So to overcome this problem, we can use the Azure AD Powershell cmdlet Get-MsolUser.
#Connection to Azure AD Module
Import-Module MSOnline
$365Logon = Get-Credential
Connect-MsolService –Credential $365Logon

Get-MsolUser -All | ? {$_.UserType -eq "Guest"} | Select DisplayName,SignInName | FT
The above command returns all the Office 365 external users (guest users). You can also apply more where filter to get users from specific domain. The below command returns users only from the domain TestDomain.com.
Get-MsolUser -All | ? {$_.UserType -eq "Guest"} | ? {$_.SignInName -like "*TestDomain.com"}

Export all the External user details to CSV file

You can easily export the external user details to csv file by using the cmdlet Export-Csv.
Get-MsolUser -All | ? {$_.UserType -eq "Guest"} | Select DisplayName,SignInName |
Export-CSV "C:\\External-Users.csv" -NoTypeInformation -Encoding UTF8
Read More...

Thursday, 9 February 2017

Update Office 365 License features using Powershell

You can easily add a new license with required features and remove an existing license using Azure AD Powershell cmdlet Set-MsolUserLicense. In certain scenario you may need to update an existing license features (enable or disable license sub plans) using this cmdlet.

Use the below command to set a new license.
Set-MsolUserLicense -UserPrincipalName 'morgan@contoso.com' -AddLicenses 'contoso:ENTERPRISEPACK'
To assign multiple licenses, you have to provide AccountSkuId of all the licenses as comma (,) separated values.
Set-MsolUserLicense -UserPrincipalName 'morgan@contoso.com' -AddLicenses contoso:ENTERPRISEPACK,contoso:AAD_PREMIUM
You can enable only particular set of features while adding new license to an user. we have to use the powershell cmdlet New-MsolLicenseOptions to set license features that we want to disable (or remove) from new license.
$options = New-MsolLicenseOptions -AccountSkuId 'contoso:O365_BUSINESS_PREMIUM' -DisabledPlans OFFICE_BUSINESS,MCOSTANDARD
Set-MsolUserLicense -UserPrincipalName 'morgan@contoso.com' -LicenseOptions $options –AddLicenses 'contoso:O365_BUSINESS_PREMIUM'
Note: There is no option EnabledPlans like DisabledPlans, so we can't set only required features in straightforward way, we can achieve this only by excluding non-required features by using DisabledPlans option.

Update existing Office 365 License features

If you want to update or disable license features in existing license, you have to set only LicenseOptions in Set-MsolUserLicense cmdlet (exclude the parameter –AddLicenses).
$options = New-MsolLicenseOptions -AccountSkuId 'contoso:O365_BUSINESS_PREMIUM' -DisabledPlans OFFICE_BUSINESS,MCOSTANDARD
Set-MsolUserLicense -UserPrincipalName 'morgan@contoso.com' -LicenseOptions $options
Read More...

Tuesday, 31 January 2017

Working with Array in Powershell

Array holds a list of data items. The Powershell array items can be the same type or different types.

Create or Initialize an Empty Array

The following syntax just creates an empty array object.
$myArray = @()

Create Array with Items

We can easily create predefined Array by just setting comma separated elements.
$myArray = "A","B","Hello","World"
Using explicit syntax:
$myArray = @(1,2,3,4,5)

Add values to an Array

We can add items to an array object by using the + operator.
$myArray = @(1,2,3,4,5)
$myArray = $myArray + 6
You can simplify the add operation by using assignment operator.
$myArray += 6
You can also add another array object using + operator.
$myArray += $secondArray

Read the contents of an array

We need to specify index number to retrieve an element from array, The Powershell array elements starting at 0th index.

Display all the elements in an array:
$myArray
This command returns the first element in an array:
$myArray[0]
This command displays the 2nd,5th,8th elements
$myArray[1,4,7]
Return the range of elements (4th element to the 8th element):
$myArray[3..7]
Return the last element in an array:
$myArray[-1]

Contains check in array

If you want to find an array contains a certain value, you don’t have to iterate through elements to compare the values with search term. Instead, you can apply filter with various comparison operators directly to the array.
$myArray = "A","B","C","Hello","World"
This command would check and return the array elements contains the string "Worl".
$myArray -like "*Worl*"
This command would check if the first three array elements contains the string "B" and return values.
$myArray[0..2] -like "*B*"

Set or Update array values

Use the assignment operator (=) to change or update values in an array.
$myArray[2]=23

Sort an elements

You can simply sort the elements by using Sort operator.
$myArray = $myArray | Sort

Delete an array and elements

You can easily delete an entire array object by setting its value as null
$myArray = $null
But Arrays are fixed-size, so, you can not easily remove values at different indexes. For this need, you need to use System.Array or System.Collections.Generic.List.
Read More...

Monday, 30 January 2017

OneDrive for Business Storage Report using Powershell

You may need to see how much space your users are using in OneDrive for Business storage and need to ask them to free up space if they are getting close to your storage limit. We can retrieve the list of users with OneDrive feature provisioned by using SharePoint Online UserProfileService with Powershell.

Steps to Export OneDrive for Business Size Report:

  • Fetch all SharePoint Online users using UserProfileService.
  • Find if OneDrive for Business is provisioned or not.
  • Find Current Size and Storage Limit details.
  • Export Size and Storage Quota details to csv file.
Note: Replace the variable <your tenant name> with your Office 365 tenant name in all the occurrences and provide your own admin credentials.
$Result=@() 
# Specify your organization admin central url 
$AdminURI = "https://<your tenant name>-admin.sharepoint.com"

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

$loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
$loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")

$sstr = ConvertTo-SecureString -string $AdminPass -AsPlainText -Force
$AdminPass = ""
$creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($AdminAccount, $sstr)
$UserCredential = New-Object System.Management.Automation.PSCredential -argumentlist $AdminAccount, $sstr

# Add the path of the User Profile Service to the SPO admin URL, then create a new webservice proxy to access it
$proxyaddr = "$AdminURI/_vti_bin/UserProfileService.asmx?wsdl"
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $creds

# Set variables for authentication cookies
$strAuthCookie = $creds.GetAuthenticationCookie($AdminURI)
$uri = New-Object System.Uri($AdminURI)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container

# Sets the first User profile, at index -1
$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)
Write-Host "Starting- This could take a while."
$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1

Connect-SPOService -Url $AdminURI -Credential $UserCredential

# As long as the next User profile is NOT the one we started with (at -1)...
While ($UserProfileResult.NextValue -ne -1) 
{
Write-Host "Checking profile $i of $NumProfiles"
# Look for the Personal Space object in the User Profile and retrieve it
# (PersonalSpace is the name of the path to a user's OneDrive for Business site. 
# Users who have not yet created a  OneDrive for Business site might not have this property)
$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" } 
$Url= $Prop.Values[0].Value
 
# If "PersonalSpace" exists, then OneDrive Profile provisioned for the user...
if ($Url) {
$siteUrl = "https://<your tenant name>-my.sharepoint.com"+ $Url.Substring(0,$Url.Length-1)

# Find size and storage limit
$temp = Get-SPOSite $siteurl -Detailed
if($temp)
{
$Result += New-Object PSObject -property @{ 
UserName = $temp.Title
UserPrincipalName = $temp.Owner
Size_inMB = $temp.StorageUsageCurrent
StorageQuota_inGB = $temp.StorageQuota/1024
WarningSize_inGB =  $temp.StorageQuotaWarningLevel/1024
}
}
}
# And now we check the next profile the same way...
$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)
$i++
}
$Result | FT
You can also export the output into csv file:
$Result | Export-CSV "C:\\OneDrive-for-Business-Size-Report.csv" -NoTypeInformation -Encoding UTF8
Read More...

Wednesday, 28 December 2016

Create all day event using Microsoft Graph Api

I have just developed a small application to import holiday list from csv file into every Office 365 users Outlook calendar. I have already created an Azure AD Application and set the required permission "Read and write calendars in all mailboxes". I am using following graph api endpoint to post my new calendar event.
https://graph.microsoft.com/v1.0/me/events
Json Body to add new Christmas Holiday event (2016-12-25):
{  
  "originalStartTimeZone": "UTC",
  "originalEndTimeZone": "UTC",
   "Subject":"Christmas Holiday",
   "Start":{  
      "DateTime":"2016-12-25T00:00:00",
      "TimeZone":"UTC"
   },
   "End":{  
      "DateTime":"2016-12-26T00:00:00",
      "TimeZone":"UTC"
   },
"iCalUId": "iCalUId-value",
"IsAllDay":true,
} 
To a create holiday event, we need to make sure that the event should occur in whole day (12 AM to 12 PM), to achieve this we need to set the parameter isAllDay=true and we have to set the start and end properties of the event to midnight of the day when event occurs (2016-12-25T00:00:00) and midnight of the next day of the event (2016-12-26T00:00:00).

If you set the event without giving the parameter "IsAllDay":true, the event may spread over two days due to time zone problem. So, don't forgot to set the property IsAllDay as true to create all day event like holiday.

Html Javascript Code : Create Holiday Calendar Event

var jsonBody = '{  
  "originalStartTimeZone": "UTC",
  "originalEndTimeZone": "UTC",
   "Subject":"Christmas Holiday",
   "Start":{  
      "DateTime":"2016-12-25T00:00:00",
      "TimeZone":"UTC"
   },
   "End":{  
      "DateTime":"2016-12-26T00:00:00",
      "TimeZone":"UTC"
   },
"iCalUId": "iCalUId-value",
"IsAllDay":true,
}'


var httpRequest = new XMLHttphttpRequestuest();
httpRequest.open("POST", "https://graph.microsoft.com/v1.0/me/events");
httpRequest.sethttpRequestuestHeader("authorization", "Bearer " + accessToken);
httpRequest.sethttpRequestuestHeader("content-type", "application/json");
httpRequest.onload = function (e) {
    if (httpRequest.readyState === 4) {
        if (httpRequest.status === 201) {
            console.log(httpRequest.response);
        }
    }
};
httpRequest.onerror = function (e) {
    // Handle error
};
httpRequest.send(jsonBody);
Read More...

Monday, 26 December 2016

List all the OneDrive for Business users in Office 365 - Powershell

We can get the list of users with OneDrive for Business feature provisioned by using SharePoint Online UserProfileService with Powershell. As you know SharePoint is base for OneDrive as like some other services (Office 365 Groups, Planner, Teams, and etc..), so it's users basic profile information obviously will be stored in SharePoint. You can get all the SharePoint Online users using SharePoint UserProfileService and look for the Personal Space object, users who have OneDrive for Business site alone have value for this property and other users do not have this property.

Steps to Export OneDrive for Business Provisioned Users:

  • Fetch all SharePoint Online users using UserProfileService.
  • Find if OneDrive is provisioned or not.
  • Export my site collections to text file.
Note: Replace the variable <your tenant name> with your Office 365 tenant name in all the occurrences and provide your own admin credentials.
# Specify sharepoint online admin url 
$adminURL = "https://<your tenant name>-admin.sharepoint.com"

# Specify the location where the list of OneDrive sites should be saved
$LogFile = 'C:\OneDrivesites.txt'

#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")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")

#Provide your global admin credentials.
$UserName = "admin@<your tenant name>.onmicrosoft.com"
$SecPwd = $(ConvertTo-SecureString 'password' -asplaintext -force) 
$adminCreds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecPwd) 

# Set User Profile Service path using SPO admin URL 
$proxyaddr = "$adminURL/_vti_bin/UserProfileService.asmx?wsdl"
# Create a new webservice proxy to access UserProfileService
$UserProfileService= New-WebServiceProxy -Uri $proxyaddr -UseDefaultCredential False
$UserProfileService.Credentials = $adminCreds

# Set authentication cookies
$strAuthCookie = $adminCreds.GetAuthenticationCookie($adminURL)
$uri = New-Object System.Uri($adminURL)
$container = New-Object System.Net.CookieContainer
$container.SetCookies($uri, $strAuthCookie)
$UserProfileService.CookieContainer = $container

# Sets the first User profile, at index -1
$UserProfileResult = $UserProfileService.GetUserProfileByIndex(-1)

Write-Host "Starting- This could take a while."

$NumProfiles = $UserProfileService.GetUserProfileCount()
$i = 1

# As long as the next User profile is NOT the one we started with (at -1)...
While ($UserProfileResult.NextValue -ne -1) 
{
Write-Host "Checking profile $i of $NumProfiles" -foreground Yellow

# Look for the Personal Space object in the User Profile and retrieve it
# (PersonalSpace is the name of the path to a user's OneDrive for Business site. 
# Users who have not yet created a  OneDrive for Business site might not have this property)
$Prop = $UserProfileResult.UserProfile | Where-Object { $_.Name -eq "PersonalSpace" } 
$Url= $Prop.Values[0].Value

# If "PersonalSpace" (which we've copied to $Url) exists, log it to our file...
if ($Url) {
$siteUrl = "https://<your tenant name>-my.sharepoint.com"+ $Url
# Write OneDrive site url in console
Write-Host $Url -foreground Green
$siteUrl | Out-File $LogFile -Append -Force
}

# And now we check the next profile the same way...
$UserProfileResult = $UserProfileService.GetUserProfileByIndex($UserProfileResult.NextValue)
$i++
}
Source : https://technet.microsoft.com/en-us/library/dn911464.aspx
Read More...