Wednesday, 28 September 2016

Get Last Logon Time for Exchange Online Users

Getting last logon date of all Office 365 Mailbox enabled users is one of the important task to track user logon activity and find inactive users to calculate the Exchange Online license usage. We can use the Exchange Online powershell cmdlet Get-MailboxStatistics to get last logon time, mailbox size, and other mailbox related statistics data.

Before proceed, first we need to connect Remote Exchange Online powershel module by running below command:
$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession $Session
Run the following command to get mailbox statistics for a single Office 365 user
Get-MailboxStatistics -Identity <name or upn of user>
To find last logon time for all the Office 365 users, first we need to get all mailboxes by using Get-Mailbox cmdlet and pipe the results to Get-MailboxStatistics.
Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics | Select-Object DisplayName,LastLogonTime
Using above script, you can get output only from the cmdlet Get-MailboxStatistics and you can't fetch any result from Get-Mailbox. If you want to read detail from Get-Mailbox command like UserPrincipalName, you need to merge output of two cmdlets.
$mailboxes = Get-Mailbox -ResultSize Unlimited
$mailboxes | ForEach-Object {
$mbx = $_
$mbs = Get-MailboxStatistics -Identity $mbx.UserPrincipalName | Select LastLogonTime
if ($mbs.LastLogonTime -eq $null){
$lt = "Never Logged In"
}else{
$lt = $mbs.LastLogonTime }

New-Object -TypeName PSObject -Property @{ 
UserPrincipalName = $mbx.UserPrincipalName
LastLogonTime = $lt }
}

Export Last Logon Time of Office 365 Users to CSV file:

You can also export all Exchange Online user's last logon time to csv file by using below script
$Result=@() 
$mailboxes = Get-Mailbox -ResultSize Unlimited
$totalmbx = $mailboxes.Count
$i = 1 
$mailboxes | ForEach-Object {
$i++
$mbx = $_
$mbs = Get-MailboxStatistics -Identity $mbx.UserPrincipalName | Select LastLogonTime
if ($mbs.LastLogonTime -eq $null){
$lt = "Never Logged In"
}else{
$lt = $mbs.LastLogonTime }

Write-Progress -activity "Processing $mbx" -status "$i out of $totalmbx completed"

$Result += [PSCustomObject] @{ 
Name = $mbx.DisplayName
UserPrincipalName = $mbx.UserPrincipalName
LastLogonTime = $lt }
}

$Result | Export-CSV "C:\\O365-LastLogon-Info.csv" -NoTypeInformation -Encoding UTF8
Read More...

Tuesday, 27 September 2016

Invite external users to SharePoint site using CSOM

We may required to automate the process of inviting external users to SharePoint site or document. In this article, I am going write CSOM based C# code to send invitation for bulk external users to site or document.

The Microsoft SharePoint Online SDK assembly Microsoft.SharePoint.Client.dll includes the namespace Microsoft.SharePoint.Client.Sharing in which there are two useful classes called WebSharingManager and DocumentSharingManager. We can use the class WebSharingManager to share a SharePoint site with external users.
private static void InviteExternalUsersForSite() 
{ 
    // Create Connection to SharePoint Online Site 
    using (var context = new ClientContext("https://spotenant.sharepoint.com/sites/contosobeta")) 
    { 
        context.Credentials = new SharePointOnlineCredentials("admin@spotenant.com", securePwd); 
        // Create invitation request list to multiple users 
        var users = new List<string>() { "admin@extDomain.com", "alexd@extDomain.com"}; 
        var userRoles = new List<UserRoleAssignment>(); 
        foreach (var user in users) 
        { 
            UserRoleAssignment role = new UserRoleAssignment(); 
            role.UserId = user; 
            role.Role = Role.View; 
            userRoles.Add(role); 
        } 
        string message = "Please accept this invite to access our SharePoint Site."; 
        // Send invitation requests to external users 
        WebSharingManager.UpdateWebSharingInformation(context, context.Web, userRoles, true, message, true, true); 
        context.ExecuteQuery(); 
    } 
}
We need to use the class DocumentSharingManager to programmtically share a document with external users.
string absoluteFileUrl = "https://spotenant.sharepoint.com/sites/contosobeta/Shared%20Documents/Document.docx"; 
DocumentSharingManager.UpdateDocumentSharingInfo(context, absoluteFileUrl, userRoles, true, true, true, customMsg, true, true);
Note: Here, I have used list to send invitation for multiple users, but you can alternatively import users from csv file and share site or document with bulk users.
Read More...

