Part 2: Customize SharePoint Online User Interface using JavaScript | CSOM | PowerShell

2016-11-02_12-42-56

This is a continuation of part 1 and we will cover about adding a custom action in site action of the web. Note: You can think about any solution. This blog post is to show an option in PowerShell and Client Side Object Model to customize the Site Actions of the web.

  1. To know Default Custom Action and Location ID’s – Navigate here.
  2. How to work with User Custom Action – Navigate here.

Here is the sample code to add a link in Site Actions!

#Choose the Location as Microsoft.SharePoint.SiteSettings
$UserCustomAction.Location = "Microsoft.SharePoint.SiteSettings"

#Choose the Group as SiteTasks (Site Actions)
$UserCustomAction.Group = "SiteTasks"

Site Actions Before

2016-11-02_12-30-44

Site Actions After

12

Full Code

Import-Module C:\Temp\SharePointOnlinePowerShell\Microsoft.SharePoint.Client.dll
$Admin = "Chendrayan@Contoso.onmicrosoft.com"
$Password = "Password01" | ConvertTo-SecureString -AsPlainText -Force 
$Context = [Microsoft.SharePoint.Client.ClientContext]::new("https://contoso.sharepoint.com/Sites/PublishingPortal")
$Context.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Admin,$Password)

$UserCustomAction = $Context.Web.UserCustomActions.Add()

#Choose the Location as Microsoft.SharePoint.SiteSettings
$UserCustomAction.Location = "Microsoft.SharePoint.SiteSettings"

#Choose the Group as SiteTasks (Site Actions)
$UserCustomAction.Group = "SiteTasks"

$UserCustomAction.Name = "Demo"
$UserCustomAction.Sequence = 1000
$UserCustomAction.Url = "http://www.bing.com"
$UserCustomAction.Title = "Search Bing"
$UserCustomAction.Update()

$Context.ExecuteQuery()

Enjoy PowerShell!

Get High Priority Email Message as a Phone Call using EWS API and PowerShell

baby-phone-scam

A colleague shared a blog post and asked me a script to get high priority email using PowerShell? Well, it’s the same way  by modifying the search filter as required as shown below.

$SearchFilter = [Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo]::new([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Importance, 
                "High")

and the below is the view to get the number of email we need from the inbox – In our case just one!

$View = [Microsoft.Exchange.WebServices.Data.ItemView]::new(1)

Hey, I need a phone call for a high priority email and it should read the message! That’s a Friday fever! For any IT Professional major incidents are not new 🙂 check the below email body 🙂 let’s get a call for the same !

Email Body

2016-10-28_13-05-55

 

Here is the sample code !

$Credential = Get-Credential "Chendrayan.Venkatesan@contoso.com"
$Service = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
$Service.Credentials = [System.Net.NetworkCredential]::new($Credential.UserName,$Credential.Password)
$Service.AutodiscoverUrl($UserID,{$true})
$Service.Url = "https://outlook.office365.com/EWS/Exchange.asmx"
$Folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$View = [Microsoft.Exchange.WebServices.Data.ItemView]::new(1)
$SearchFilter = [Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo]::new([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Importance, 
                "High")
$Results = $Service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$SearchFilter,$View)
$ItemId = $Results.Items[0].Id.UniqueId

# Fun and it's Fun
$Call = $Service.UnifiedMessaging.PlayOnPhone($ItemId, "+31<Number>")
$Call.Refresh()

Enjoy PowerShell!

Microsoft Word VSTO ADDIN – Retrieve SharePoint Site List Information Using CSOM

A friend of mine Erdem Avni Avni SELÇUK from Turkey showed a video sample which retrieves SharePoint Online list column information in Excel! Truly amazing stuff for SharePoint IT Professionals  at least for me. So, thought of Sharing my demo code which simply lists all SharePoint list title and includes a header text and footer with image in word document. This is very ugly code but may give some dice for IT Pro’s for customizing and building the solution as desired for content managers.

This is our output – Modified the image so header and footer will be visible

6

 

Step 1: Create a a Office VSTO office 2013 / 2016 addin solution using Visual Studio – Start From here

Step 2: Add a new item to the solution and choose Ribbon – it’s an xml file! – Start From here

Step 3: Install CSOM SDK assemblies 🙂 🙂 🙂 – Below is the sample code

Continue reading Microsoft Word VSTO ADDIN – Retrieve SharePoint Site List Information Using CSOM

Part 1: Customize SharePoint Online User Interface using JavaScript | CSOM | PowerShell

 

Woman’s hand drawing a light globe with a felt pen

 

During my web-ex session “Manage SharePoint Online Using CSOM” I showed few of the custom functions wrapped up as script module. I will be posting the recording session by next week and module will be shared in Git! In the session content management team was actively posting questions and this blog series shares all the questions and solutions we discussed.

Question: Can we Inline Java Script and modify the ribbons, menu items etc in SharePoint Online? If yes can you show step by step procedure?

Answer: Start from here!

Step 1: Create a folder and save all the required files and test the simple java script code to show Hello, World!

console.log('Message appears here!')

1

Step 2: Now, we need to know the existing custom actions attached in the list, the below code does it for you!

Import-Module .\Microsoft.SharePoint.Client.dll
$Admin = "Admin@domain.onmicrosoft.com"
# Using Clear Text Password is not adviced in the script (Use Get-Credential)
$Password = "P@ssw0rd!" | ConvertTo-SecureString -AsPlainText -Force
$Credential = [pscredential]::new($Admin,$Password)
$Context = [Microsoft.SharePoint.Client.ClientContext]::new('https://contoso.sharepoint.com/sites/csom')
$Context.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credential.UserName,$Credential.Password)

