Get SharePoint List Inventory using PowerShell

PowerShell scripts are very useful to generate some amazing reports, recently I have written a PowerShell script which retrieves all lists and libraries for a SharePoint site collection under all sub sites with item count and versioning enabled.

This is a report which can be very useful when you are going to the delta/cutover migration and you can get the details for list and libraries recently modified and also item count.

Use this report to compare list count including item count in each list for different sites (useful in migrations).

You can download the script directly from GitHub repository.

Include the reference SharePoint PowerShell.

if ((Get-PSSnapin “Microsoft.SharePoint.PowerShell” -ErrorAction SilentlyContinue) -eq $null)
Add-PSSnapin “Microsoft.SharePoint.PowerShell”

I am going to create a function name “GetListInventory” which will take one site Url as parameter.

function GetListInventory($siteUrl)
$webApp = Get-SPWebApplication $siteUrl

$SiteDetail = @();

Foreach ($web in $webApp | Get-SPSite -Limit All | Get-SPWeb -Limit All)
Write-host “Processing site $web.Name…”

foreach($list in $web.lists)
$row = new-object PSObject
Add-member -inputObject $row -memberType NoteProperty -Name “Site Name” -value $web.Name
Add-member -inputObject $row -memberType NoteProperty -Name “URL” -value $web.Url
Add-member -inputObject $row -memberType NoteProperty -Name “List Title” -value $List.Title
Add-member -inputObject $row -memberType NoteProperty -Name “List Item Count” -value $list.Items.Count
Add-member -inputObject $row -memberType NoteProperty -Name “Last Modified Date” -value $List.LastItemModifiedDate
if ($list.EnableVersioning -eq $TRUE)
Add-member -inputObject $row -memberType NoteProperty -Name “Versioning” -value “Yes”
Add-member -inputObject $row -memberType NoteProperty -Name “Versioning” -value “No”

$SiteDetail += $row;

I have used list.Items.Count property instead of Lites.ItemCount.

Difference between List.items.Count and List.ItemCount

Now you have compiled the above script, call the function to generate the list inventory. You can either print output on Out-GridView or in a CSV file using Out-File.

GetListInventory “http://SP2016Farm” | Out-GridView

SharePoint List Inventory

In above report, you can see the Site title, site URL, List name, no. of items, Last Modified Date and versioning which will be yes if enabled

But it will be very useful if you copy the content from above report into excel or generate a csv report will using Out-file:

GetListInventory “http://SP2016Farm” |  Out-File “E:\Reports\ListInventory.csv”

SharePoint List Inventory Out-File

Using excel you  can apply different sorting orders and filters in excel like to get the list with maximum no. of items, latest or lest modified list, lists with versioning enabled or for any specific site. These types of filters are quite easy in excel. Instead of applying these filters in PowerShell, generate lists inventory like this and then perform different actions on it.

Important: I have tested this script in SharePoint 2010, SharePoint 2013 and SharePoint 2016.

Changing site logo for all sub sites in a Site collection for SharePoint Online (Office 365)

In my previous article, I shared details for changing site logo for a site collection and its sub sites using PowerShell, but that was only for on-premise environment. PowerShell script for SharePoint Online is different from on-premise where we refer SharePoint client dlls, make sure you should have installed SharePoint Online Management Shell, if not then you can download it from this link.

I have update the script at technet gellery for changing site logo for both SharePoint On-Premise as well as for SharePoint Online, you can download it from this link.

MsTechtalk Technet gallery

Below is the PowerShell script which update the site logo for all sub sites under a site collection, it will ask you for site URL, user name and password.