Friday, 23 September 2016

Azure AD Import-Module – Could not load file or assembly

Problem:

You will receive the following error when try to run the Windows Azure Active Directory Module or run the command Import-Module MSOnline on a Windows 7 or 2008 R2 machine.
Import-Module : Could not load file or assembly ‘file:///C:\Windows\system32\WindowsPowerShell\v1.0\Modules\MSOnline\Microsoft.Online.Administration.Automation.PSModule.dll’ or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.
At line:1 char:14
+ Import-Module <<<<  MSOnline
    + CategoryInfo          : InvalidOperation: (:) [Import-Module], BadImageFormatException
    + FullyQualifiedErrorId : FormatXmlUpateException,Microsoft.PowerShell.Com   mands.ImportModuleCommand

Cause:

This problem will occur due to PowerShell built against the .NET framework in a specific version. You can check it by the PowerShell variable: $PSVersionTable.

Fix/Solution:

For me the problem was solved after installing Windows Management Framework 3.0.

For more detail, you can refer this article: Azure AD Module – This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded
Read More...

Powershell - Connect-MsolService Error : Method not found

Problem:

After installing Azure Active Directory Powershell module, you will get the following error when you connect Azure AD using the cmdlet Connect-MsolService.
Connect-MsolService : Method not found: 'Void
System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr, !!0)'.
At line:1 char:1
+ Connect-MsolService -Credential $cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [Connect-MsolService], Mis
   singMethodException
    + FullyQualifiedErrorId : System.MissingMethodException,Microsoft.Online.A
   dministration.Automation.ConnectMsolService

Fix/Solution:

For me the issue was fixed after update my .NET to 4.5.2.

You can also try other solutions if the above update does not fix the problem for you. Check this Microsoft forum for more info: Problem to Connect MsolService
Read More...

Fix - Office 365 Implicit Remoting Broken in PowerShell

Problem:

You will get the following error when you connect to Exchange Online via PowerShell after the Windows Client Update KB3176934.
Import-PSSession : Could not load type ‘System.Management.Automation.SecuritySupport’ from assembly
‘System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’.

Cause:

On August 23, Microsoft released the Windows Client update KB3176934. Due to a missing .MOF file in the build package, the update breaks DSC. All DSC operations will result in an “Invalid Property” error. This is a known issue and it is documented under Known Issues section in https://support.microsoft.com/en-in/kb/3176934

Fix/Solution:

Microsoft released fix for this issue in next cumulative Windows update https://support.microsoft.com/en-us/kb/3176938.
Read More...

Thursday, 22 September 2016

Create SharePoint List from Custom Template using CSOM

In this post, I am going write C# code sample to create a new list based on existing list template (.stp uploaded to the list template gallery) with managed Client Object Model. Along with creating new sharepoint list or document library, this process creates new content type, site columns , list view and contents (files or list items) if exists in custom list template.

This process includes following steps:

1. Initialize site context by giving site url where we want to create list or document library.
2. Get all custom list templates.
3. Initialize ListCreationInformation with new list or document library name and custom list template.
4. Finally, creates new list with custom template.
private static void CreateLibraryUsingCustomTemplate() 
{ 
    using (var context = new ClientContext("https://spo-tenant.sharepoint.com/sites/teamsite")) 
    { 
        context.Credentials = new SharePointOnlineCredentials("username", securePwd); 
        // Load the custom templates from site collection 
        ListTemplateCollection templates = context.Site.GetCustomListTemplates(context.Web); 
        context.Load(templates); 
        context.ExecuteQuery(); 
        // Initialize list or library creation info 
        var listCreationInfo = new ListCreationInformation 
        { 
            Title = "Test Custom Library", 
            Description = "Test Custom Library" 
        }; 
  
        ListTemplate listTemplate = templates.First(listTemp => listTemp.Name == "<template name>"); 

        listCreationInfo.ListTemplate = listTemplate; 
        listCreationInfo.TemplateFeatureId = listTemplate.FeatureId; 
        listCreationInfo.TemplateType = listTemplate.ListTemplateTypeKind;  
        // Add Document Library to site 
        context.Web.Lists.Add(listCreationInfo); 
        context.ExecuteQuery(); 
    } 
} 
Read More...

Friday, 16 September 2016

Rename a document in Sharepoint Online using CSOM

There is no direct function to rename a uploaded document in SharePoint document library using the client side object model (csom), as a work-around, we need to use File.MoveTo method to rename a file. Here we need to actually move the file in same location with different name.

Use the below powershell script to rename a specific sharepoint document file.
#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")  
 
$siteUrl = "https://spotenant.sharepoint.com/sites/contosobeta" 
$UserName = "admin@spotenant.onmicrosoft.com" 
$SecPwd = $(ConvertTo-SecureString 'adminPassword' -asplaintext -force) 
 
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl) 
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecPwd) 
$ctx.credentials = $credentials 
 
#Rename a file 
$fileUrl ="/sites/contosobeta/Shared Documents/test.csv" 
$newfileUrl="/sites/contosobeta/Shared Documents/test_rename.csv" 

$file = $ctx.Web.GetFileByServerRelativeUrl($fileUrl) 
$file.MoveTo($newfileUrl, [Microsoft.SharePoint.Client.MoveOperations]::Overwrite) 
$ctx.ExecuteQuery() 

Rename a file using Office Dev PnP

You can also use below powershell code to rename a document stored inside a SharePoint Online document library using Office Dev PnP.
Connect-SPOnline -url [yoururl]
$ctx = Get-SPOContext
$web = Get-SPOWeb
$fileUrl ="/sites/contosobeta/Shared Documents/test.csv" 
$newfileUrl="/sites/contosobeta/Shared Documents/test_rename.csv" 
$file = $web.GetFileByServerRelativeUrl("$fileUrl")
$file.MoveTo("$newfileUrl", 'Overwrite')
$ctx.ExecuteQuery()
 

Rename all uploaded document files in a SharePoint List

You can also use the below powershell script to rename all the files in a document library.
$siteUrl = "https://spotenant.sharepoint.com/sites/contosobeta" 
$UserName = "admin@spotenant.onmicrosoft.com" 
$SecPwd = $(ConvertTo-SecureString 'adminPassword' -asplaintext -force) 
 
$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl) 
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName,$SecPwd) 
$ctx.credentials = $credentials 
  
#Load items 
$list = $ctx.Web.Lists.GetByTitle("Documents") 
$query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery() 
$items = $list.GetItems($query) 
$ctx.Load($items) 
$ctx.ExecuteQuery() 
 
#Rename File(s) 
foreach ($item in $items){ 
if($item.FileSystemObjectType -eq [Microsoft.SharePoint.Client.FileSystemObjectType ]::File) {  
$destFileUrl = $item["FileRef"].ToString().Replace("test","test_rename") 
$item.File.MoveTo($destFileUrl, [Microsoft.SharePoint.Client.MoveOperations]::Overwrite) 
$ctx.ExecuteQuery() 
} 
}
Read More...

Thursday, 15 September 2016

Guest access feature indroduced for Office 365 Groups

The introduction of Office 365 groups gives the rich collaboration within a team inside an organization. There will be a situation you need to give access to outside of organisation when you work closely with customers, partners, and others outside organizations. The importance of collaboration with external users is inevitable in various business needs, to resolve this, Microsoft finally announced the external user (Guest) access feature: Introducing guest access for Office 365 Groups