$UserCustomActionCollection = $Context.Web.Lists.GetByTitle('Custom').UserCustomActions
$Context.Load($UserCustomActionCollection )
$Context.ExecuteQuery()
foreach($UserCustomAction in $UserCustomActionCollection)
{
    $UserCustomActionCollection
}

For now, we haven’t attached any custom user actions so the script returns nothing for the list custom (In your case if you have any user custom actions attached you get to see whole bunch of information)!

Step 3: Now, we will add a simple menu in the SharePoint List item menu (The code is in MSDN link and we will use the same but in PowerShell). Take a look at the screen shot which is default out of the box options.

3

Let us add a menu name as Bing to open the bing search engine !  below is the code which does it easily

Import-Module .\Microsoft.SharePoint.Client.dll
$Admin = "Admin@domain.onmicrosoft.com"
# Using Clear Text Password is not adviced in the script (Use Get-Credential)
$Password = "P@ssw0rd" | ConvertTo-SecureString -AsPlainText -Force
$Credential = [pscredential]::new($Admin,$Password)
$Context = [Microsoft.SharePoint.Client.ClientContext]::new('https://contoso.sharepoint.com/sites/csom')
$Context.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credential.UserName,$Credential.Password)

$UserCustomActionCollection = $Context.Web.Lists.GetByTitle('Custom').UserCustomActions
$Context.Load($UserCustomActionCollection )
$Context.ExecuteQuery()

$NewAction = $UserCustomActionCollection.Add()
$NewAction.Location = 'EditControlBlock'
$NewAction.Title = "Bing It!"
$NewAction.Description = "Search in Bing!"
$NewAction.Url = "http://www.bing.com"
$NewAction.Update()
$Context.ExecuteQuery()

It works! Here is the output 🙂

4

Step 4: If we rerun the Get Custom Actions script we get to see information about the custom actions we added. The below image illustrate it

5

If you re run the script List Drop Down Menu it gets duplicated! So, don’t do that if accidentally did that like me not an issue quickly clean the dirt by running the below piece of code

foreach($UserCustomAction in $UserCustomActionCollection)
{
    $UserCustomAction.DeleteObject()
    $Context.ExecuteQuery()
}

Clear! Now, it’s time to use java script 🙂 since I have very basic knowledge in java I showed the example using the MSDN code sample 🙂 Yes Copy + Paste !

In this example we will add a custom ribbon user interface in list display form  – All I did is removing the unnecessary nodes from the XML and below is my example