$siteUrl = Read-Host -Prompt “Enter site collection URL (” #you can also set the site URL
$userToLogin = Read-Host -Prompt “Enter Username” #you can also set the user name, make sure it should be global admin
$password = Read-Host -Prompt “Enter Password” -AsSecureString
$sitelogoURL = “/SiteAssets/newSitelogo.gif” #change the site logo
$clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($userToLogin, $password)

$clientContext.Credentials = $credentials

$web = $clientContext.get_web()
$webs = $clientContext.Web.Webs;


function updateSubSites($subWeb) {
$subsites = $subWeb.Webs;
foreach ($subSite in $subsites) {

function updateSiteLogo($subWeb) {
$subWeb.SiteLogoUrl = $sitelogoURL

Write-Host “Updated logo for ” $subWeb.Title ” , site url:” $subWeb.Url


foreach ($subWeb in $webs)
write-host “inside bottom foreach”

You might get below exception if the user is not global admin, so make sure you have credentials for global admin.

Exception calling “ExecuteQuery” with “0” argument(s): “The Login server cannot issue the requested compact encrypted ticket because a Data Encryption Key (DEK) has not been uploaded to the site.”

At line:19 char:1

+ $clientContext.ExecuteQuery()

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : IdcrlException

SharePoint: Difference between List.items and List.ItemCount

The basic difference between List.items and List.ItemCount is that list.items returns total no. of list items excluding folders while list.ItemsCount return total no. items in a list including folders.

Check SPList.ItemCount property

Check SPListItemCollection.Count property

There is one more major difference between them is that List.Count shows only those items which are shared with the current user as item collection is security trimmed whereas List.ItemCount return all items and as it is not security-trimmed.

One more thing is that List.ItemCount is faster because it fetch the information from SPList property instead of building SPListItemCollection.

Deleting List Items throws “Specified argument was out of the range of valid values” Exception

One more thing is that List.ItemCount is faster because it fetch the information from SPList property instead of building SPListItemCollection.

And a good example of this is when you are trying to delete list items through loop using list.Count, you might get “Specified argument was out of the range of valid values” exception because you are deleting the list item from list item collection.

//Delete List items

for (int i = 0; i < list.Items.Count; i++)

To resolve the issue, use List.ItemCount which gives you the static item count value from list property.

for (int i = 0; i < list.ItemCount; i++)

SharePoint how to lock and unlock a site collection

Making a site read-only (also known lock) is required most of the time when you are going to migrate to newer version and restrict user for any modifications. This is most of the time required over cut over migration.

If you have to lock a web application read-only which contain multiple site collections then you have to mark each of them read-only.

There are four options for changing lock status of a site collection

  • Read Only
  • Not Locked
  • Adding Content Prevented
  • No Access

Check this link for more details on locking options

There are multiple ways to lock a site collection.

  1. Using SharePoint Central Admin
  2. Using PowerShell
  3. Using STSADM

Using SharePoint Central Admin

This is the easiest way to lock/unlock a site collection. Go to SharePoint Central Admin –> Application Management –> Site Collections –> and click on Configure Quotas and Locks

Configure Quotas and Locks

This will take you to the configure Quotas and lock page, change the site collection which you want to lock or unlock.

Configure Quotas and Locks - SharePoint 2010

You can see four different options, select read-only if you want lock the site collection or select Not locked to unlock the site collection.

The above screenshots are from a SharePoint 2010 Farm, you can follow the similar steps to lock/ unlock sites on SharePoint 2007, SharePoint 2013 and SharePoint 2016.

SharePoint 2007

Configure Quotas and Locks - SharePoint 2007

SharePoint 2016

Configure Quotas and Locks - SharePoint 2016

Using PowerShell

You have seen four different options in above screenshots for different lock status. Below are the four PowerShell cmdlets to execute the similar functionality, this way is faster for SharePoint admins instead of going through central admin.

  • Set-SPSite -Identity “http://sp2010/sites/site1” -LockState “ReadOnly”
  • Set-SPSite -Identity “http:// sp2010/sites/site1” -LockState “Unlock”
  • Set-SPSite -Identity “http:// sp2010/sites/site1” -LockState “NoAdditions”
  • Set-SPSite -Identity “http:// sp2010/sites/site1” -LockState “NoAccess”


I would recommend to using PowerShell cmdlets for locking / unlocking a site collection but if you are using SharePoint 2007 or WSS 3.0 (or older version) then you still use the central admin or can use below cmdlets

  • Get site lock status: stsadm -o getsitelock -url http://sp2007
  • Lock site: stsadm -o setsitelock -url http://sp2007-lock noaccess
  • Remove site lock: stsadm -o setsitelock -url http://sp2007 -lock none

Azure AD Sync Permissions Error: Error Code 8344

Azure AD Sync Export Error “Permissions-Issue”

Today i have been working on troubleshooting Azure AD Sync tool for one of my customer where they were having issues with the tool. MIIS client was reporting export errors for all the users in the organization and the error was “Permissions-Issue”. It was one of the interesting errors to work on and it took me a day to resolve the issue and i thought to share the remedy with all of you so that you should be able to resolve this issue within an hour.

Azure AD Sync Export Error

Whenever AAD Sync perform synchronization with office 365, evertime we were getting the error message on “Export”. If we look at the error message it says “Permissions-issue” and we verified that our on prem service account and Office 365 service account has all the required permission for AAD Sync tool. At one stage we thought it’s a false error but No it’s not a false error and it does have a solution. Below is the screenshot of error message that we were getting.

1When you click on permission-issue you’ll see the following screenshot which is giving us the details of error message along with error code.


Let’s get started to resolve this error and below are the steps that we need to perform to resolve this issue.

Resolve AAD Sync Export Error

If you click on Permission-Issue to see the detail you’ll see that Connected date source error code is 8344. To resolve this issue, perform the following steps

1. Run Active Directory Inheritance script to get a list of users on which inheritance is blocked. Once you’ve the list pls make sure that you allow inheritance on those users/groups.

To allow inheritance, Make sure Advance Features are enabled in View then go to user properties –> Security –> Advanced –> Select the check box “to include inheritable permissions from this object’s parent”

2. Make sure you’ve the required on prem permissions assigned to Azure AD Sync tool service account. You can assign the appropriate permissions to Azure AD Sync tool by following this article.

3. Once you’ve check the inheritance and required permissions. Make sure that the service account is a part of AAD Sync security group in active directory. The name of security group is MSOL_AD_Sync_RichCoexistence. After you add the service account to the group, re-run the full synchronization and you will see that all permission-issue errors are gone.

In my case, customer was using AAD Sync along with password sync and they had Exchange 2010 SP3 hybrid configured.

Hope this article will help you resolve your issue with Azure AD Sync tool. Please feel free to ask us in case you have other issues. Thanks.

Step by Step Azure AD Sync Installation Guide (Part 5)

Change Default Sync time of Azure AD Sync

In Part 4 of this article series, we learned about how we can manually synchronize on prem identities and password hash with office 365. In this article we will learn how we can change the default synchronization time of Azure AD Sync tool to meet our requirements.

Let’s get started with Part 5 of this series.

Default Synchronization

By default Azure AD Sync tool synchronize with office 365 after every 3 hours just like Dir Sync tool. Dir Sync determines the time to synchronize with office 365 using Microsoft.Online.DirSync.Scheduler.exe.config file located in “C:\Program Files\Microsoft Online Directory Sync” but this has been changed with the new Azure AD Sync tool and now we have Windows Tasks Scheduler to determine / modify the time to sync with Office 365.

By Default, Azure AD Sync schedule runs after every 3 hours executed by a schedule tasks. This scheduled task actually runs DirectorySyncClientCmd.exe in the backend and perform delta sync.

To modify the default synchronization time, we need to perform following steps.

  • Log on to Sync server using on prem Sync service account. In our case, we’re using as service account.
  • Go to start menu and search for Windows Tasks Scheduler


  • In windows tasks scheduler Library, you can notice that a task with the name of Azure AD Sync Scheduler is defined to triggered after every 3 Hours.


  • We can’t modify the task if it’s enabled. To modify the scheduler Right Click on Task –> Click Disable to disable the task as shown below


  • After disabling the schedule, double click on task and go to Triggers as shown below



  • Select the Trigger and click on Edit to edit the schedule trigger. Currently you can see the trigger is defined to run after every 3 hours and it’s set to run for Indefinitely.


  • From the drop down menu of “Repeat task every” Select the time after which you want to trigger Azure AD sync with office 365. In our case I’ve modified the time to 10 minutes.



  • Click Ok to close the Trigger editor. Click on Ok to Azure AD Sync Scheduler Properties as well to complete the process.


  • When you click on Azure AD Sync Scheduler Properties, It will prompt you to enter the Password of Microsoft account created during the installation and configuration but we can replace that account with our Azure AD Sync on prem service account. Enter your on prem Azure AD Sync service account credentials and hit Ok.


  • After modifying the trigger settings, you can see that you have successfully modified the default sync time of Azure AD Sync tool to 10 minutes.


  • Last action that we need to perform after changing the default sync time is to enable the scheduler by Right Clicking on the scheduler and Click Enable.

This brings us to the end of this article in which we learned how to modify the default sync time of Azure AD Sync tool. If you want to read other articles of this series please go through the following URLs.

Enable / Disable Skype for Business Client

Step by Step to Enable / Disable Skype for Business client

In my previous post, I shed some light on new Skype for Business Client (formally known as Lync client ) look and options available to end user. This post will focus on the steps require to enable or disable Skype for Business Client for end user. Being an administrator you can control whether a user can use Skype for Business or not. With that being said, let’s get started with this post.

Before we start, i assume that you currently have Lync 2013 deployed in your infrastructure and the steps mentioned below are tested on Lync 2013 server edition. Here are the steps to Enable or Disable Skype for Business client in Lync 2013 server.

Mostly Microsoft product updates are pushed to end users from Windows Updates and Microsoft prefer to push new product updates from Windows Updates too. You can either manage Windows Updates centrally using WSUS and allow which updates can be pushed to end users machine and if you don’t have any centralized Patching system then you probably come up with this scenario where few users update their Lync client to Skype for Business and few using Lync. Once lync client is updated to Skype for Business client users will get the following pop up.


Most of the companies wants to standardize their software deployment and if you want to manage standardization of Lync client without using any central management system then here are the steps which will help you to control lync client version on your end user machines.

Enable Skype User Interface

By default Skype for Business client UI value is Null in Lync Client policy. We can check client policy setting using this cmdlet,

Get-CsClientPolicy -Identity Global <PolicyName>


We can allow Skype for Business client interface using following cmdlet in Lync Management Shell,

Set-CsClientPolicy -Identity Global -EnableSkypeUI $True

To enable for particular set of users,

New-CsClientPolicy -Identity AllowSkypeUI -EnableSkypeUI $True

Grant-CsClientPolicy -Identity <sip address> -PolicyName AllowSkypeUI


After configuring client policy, Lync client will prompt for restart,


Disable Skype User Interface

To disable Skype for Business client user interface run the following command in Lync management shell,

Set-CsClientPolicy -Identity Global -EnableSkypeUI $False

Registry Settings

Administrators can control the client interface using registry settings too. Here is the registry location:


To change registry settings using powershell,

Enable Skype for Business: Set-ItemProperty HKCU:\Software\Microsoft\Office\Lync -Name EnableSkypeUI -Value 00,00,00,01

Disable Skype for Business: Set-ItemProperty HKCU:\Software\Microsoft\Office\Lync -Name EnableSkypeUI -Value 00,00,00,00


Step by Step Azure AD Sync Installation Guide (Part 4)

Azure AD Synchronization using PowerShell

In Part 3 of this article series, we learned about different filtering options available to us and how we can use them to fulfill the requirements. In this article we will learn on how we can manually force a synchronization using PowerShell and how we can change the default synchronization time of Azure AD Sync.

Let’s get started with Part 4 of this series.

Azure AD Full Synchronization

We’ve a utility called DirectorySyncClientCmd.exe which executes the sequence of actions to synchronize on prem identities with office 365.

To run a full synchronization browse to “C:\Program Files\Microsoft Azure AD Sync\Bin” from windows powershell and run the cmdlet .\DirectorySyncClientCmd.exe Initial as shown below. “Initial”will perform a full synchronization.


It’s recommended that you perform a full synchronization after making a major change in your Azure AD Sync configuration like enabling password synchronization for user.

Azure AD Delta Synchronization

To perform the delta synchronization with Office 365, we need the same executable to perform delta synchronization of users from on prem to office 365. By default Azure AD Sync tool performs delta sync after every 3 hours. Later in this article we’ll learn on how we can change the default sync time of the tool. To perform the delta synchronization we use the .\DirectorySyncClientCmd.exe executable with Delta keyword as shown below.


Azure AD Password Synchronization

Password Sync was one of those features which helped a lot of enterprises to manage their users password policies and change management from local active directory. Password Synchronization enables users to log into their Office 365 and other Microsoft online services like Intune, CRM etc using the same password as they use to log into their on-premises infrastructure. It is important to note that this feature does not provide a Single Sign-On solution because there is no token sharing in the Password Sync process. This feature is also referred as Same Sign-On.

Active Directory Domain Services that are configured for FIPS are not compatible with the Password Sync feature.  During Password Synchronization Plain text version of a user’s password is neither exposed to the password sync tool nor to Azure AD or any of the associated services. Azure AD Sync tool synchronize the user’s password in the form of hash.

When you’ve password synchronization enabled then password complexity policy and password expiry policy on office 365 will no longer be valid and on prem policies will be applicable.

To perform a Password Synchronization, We need to run the Password Synchronization with Office 365 using Azure AD Sync. You can download this script from Technet.


More details on password synchronization can be found on Technet.

Verifying Manual Synchronization

To verify the Full and Delta Synchronization, Log in to Office 365 Portal and Browse to users –> Active Users and check the last sync time. You can also check the MIISClient for last sync time and status of sync.


To verify the password synchronization is completed successfully, Go to Event Viewer –> Application Logs and look for Event ID 656 and 657 as shown below.



If you want to read the other Parts in this series, then please go to:

Skype for Business Client Announced

What’s New in Skype for Business Client

Finally ! Microsoft has announced the availability of Skype for Business. Skype for Business client was available for end users in Preview but yesterday Microsoft released the new update for Lync 2013 client KB2889923.

Microsoft rebranded Lync client to Skype for Business client. New Lync client is named as Skype for Business. Skype for Business client has new look then the Lync client but a look similar to Skype for consumer for user adoption and ease of usage. Here I’m going to walk you through some of the new look and feel of Skype for Business Client.

You can download Skype for Business client update from Microsoft download center.

Here are the new look of Skype for Business client


New One click Call controls in Skype4B client

Call Control

Meeting Experience


New Emotions in Skype for business meeting and chat window,


New call control bar, when Skype4b client is in background,

Call BG

New Phone tab look in Skype for Business client,


New Skype for business client icons in outlook for meeting schedule, join Skype meeting and meeting invitation.

join      MSchedule


Here are the new settings in Skype4B client Options