Note: Microsoft announced the guest access feature works only for email accounts including corporate and consumer domains (such as Outlook.com or Gmail.com). If the guest email identity is associated with a Microsoft account (such as Office 365 or Outlook.com accounts, for instance), the user is directed to a sign-in page to identify themselves. If the guest doesn’t have a Microsoft account, they will be directed to a sign-up page to create an account.

You can also read this great article https://www.petri.com/external-access-office-365-groups (by Tony Redmond) to know more about how to add guest users for Office 365 Groups and how an external user invitation works for guest users.
Read More...

Wednesday, 14 September 2016

Get all Documents from a SharePoint List using CSOM

In this post, I am going to write C# code to list all documents in a SharePoint list and get all files from SharePoint Site using Client Object Model (CSOM).

List all documents in a SharePoint Document Library

The below C# code find and list all files in the particular document library. You can replace your own list name to get required documents.
public static void GetAllDcoumentsInaList() 
{    
    string sitrUrl = "https://SPTenant.sharepoint.com/sites/contosobeta"; 
    using (var ctx = new ClientContext(sitrUrl)) 
    { 
        //ctx.Credentials = Your Credentials
        ctx.Load(ctx.Web, a => a.Lists); 
        ctx.ExecuteQuery(); 

        List list = ctx.Web.Lists.GetByTitle("Documents"); 
        var items = list.GetItems(new CamlQuery() { ViewXml = "<View Scope=\"RecursiveAll\"><Query><Where><IsNotNull><FieldRef Name=\"File_x0020_Type\" /></IsNotNull></Where></Query></View>" }); 
        ctx.Load(items); 
        ctx.ExecuteQuery(); 
        foreach (var doc in items) 
        { 
            Console.WriteLine(doc["FileRef"].ToString().Split('/').LastOrDefault() + 
                " (" + doc["File_x0020_Size"].ToString() + " bytes)"); 
        } 
    } 
} 

Get all documents in a SharePoint Site

To retrieve items from entire site, first, we need to fetch all the lists in a site and add condition check BaseType in list to filter only document libraries.
public static void GetAllDcoumentsInaSite() 
{ 
    string sitrUrl = "https://SPTenant.sharepoint.com/sites/contosobeta"; 
    using (var ctx = new ClientContext(sitrUrl)) 
    { 
        //ctx.Credentials = Your Credentials
        ctx.Load(ctx.Web, a => a.Lists); 
        ctx.ExecuteQuery(); 
 
        foreach (List list in ctx.Web.Lists) 
        { 
            if (list.BaseType == BaseType.DocumentLibrary) 
            { 
                Console.WriteLine("List: " + list.Title); 
                Console.WriteLine("-----------------------"); 
                var items = list.GetItems(new CamlQuery() { ViewXml = "<View Scope=\"RecursiveAll\"><Query><Where><IsNotNull><FieldRef Name=\"File_x0020_Type\" /></IsNotNull></Where></Query></View>" }); 
                ctx.Load(items); 
                ctx.ExecuteQuery(); 
                foreach (var doc in items) 
                { 
                    Console.WriteLine(doc["FileRef"].ToString().Split('/').LastOrDefault() + 
                " (" + doc["File_x0020_Size"].ToString() + " bytes)"); 
                } 
            } 
        } 
    } 
} 
Read More...

Thursday, 8 September 2016

CSOM : The request uses too many resources - SharePoint Online