$here = @"
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListForm.Display.Manage.Controls._children"> 
<Button Id="{B511A716-54FF-4EAE-9CBE-EA02B51B626E}" 
Command="{4E2F5DC0-FE2C-4466-BB2D-3ED0D1917763}" 
Image32by32="~site/_layouts/Images/BingSearch/bing32.png" 
Image16by16="~site/_layouts/Images/BingSearch/bing16.png" 
Sequence="0" 
LabelText="Hello, World" 
Description="SharePoint Demo" 
TemplateAlias="o1" /> 
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="{4E2F5DC0-FE2C-4466-BB2D-3ED0D1917763}" CommandAction="javascript:alert('Hello, World!')" />
</CommandUIHandlers>
</CommandUIExtension>
"@

I don’t have the BingSearch and bing image in my layouts so image breaks but code works as expected

6

 

Sample code is below, you need to change the URL, credentials and list name as applicable! Exception handling is not in place because this is built during the demo

Import-Module .\Microsoft.SharePoint.Client.dll
$Admin = "admin@contoso.onmicrosoft.com"
# Using Clear Text Password is not adviced in the script (Use Get-Credential)
$Password = "P@ssw0rd!" | ConvertTo-SecureString -AsPlainText -Force
$Credential = [pscredential]::new($Admin,$Password)
$Context = [Microsoft.SharePoint.Client.ClientContext]::new('https://contoso.sharepoint.com/sites/csom')
$Context.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credential.UserName,$Credential.Password)
$UserCustomActionCollection = $Context.Web.Lists.GetByTitle('Custom').UserCustomActions
$Context.Load($UserCustomActionCollection )
$Context.ExecuteQuery()
$here = @"
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListForm.Display.Manage.Controls._children"> 
<Button Id="{B511A716-54FF-4EAE-9CBE-EA02B51B626E}" 
Command="{4E2F5DC0-FE2C-4466-BB2D-3ED0D1917763}" 
Image32by32="~site/_layouts/Images/BingSearch/bing32.png" 
Image16by16="~site/_layouts/Images/BingSearch/bing16.png" 
Sequence="0" 
LabelText="Hello, World" 
Description="SharePoint Demo" 
TemplateAlias="o1" /> 
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="{4E2F5DC0-FE2C-4466-BB2D-3ED0D1917763}" CommandAction="javascript:alert('Hello, World!')" />
</CommandUIHandlers>
</CommandUIExtension>
"@
$NewAction = $UserCustomActionCollection.Add()
$NewAction.Location = 'CommandUI.Ribbon.DisplayForm'
$NewAction.CommandUIExtension = $here
$NewAction.Update()
$Context.ExecuteQuery()

Go through the MSDN reference links for more information! In next part I will show bit more automation of UI settings using PowerShell. Cheers 🙂 Enjoy PowerShell 🙂

Delete Navigation (Top Navigation or Quick Launch Node) Using CSOM and PowerShell

1

A colleague asked me a script for deleting nodes from Global Navigation or from Quick Launch in a SharePoint Site. Before we get into the PowerShell script lets know about the Navigation (In General). The below image illustrates the navigation settings in a SharePoint Site

2

All the headings with folder signs are parent nodes and links are children i.e child nodes. The requirement for now is to remove the parent node which can be accomplished by enumerating the appropriate collections QuickLaunch and TopNavigationBar. Here is the full script

Import-Module C:\Scripts\CSOMOnlineAssemblies\Microsoft.SharePoint.Client.dll
Import-Module C:\Scripts\CSOMOnlineAssemblies\Microsoft.SharePoint.Client.Runtime.dll

