Author Archives: ArmgaSys

Automate user photos in Exchange

The introduction of hi-resolution photo support within Exchange solved the photo quality issues in various Microsoft products such as Outlook and Skype for Business (Lync).  For many companies, the next question became “How do I get my corporate approved photos uploaded to Exchange?”

Here at ArmgaSys, we asked the same question.  Here is our solution

The Challenges

  1. Build a PowerShell script to automatically upload corporate photos to Exchange.
  2. Automate the process via a scheduled task using the least privileges possible.
  3. Prevent users from uploading their own pictures and overriding the corporate approved (non-cat/clown/other) photos.

The PowerShell Script

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn;

$imgFolder = ‘C:\Headshots\’

foreach ($pic in Get-ChildItem $imgFolder)
        Set-UserPhoto `
            $pic.BaseName `
            -PictureData ([System.IO.File]::ReadAllBytes(“$imgFolder\$($pic.Name)”)) `
        Remove-Item “$imgFolder\$($pic.Name)”
        Write-Warning “Warning : $_”

# Update Exchange policies to prevent users from uploading their own pictures
Get-CASMailbox -ResultSize Unlimited | Set-CASMailbox -OWAMailboxPolicy Default
Get-OWAMailboxPolicy | Set-OWAMailboxPolicy -SetPhotoEnabled:$false

Script Usage Notes

  • Be sure to set the variable $imgFolder to the location of your headshots
  • This script assumes image deltas.
    I.E. only new or changed images should be processed.  As such, the script deletes the image after it is completed. If you want to process every user image every time the script is run, remove the line:
    Remove-Item “$imgFolder\$($pic.Name)”
  • Important: Be sure to include the backtick (line continuation character) in your script if you leave the Set-UserPhoto command on multiple lines!
  • This script will reside directly on the Exchange server

Scheduling the Script
Using Task Scheduler on the Exchange server that houses the script, create a task to run at the time intervals desired by your needs.  Set the remaining options as follows:
Security Options
Set the user account to NT AUTHORITY\NETWORK SERVICE
Action = Start a program
Program Script = PowerShell.exe
Add arguments (optional) = -ExecutionPolicy Bypass [Full path and file to your script]
                 Example: -ExecutionPolicy Bypass C:\Scripts\Headshot.ps1


Setting up Security: Headshots Folder
Grant the Exchange computer Modify access to the folder which contains the headshots. 
NOTE: If your script will not delete the Headshot images, you can grant Read-Only access to the folder.


In our example above, the server name is SRVEXCH16 and resides in the ArmgaSys corporate domain.
Important: You will need to make sure the Object Types includes Computers!

Setting up Security: Script Access to Exchange
Grant the Exchange computer access to the user’s mailboxes so the script can upload the user images.

  1. Launch the Active Directory Users and Computers snapin
  2. Open the OU Microsoft Exchange Security Groups
  3. Open the group Help Desk
  4. Add the Exchange computer running the script as a member
    In our example above, the server name is SRVEXCH16 and resides in the ArmgaSys corporate domain.
    Important: You will need to make sure the Object Types includes Computers!

Populating Headshot Images
Now all you need to do is populate your headshots directory and test!
Important:  The script assumes all headshot images are in the format of [ExchangeUserName].[EXT].  In our organization, we use [FirstName].[LastName] as our Exchange user name format.

So, an example headshot image dropped into our headshots directory would be



LegacySiteDetected during upgrade to SharePoint 2016

So, you are happily migrating your SharePoint 2013 content database to SharePoint 2016 when the Test-SPContentDatabase command spits out:

Category        : LegacySiteDetected
Error           : True
UpgradeBlocking : True
Message         : 1 site(s) using SharePoint 2010 experience.
Remedy          : Please upgrade sites using SharePoint 2010 experience
                  in database [Your Content Database] to SharePoint 2013
                  experience before proceeding.

Wait a second???  We are migrating from 2013?  How did a SharePoint 2010 experience get in there?

Root Cause
The content database you are migrating to SharePoint 2016 was very likely using the SharePoint 2010 Office Web Apps.

The Fix
Step#1: Locate the offending SharePoint 2010 site

  1. Launch SQL Server Management Studio (SSMS)
  2. Connect to the offending content database
  3. Execute the following query:

    SELECT, als.PlatformVersion, aw.Title, aw.FullUrl, aw.ProductVersion, als.Deleted
    FROM dbo.AllSites als
         INNER JOIN dbo.AllWebs aw
      ON aw.Id = als.RootWebId

  4. Locate the entry that does not have a product version of 15.  It will most likely look like this:

    PlatformVersion    Title             FullUrl                         Team Site         sites/Office_Viewing_Service_Cache

Step#1: Deactivate (Delete) the offending SharePoint 2010 site

  1. Note the GUID associated with the site you identified in Step#1 above
    (This will be the id column)
  1. Run the following query using SSMS connected to the content database:

    UPDATE dbo.AllSites
    SET Deleted = 1
    WHERE id = ‘[GUID]’


SharePoint: Upgrade 2013 content to 2016

Performing an upgrade to SharePoint 2016 is relatively straight forward, but is not as easy as upgrading, say, Microsoft Office.  There are some considerations which must be taken into account before performing an upgrade.

Consideration#1: There is no direct upgrade from SharePoint 2010 to SharePoint 2016
You can only upgrade from SharePoint 2013 content databases.  If you have a SharePoint 2010 installed, please upgrade to SharePoint 2013 first.  See this blog entry on how to upgrade to 2013.

Consideration #2: There is no in-place upgrade from SharePoint 2013
You must upgrade each content database using the Database Attach and upgrade Method.  This blog entry will cover the attach and upgrade method in detail.

Consideration #3: SharePoint 2016 does not support classic mode authentication.
In our experience, many SharePoint 2013 web applications still utilize classic mode authentication.  For content databases using classic mode authentication, you must migrate to Claims Based authentication before you begin migrating your data.  See the Dealing with legacy (classic mode) Authentication section at the end of this blog post before you start your migration process!

OK, Lets dive into the details
IMPORTANT: We strongly recommend reading all of the steps below *before* beginning the migration and upgrade process.  It’ll just make your life much easier Smile

Step#0 – Backup everything related to the content database you are migrating
Nuf’ said!

Step#1 – Attach the SharePoint 2013 content database to the new database server.
This step only applies if you are also migrating to a new database server during the SharePoint 2016 migration process. If you are not changing database servers, skip to step#2 as the content database will already be in place and ready to upgrade.

Step#2 – Create a new web application in SharePoint 2016

  1. Launch SharePoint 2016 Central Administration web site.
  2. Navigate: Application Management –> Manage Web Applications
  3. Click New on the ribbon
  4. Configure the new web application to replicate the web application being migrated
    NOTE: Take the default for Database Name which is “WSS_Content”

Step#3 – Delete the content database which was just created in Step#2
Yes, you read correctly, delete the content database.

  1. Launch SharePoint 2016 Central Administration web site.
  2. Navigate: Application Management –> Manage Content Databases
  3. Select the web application created in step#2 from the web application drop down located in the upper right of the browser
  4. Click on the Database Name which was created in step#2
    It should be named WSS_Content
  5. Scroll to the bottom of the database information page displayed and check the Remove Content Database checkbox
  6. Click the OK button

So, what is happening here?
SharePoint requires a target web application for ALL content databases. Why? Because the web application determines which features are supported and installed for all content hosted by that web application. When the actual migration process occurs, the upgrade software scans the content database for all of the features being used by the content (I.E. lists, document repositories, third party, web parts, etc.) and then determines if the target web application supports that feature.

The problem we encounter is that SharePoint has nicely created an empty content database which we are never going to use because we already HAVE a content database (the one we are migrating). So, we need to perform a little bit of cleanup work.

Step#4 – Validate the SharePoint 2013 content database can be upgraded
SharePoint provides a PowerShell comment which will validate the content database against the web application created in Step#3.

  1. Launch SharePoint 2016 Management Shell as an administrator
  2. Enter the following command

-Name <DatabaseName>
-WebApplication <URL>


-Name “WSS_Contoso2010ContentDB”

Review the output for any issues listed as Upgrade Blocked: Yes
Any issue listed as Upgrade Blocked will need to be corrected.
Google will be your dearest friend if you encounter Upgrade Blocked: Yes

Step#5 – Mount the database onto the web application created in Step#3
This step will upgrade and mount the database against your newly created web application

  1. Launch SharePoint 2016 Management Shell as an administrator
  2. Enter the following command

-Name <DatabaseName>
-WebApplication <URL>


-Name “WSS_Contoso2010ContentDB”

Step#6 – Reset and validate!
We recommend executing an IISRESET after each migration / upgrade is completed.
Then launch the SharePoint site to validate everything is running.

Dealing with legacy (classic mode) Authentication
Classic mode authentication has been officially depreciated by Microsoft.  If you are migrating a classic mode authentication based content database, you must convert the database to claims based authentication before migration (I.E. while the content database is still attached to SharePoint 2013).  You convert the database to claims based using the Convert-SPWebApplication PowerShell command. 

  1. Launch SharePoint 2013 Management Shell as an administrator
  2. Enter the following command

-Identity <URL>
-To Claims


-To Claims