I have the following c# csom (client side object model) code to get sub sites and nested sub sites of a site collection. This code runs perfectly for most site collections, but it not working for a single site collection which has a lot of sub-sites and nested sub sites.
private static List<Web> RecursiveSites(ClientContext siteCtx, Web site)
{
    var allSites = new List<Web>();
    allSites.Add(site);
    if (site.Webs.Count > 0)
    {
        siteCtx.Load(site.Webs, w => w.Include(a => a.Title, a => a.Url, a => a.Webs));
        siteCtx.ExecuteQuery();
        foreach (Web web in site.Webs)
        {
            allSites.AddRange(RecursiveSites(siteCtx, web));
        }
    }
    return allSites;
}
I am receiving below error:
Microsoft.SharePoint.Client.ServerException: The request uses too many resources
After googled sometime, I've found an article in MSDN that explains the request limits of the csom. You can refer this under the heading Request limits of the CSOM at bottom of this article https://msdn.microsoft.com/en-us/library/office/jj163082.aspx
The CSOM in Project Server 2013 is built on the CSOM implementation in SharePoint Server 2013 and inherits the limits 
for the maximum size of a request. SharePoint has a 2 MB limit for an operations request, and a 50 MB limit for the size of a
submitted binary object. The request size is limited to protect the server from excessively long queues of operations and
from processing delays for large binary objects.
.

Solution:

In SharePoint On-Premise, you can resolve this issue by setting the maxObjectPaths in WebApplication to a higher value using Powershell:
#Get the value:
Get-SPWebApplication | %{$_.ClientCallableSettings}

#Set the Value:
Add-PSSnapin Microsoft.SharePoint.PowerShell
$webApp = Get-SPWebApplication "http://myspwebapp/"
$webApp.ClientCallableSettings.MaxObjectPaths = 2500
$webApp.Update()
But in SharePoint Online, there is no way to access the ClientCallableSettings.MaxObjectPaths property. so we need to re-write the code to reduce request size. I have changed the code in a way to send request for one site instead of all sub sites at the same time, now the code execute the siteCtx.ExecuteQuery() inside the loop instead of outside the loop.
private static List<Web> RecursiveSites(ClientContext siteCtx, Web site)
{
    var allSites = new List<Web>();
    allSites.Add(site);
    if (site.Webs.Count > 0)
    {     
        foreach (Web web in site.Webs)
        {
            siteCtx.Load(web , w => w.Title, w => w.Url, w => w.Webs);
            siteCtx.ExecuteQuery();
            allSites.AddRange(RecursiveSites(siteCtx, web));
        }
    }
    return allSites;
}
Read More...

Wednesday, 31 August 2016

Office 365 License Report using PowerShell

We can use the Azure AD powershell cmdlet Get-MsolUser to get all office 365 users. This command also returns the license based property IsLicensed and Licenses (applied license details).

Note: Before proceed, Install and Configure Azure AD PowerShell

Run the below command to get all the office 365 users.
Get-MsolUser -All  | Select-Object UserPrincipalName, DisplayName, isLicensed
The below command returns only licensed office 365 users.
Get-MsolUser -All | Where-Object { $_.isLicensed -eq $true } |
Select-Object UserPrincipalName, DisplayName, Department
You can also extract what are the licenses has been assigned to every users.
Get-MSOLUser -All | Where-Object { $_.isLicensed -eq $true } |
Select-Object UserPrincipalName, DisplayName, {$_.Licenses.AccountSkuId}
Run the below command to export all the licensed users and applied license details to csv file.
Get-MSOLUser -All | Where-Object { $_.isLicensed -eq $true } |
Select-Object UserPrincipalName, DisplayName, {$_.Licenses.AccountSkuId} |
 Export-CSV "C:\\office-365-users-license.csv" -NoTypeInformation -Encoding UTF8
You can read this technet article: https://technet.microsoft.com/en-us/library/dn771771.aspx to get fine-tuned license report, like all licensed users who are enabled for specific license plan.
Read More...

Tuesday, 30 August 2016

Powershell - Write Output in Console

There are multiple ways to write output to powershell console, you can simply put quotation marks in any string to display on the screen and you can also use the powershell cmdlets Write-Host and Write-Output.
"Hello World1"
Write-Host "Hello world2"
Write-Output "Hello World3"
The Write-Host is the best choice in many cases, it is the cmdlet designed specifically to display output only on powershell console screen. You can display the output with background color and foreground color by using Write-Host.
Write-Host "Hello world" -BackgroundColor "Green" -ForegroundColor "Black"
Write-Output cmdlet should be used when you want to send data into the pipe line, but not necessarily want to display it on screen. Because, you can't pipe the output when you use Write-Host.
function Test-Output {
    Write-Output "Hello World"
}