function Remove-xSPONavigationNode 
{
<#
.Synopsis
   PowerShell script to delete the parent node from Quick Launch or from Global Navigation
.DESCRIPTION
   This PowerShell script is to delete the parent node including the child nodes from Quick Launch i.e (Current Navigation)
   or from Global Navigation (Top Level Navigation bar) 
.EXAMPLE
   Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -Title 'Tasks' -NavigationType QuickLaunch -Credential 'admin@contoso.onmicrosoft.com'
   Delete the node name Tasks and child nodes from the given site (Quick Launch)
.EXAMPLE
   Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -Title 'Subsite' -NavigationType GlobalNavigation -Credential 'admin@contoso.onmicrosoft.com'
   Delete the node name Subsite and child nodes from the given site (Global Navigation)
.LINK 
   
Delete Navigation (Top Navigation or Quick Launch Node) Using CSOM and PowerShell
.NOTE @ChendrayanV http://chen.about-powershell.com #> param ( [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] $Url, [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)] $Title, [Parameter(Mandatory)] [ValidateSet('QuickLaunch' ,'GlobalNavigation')] $NavigationType, [Parameter(Mandatory)] [System.Management.Automation.CredentialAttribute()] [pscredential] $Credential ) process { try { $SPOClientContext = [Microsoft.SharePoint.Client.ClientContext]::new($Url) $SPOClientContext.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credential.UserName,$Credential.Password) switch ($NavigationType) { "QuickLaunch" { $QuickLaunchNodes = $SPOClientContext.Web.Navigation.QuickLaunch $SPOClientContext.Load($QuickLaunchNodes) $SPOClientContext.ExecuteQuery() $SPOClientContext.Dispose() for($i=$QuickLaunchNodes.Count-1;$i -ge 0; $i--) { if($QuickLaunchNodes[$i].Title -eq $Title) { $QuickLaunchNodes[$i].DeleteObject() } } $SPOClientContext.ExecuteQuery() $SPOClientContext.Dispose() } "GlobalNavigation" { $GlobalNavigationNodes = $SPOClientContext.Web.Navigation.TopNavigationBar $SPOClientContext.Load($GlobalNavigationNodes) $SPOClientContext.ExecuteQuery() $SPOClientContext.Dispose() for($i=$GlobalNavigationNodes.Count-1;$i -ge 0; $i--) { if($GlobalNavigationNodes[$i].Title -eq $Title) { $GlobalNavigationNodes[$i].DeleteObject() } } $SPOClientContext.ExecuteQuery() $SPOClientContext.Dispose() } } } catch { $_.Exception.Message } } }

How to use this script? Copy paste the code in your script location for example C:\Scripts and follow the below steps. Warning: If you have deleted the node it can’t be restored.

PS C:\Scripts> . .\Remove-xSPONavigationNode.ps1

Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -Title 'Subsite' -NavigationType GlobalNavigation -Credential $Credential

Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -Title 'Tasks' -NavigationType QuickLaunch -Credential $Credential

'Subsite2' , 'Subsite3' | Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -NavigationType GlobalNavigation -Credential $Credential

$Credential = Get-Credential -Credential ‘admin@contoso.onmicrosoft.com’ – By doing this we can pass multiple site and node title and remove the nodes from different sites

'Subsite2' , 'Subsite3' | Remove-xSPONavigationNode -Url https://contoso.sharepoint.com -NavigationType GlobalNavigation -Credential $Credential

I have removed few nodes from Top and Quick and the below image illustrates it. (Compare the preceding image)

4

In my next blog I will share few more scripts for SharePoint Online which may helps content managers to manage the site easily. Enjoy PowerShell!

Retrieve SharePoint Site Groups Information Using PowerShell

A colleague asked me a script to retrieve SharePoint Site Groups information by excluding the user’s information and added he couldn’t use Select-Object cmdlet to exclude user’s collection in the group property. Yes, it’s not possible! But, we have a fix for it and here is the PowerShell script to get Group properties by ignoring the UserCollection property in it

Import-Module C:\Users\904870.CORPORATEROOT\Documents\WindowsPowerShell\Modules\xMicrosoft.SharePointOnline.PowerShell\Microsoft.SharePoint.Client.dll
$UserName = "chendrayan@contoso.com"
$Credential = ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force
$ctx = [Microsoft.SharePoint.Client.ClientContext]::new("https://contoso.sharepoint.com")
$ctx.Credentials = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($UserName,$Credential)
$Groups = $ctx.Web.SiteGroups
$ctx.Load($Groups)
$ctx.ExecuteQuery()
$ctx.Dispose()
$Props = ([Microsoft.SharePoint.Client.Group].GetProperties() | ? {$_.PropertyType -notlike '*Collection*'}).Name 
foreach($Group in $Groups)
{
    [Microsoft.SharePoint.Client.Group]$Group | Select -Property $Props
}

Reason: We need to explicit request and execute to get user collection information but in our case it’s not required. So, simply we skipped the property which has type as collection. Note: In group property user is the only collection type property.

Import User Profile Picture from Exchange Online using EWS and PowerShell

One of our customer requested a solution to import user profile picture from Exchange Online. Not a big task but this article is to share the simple and clean method to carry out the task without MSOnline module. Yes, we use only PowerShell! At customer environment user uploads profile picture in intranet portal which saves the picture in file share, yeah I got the same question why can’t they get it from the file share? We can but not easy to do because of the profile image file naming convention, every user has an intranet portal profile ID so the files are saved as ID_DATETIMESTAMP. E.G “PROFILEID_YYYYMMDDHHMMSS”. There are many possibilities to do like query intranet portal DB to retrieve image file information and retrieve, use MSOnline module Get-UserPhoto etc.

Outclass is to use PowerShell and get it done on the fly. All we need is the EWS url for the profile picture residing in the Exchange Online and it’s shared below with sizes for reference and hew is the documentation for Get User Photos by using EWS in Exchange

1 https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=”UserEmail” &size=HR96x96 HR96x96
2 https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=”UserEmail” &size=HR240x240 HR240x240
3 https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=”UserEmail” &size=HR648x648 HR648x648

 

All set to spin up PowerShell ISE for scripting! Simply use Invoke-WebRequest cmdlet with OutFile parameter to save the profile image in disk like shown below

$Param =@{
Uri = "https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=Chendrayan.Venkatesan@contoso.com&size=HR648x648"
Credential = (Get-Credential "Chendrayan.Venkatesan@contoso.com")
OutFile = "C:\Temp\UserID.jpg"
}

Invoke-WebRequest @Param

Yay, its easy to get the profile picture information at ease without using Get-UserPhoto cmdlet and no need of Set-Content with Encoding parameters (Saves more time) ! here is my picture – Output of the above snippet!

Chen

Check out the sample script below which use ADSI Searcher to retrieve user AD information and save the picture in disk as sAMAccountName_DisplayName.jpg 🙂

function Get-xUserPhoto
{
<#
.Synopsis
   Imports User Profile Picture from Exchange Online using PowerShell and EWS
.DESCRIPTION
   This is a sample script to export user profile picture from exchange online using EWS and PowerShell.
   Use Invoke-Webrequest cmdlet
.EXAMPLE
   Get-xUserPhoto -Email Chendrayan.Venkatesan@contoso.com -Path C:\Temp\ -Credential "Chendrayan.Venkatesan@contoso.com"
   Import single user profile picture from Exchange Online and save it in C:\Temp as sAMAccountName_DisplayName.jpg
.EXAMPLE
   "Chendrayan.Venkatesan@contoso.com" , "Chendrayan.Venkatesan@contoso.com" | Get-xUserPhoto -Path C:\temp -Credential "Chendrayan.Venkatesan@contoso.com"
   Retrieves multiple user profile picture and save it in C:\temp
#>
    param
    (
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        $Email,

        [Parameter(Mandatory=$False)]
        [ValidateSet("96x96","240x240","648x648")]
        $Size="648x648",

        [Parameter(Mandatory)]
        $Path,

        [Parameter(Mandatory)]
        [pscredential]
        [System.Management.Automation.CredentialAttribute()]
        $Credential
    )

    process
    {
        try
        {
            $DEObj = ([adsisearcher]"(&(objectclass=user)(objectclass=person)(mail=$Email))").FindOne().GetDirectoryEntry()
            $Uri = [String]::Concat("https://outlook.office365.com/ews/Exchange.asmx/s/GetUserPhoto?email=",$Email,"&size=HR",$Size)
            if(Test-Path -Path $Path)
            {
                $File = [string]::Concat($Path,"\",$DEObj.sAMAccountName, "_", $DEObj.DisplayName,".jpg")
                Invoke-WebRequest -Uri $Uri -Credential $Credential -OutFile $File
            }
            else
            {
                Write-Warning "Please Check the Path"
            }
        }
        catch
        {
            $_.Exception.Message 
        }
    }
}

 

Part 4 – Getting Started With CSOM | SharePoint Online | PowerShell

Introduction

We discussed and show cased few PowerShell and CSOM functionalities in earlier blogs. Please refer to the links below

In Part 3 we showed the steps to add Format files for our Script module and in this article we will demo an alternate method to Add custom view for our objects without creating PSOject explicitly and this is just a tip to get List Property information. Do remember we are using CSOM and PowerShell and there are high chances of performance issues which will be addressed in later upcoming blog articles. For, now we will cover alternate options.

Code at Ease

process {
        $SPOClientContext = [Microsoft.SharePoint.Client.ClientContext]::new($Url)
        $SPOClientContext.Credentials = $Credential
        $ListCollection = $SPOClientContext.Web.Lists
        $SPOClientContext.Load($ListCollection)
        $SPOClientContext.ExecuteQuery()
        $SPOClientContext.Dispose()
        foreach($List in $ListCollection) {
            $List.PSOBject.TypeNames.Insert("0" , "SharePointOnline.Format.Custom.ListView")
            $List
        }
    }

What we did here is a very simple and ugly way of getting List Information and created a default view using Format.ps1xml. The advantage is we will allow users to select the required properties! So, no need to type all properties names and keeps the code neat and clean. Again! Please ignore the performance we will discuss about it soon. This function takes maximum 4 seconds and 1 second minimum to query.

Output

333 Well! It looks good for now! Let’ test it with different properties

Get-xSPOList -Url https://chensoffice365.sharepoint.com  | Select -First 5 | Select Title , NoCrawl

Get-xSPOList -Url https://chensoffice365.sharepoint.com  | Select -First 5 | Select Title , NoCrawl , Hidden

Result

444

Part 3 – Getting Started With CSOM | SharePoint Online | PowerShell

Introduction

In our last blog series we have seen few concepts of PowerShell CSOM like creating functions and including comments based help for our PowerShell functions in the module. Reference Links is below

In this article we will demo about adding format files to get desired output.

What is Format File?

Why we need to add format file? The very simple reason is to define display the object in command line. For example check the output of Get-Service cmdlet. By default it shows the properties like Status, Name and DisplayName which is defined in the file DotNetTypes.Format.ps1xml. Please use this for reference and do not modify it to avoid tampering of your existing view in PowerShell. So, when we run Get-Service we get three properties in output by default and to see more we either do one of the below as required
111. Okay, with this reference we will create our own Format File and name it as SPOnlineModule.Format.PS1XML and the location is under our module folder. To make this article easy I am opting to make List View Basic

Get Started

Let’s make our job easy! I copied the code from the List View Basic and modified my PowerShell function to meet the requirement.

<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
  <ViewDefinitions>
    <View>
      <Name>SharePointOnline.Format.Custom.ListView</Name>
      <ViewSelectedBy>
        <TypeName>SharePointOnline.Format.Custom.ListView</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Title</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>ItemCount</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

All we need to do is simple steps

  • Create a Format File and name it as SPOnlineModule.Format.ps1xml
  • Save the file inside your module directory
  • Include this file name in PSD1 file at FormatsToProcess = @(‘SPOnlineModule.Format.ps1xml’)
  • Import the Module
  • Connect to SharePoint Online and execute Get-xSPOList cmdlet which yields only two properties Title and ItemCount.

Just as an example I am selecting first 5 list and the output is illustrated below
222
Note: We haven’t fixed the Connect-xSPOTenant cmdlet yet! We need to add Conditional Scope to make it more friendly.

In our Get-xSPOList cmdlet I included the below code which appends the view name to the PSCustomObject

foreach($List in $ListCollection) {
            #$List | Select Title , ItemCount , Created , LastItemModifiedDate
            $Obj = [Pscustomobject] @{
                "Title" = $List.Title
                "ItemCount" = $List.ItemCount
                "Created" = $List.Created
                "LastItemModifiedDate" = $List.LastItemModifiedDate
            }
            $Obj.PSObject.TypeNames.Insert(0,"SharePointOnline.Format.Custom.ListView")
            $Obj
        }

 

Part 2 – Getting Started With CSOM | SharePoint Online | PowerShell

Introduction

In our last blog post (Part 1) we have show cased two functions which allows us to connect to SharePoint Online and retrieves list information from the site collections. Now, we will create a small PowerShell module with help.

About Modules

To learn about PowerShell Modules refer this link. We will be focusing about Script Module! Which is easy to understand and to troubleshoot as well. A script Module is nothing but valid script saved as .psm1 file and it has a structure to save. For our demo, we will save the PowerShell module is User Module path i.e “C:\Users\ChenV\Documents\WindowsPowerShell\Modules\SPOnlineModule” in which SPOnlineModule is the folder which contains .PSM1, .PSD1 file and required DLL’s. Ensure the psm1 and psd1 files are also named as SPOnlineModule.

Specific User

This is the location for installing modules for specific user “$home\Documents\WindowsPowerShell\Modules\

For All Users

This is the location for installing modules for all users “$EnvProgramFiles\WindowsPowerShell\Modules\”

Creating Modules

It’s very simple to create module but before distributing it ensure you have done the below

  • Test the Module
  • Include PowerShell Version
  • Create a Proper psd1 file
  • Include all required assemblies (In our case it’s required)
  • Include Help Files (This blog post will cover this!)
  • Create a Custom View for the Output

PSD1 File

This is psd1 file for the two functions we created named “Connect-xSPOTenant” and Get-xSPOList. I have moved all the SharePoint Online CSOM SDK Assemblies to my module folder. Just to distribute it to my clients and they don’t need to install the package. I have included the required dll in NestedModule Section.

#
# Module manifest for module 'SPOnlineModule'
#
# Generated by: Chendrayan Venkatesan
#
# Generated on: 11-5-2016
#

@{

# Script module or binary module file associated with this manifest.
RootModule = 'SPOnlineModule.psm1'

# Version number of this module.
ModuleVersion = '1.0'

# ID used to uniquely identify this module
GUID = 'c62fa4e8-d1d2-41e2-9304-af38c827dda9'

# Author of this module
Author = 'Chendrayan Venkatesan'

# Company or vendor of this module
CompanyName = 'Free Lancer'

# Copyright statement for this module
Copyright = '(c) 2016 904870. All rights reserved.'

# Description of the functionality provided by this module
Description = 'Include the Module Description.'

# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.0'

# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''

# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this module
# CLRVersion = ''

# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = @('GetCredential.ps1')

# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('Microsoft.SharePoint.Client.dll',
                  'Microsoft.SharePoint.Client.Runtime.dll',
                  'Microsoft.Online.SharePoint.Client.Tenant.dll' ,
                  'CredentialManagement.dll')

# Functions to export from this module
FunctionsToExport = '*'

# Cmdlets to export from this module
CmdletsToExport = '*'

# Variables to export from this module
VariablesToExport = '*'

# Aliases to export from this module
AliasesToExport = '*'

# DSC resources to export from this module
# DscResourcesToExport = @()

# List of all modules packaged with this module
# ModuleList = @()

# List of all files packaged with this module
# FileList = @()

# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{

    PSData = @{

        # Tags applied to this module. These help with module discovery in online galleries.
        # Tags = @()

        # A URL to the license for this module.
        # LicenseUri = ''

        # A URL to the main website for this project.
        # ProjectUri = ''

        # A URL to an icon representing this module.
        # IconUri = ''

        # ReleaseNotes of this module
        # ReleaseNotes = ''

    } # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module
# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

}

PSM1 File

We haven’t added help / comments or display view for the functions. All we did is created the module with required files. The below code is my PowerShell .psm1 file which has only two functions as I mentioned earlier.

function Connect-xSPOTenant {
    [CmdletBinding()]
    param(
        [uri]
        $Url,
        
        [System.Management.Automation.CredentialAttribute()]
        $Credential
    )
    
    begin {
    }
    
    process {
        if($Script:Credential -eq $null) {
            $Credentials = Get-Credential -Message "SharePoint Online Credential" 
            $Script:Credential = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credentials.UserName , $Credentials.Password)
            $SPOClientContext = [Microsoft.SharePoint.Client.ClientContext]::new($Url);
            $SPOClientContext.Credentials = $Credential;
        }
        
    }
    
    end {
    }
}

function Get-xSPOList {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [uri]
        $Url
    )
    
    begin {
    }
    
    process {
        $SPOClientContext = [Microsoft.SharePoint.Client.ClientContext]::new($Url)
        $SPOClientContext.Credentials = $Credential
        $ListCollection = $SPOClientContext.Web.Lists
        $SPOClientContext.Load($ListCollection)
        $SPOClientContext.ExecuteQuery()
        $SPOClientContext.Dispose()
        foreach($List in $ListCollection) {
            $List | Select Title , ItemCount
        }
    }
    
    end {
    }
}

Take look at the folder contents inside my module folder – And remember we named it as SPOnlineModule
2016-05-24_16-28-30 It’s good to start! Let’s try to import the module and test the functionality so we can add the requirement components which makes our module rich and easy to use.

Import-Module SPOnlineModule -Verbose

Fantastic, we can see the module loading successfully.
2016-05-24_16-32-01 always use Verbose switch to get information about the cmdlets we are loading to the session. Now, let’s see the available cmdlet by simply executing the below snippet

Get-Command -Module SPOnlineModule

and the output is shown below
2016-05-24_16-34-35 let’s skip the functionality test because we did it in our previous blog (Part 1). So we will focus on help and custom view for output formatting in this blog post. If we run the below PowerShell code we get very basic information about the cmdlet.