function Receive-Output {
    process { Write-Host $_ -ForegroundColor Yellow }
}

#Output piped to another function, not displayed in first.
Test-Output | Receive-Output
You can get more detail about the cmdlets Write-Host and Write-Output from this article : https://blogs.technet.microsoft.com/heyscriptingguy/2011/05/17/writing-output-with-powershell/
Read More...

Host Web vs App Web in SharePoint

If you are newbie for SharePoint apps development, you might be wondering to know clear idea about the terminologies host web and app web (add-in web).

The special site where the app is deployed is called an app web. The site where the app is installed is called the host web. In other words, the SharePoint add-in which host SharePoint components (e.g. lists, content types etc.) is called the app web.

Consider that you are developing an app with custom ribbon action in List view page and the custom action click redirects you to the special site page. Here, the custom action placed in host web and special page is an app web

App Web - The special website to which the add-in is deployed

Host Web - The site on which the App is installed

For more detail checkout this article : https://msdn.microsoft.com/en-us/library/office/fp179925.aspx
Read More...

Monday, 29 August 2016

How to change product key in Office or Outlook 2016

Today, I have installed Office 2016 setup to use Outlook 2016 and put in the product key when I open the outlook. After entering the product key, it sends to the product Activation page, the product activation message says that it is valid key but it is already used. So, now I have been forced to change the new product key.

Find and Reset Office 2016 License Key using VBScript

1. Open a command prompt (Start-> Run: cmd).
2. Run the following commands:
cscript "C:\Program Files\Microsoft Office\Office16\ospp.vbs" /dstatus
3. Note it the 5 digit partial product key (You may find multiple keys).
How to change license key in Office or Outlook 2016
4. Then run the following command after replacing the <partial_key> with the 5 digit key that you got previous step.
cscript "C:\Program Files\Microsoft Office\Office16\ospp.vbs" /unpkey:<partial_key>
This will uninstall an installed product key with partial product key you noted earlier. Uninstall all of the keys.

5. Now you should be able to set the license key as usual way. Or you can use following command after replacing the <new_full_key> with your new license key:
cscript "C:\Program Files\Microsoft Office\Office16\ospp.vbs" /inpkey:<new_full_key>
Then you need run the below command to activate license.
cscript "C:\Program Files\Microsoft Office\Office16\ospp.vbs" /act

Note:

Depending on the combination of Office version you might have to change the path to Program Files(x86)

For (x64 Office 2016) : C:\Program Files\Microsoft Office\Office16\
For (x86 Office 2016): C:\Program Files(x86)\Microsoft Office\Office16\

For (x64 Office 2013) : C:\Program Files\Microsoft Office\Office13\
For (x86 Office 2013): C:\Program Files(x86)\Microsoft Office\Office13\
Read More...

Friday, 26 August 2016

Powershell - Check Contains String In Where Object

You can use the Where-Object cmdlet to filter objects from a collection based on their property values. We can use the comparison operator like with wildcard character to check if a property of object contains a specific string.
Note: You can not use the comparison operator contains to check the contains string, because it's designed to tell you if a
collection of objects includes ('contains') a particular object
The following command returns all the processes in current machine.
Get-Process | Select ID,ProcessName
If you want to list only the process which contains string '32' in processname, you need to use the below command.
Get-Process | Where-Object { $_.Name -like '*32*' }
By default like operator ignore the case-sensitive check. To perform a case-sensitive comparison just prefix the word "c" with like operator ("clike").
Get-Process | Where-Object { $_.Name -clike '*rundll*' }
If you want to check starts with string, you can use the same like operator with appending * at the end of the string alone.
Get-Process | Where-Object { $_.Name -like 'rundll*' }
Likewise, to check ends with string, need to append * at start of the string.
Get-Process | Where-Object { $_.Name -like '*host' }
Read More...