help Connect-xSPOTenant
help Connect-xSPOTenant -Detailed
help Connect-xSPOTenant -Examples

Something like this
2016-05-24_16-38-45 Okay enough of theory, we just need to add comment based help for our function and PowerShell will take care of the rest. To do this in our psm1 file we will include the comment based help inside the PowerShell functions like shown below

<#
.SYNOPSIS
    Short description
.DESCRIPTION
    Long description
.EXAMPLE
    C:\PS> <example usage>
    Explanation of what the example does
.INPUTS
    Inputs (if any)
.OUTPUTS
    Output (if any)
.NOTES
    General notes
#>

Just by doing this we are adding more feature to our PowerShell module and makes others to read the help before using the module. Avoids many hindrances and break dependencies at work place. Any PowerShell folks can go through the code and understand it. So, now Connect-xSPOTenant looks like below

function Connect-xSPOTenant {
<#
.SYNOPSIS
    This cmdlet is to establish connection to SharePoint Online Tenant.
.DESCRIPTION
    Prior to any other cmdlet this needs to be used. In order to perform SharePoint Online Tasks using Client Side Object Model establish the connection
    using Connect-xSPOTenant cmdlet. 
.EXAMPLE
    C:\PS> Connect-xSPOTenant -Url "https://contoso-admin.sharepoint.com"
    Prompts to enter the SharePoint Online Admin Credentials without User Name
.EXAMPLE
    C:\PS> Connect-xSPOTenant -Url "https://contoso-admin.sharepoint.com" -Credential "Admin@contoso.onmicrosoft.com"
    Prompts to enter the SharePoint Online Admin Credentials with User Name
#>
    [CmdletBinding()]
    param(
        [uri]
        $Url,
        
        [System.Management.Automation.CredentialAttribute()]
        $Credential
    )
    
    begin {
    }
    
    process {
        if($Script:Credential -eq $null) {
            $Credentials = Get-Credential -Message "SharePoint Online Credential" 
            $Script:Credential = [Microsoft.SharePoint.Client.SharePointOnlineCredentials]::new($Credentials.UserName , $Credentials.Password)
            $SPOClientContext = [Microsoft.SharePoint.Client.ClientContext]::new($Url);
            $SPOClientContext.Credentials = $Credential;
        }
        
    }
    
    end {
    }
}

which now allows us to use help at ease.
2016-05-24_16-53-24 and examples like 34334