SharePoint Online Content Type Hub Publishing Issues

We use the SharePoint Online Content Type Hub extensively as the central location to create, manage and distribute content types throughout our SharePoint Online tenant. We recently saw an issue with the distribution of one of the content types defined in the Content Type Hub which had a specific PowerPoint template assigned to it.

The content type in question had been updated with a revised template and republished, however when we tried to create a new presentation from the content type in SharePoint Online, the older template was still being served. I spent quite a long time testing a variety of PowerPoint template files of varying content and sizes with the content type (upload a new template to the content type in the Content Type Hub –> republish the content type –> wait for distribution to the site collections –> test; a process that can take some time when the content type is being distributed correctly) with no progress at all. It didn’t seem to matter what template file I uploaded to the content type, nothing seemed to be distributed. I even tried a blank Word template, and even that didn’t get distributed. Eventually I raised a Microsoft support case to help resolve the issue.

As the content type used managed metadata columns and I’d made a minor change to those, I tested with content types created using the same columns but a different template file and one using no managed metadata columns, but with what appeared to be the problematic template file uploaded. Only the example with the problematic template file was affected, but in the same way that we’d seen with the original content type, it didn’t matter what template file we uploaded afterwards, the content type and revised template were not distributed. The template we were using was obviously the issue, however it seemed to break distribution of any content type it was uploaded to from then on.

SharePoint content type templates are held in a folder structure in the root of site collections as follows:

_cts/<content type name>/<template file name>

This is true for both the Content Type Hub where the content types are distributed from, and the destination site collections.

Examining this location in the Content Type Hub (initially using PowerShell, but also using the SharePoint Client Browser), showed the following:

SPCB exploration of cts folder

As can be seen, all of the template files that have been uploaded to the content type were still present! Uploading a new template file does not appear therefore to delete the previous file that was associated with the content type. If one of the uploaded files causes issues distributing the content type, even though it may not be associated with the content type anymore, it continues to cause issues simply by being present in the folder for the content type. For example the following PowerShell retrieves the template filename and URL associated with the content type:

Get-PnPContentType -Identity “Black Marble Presentation” | select DocumentTemplate,DocumentTemplateUrl

In our case, this demonstrated that the template that was causing the issue was not associated with the content type, except by its existence in the folder for the content type in _cts.

The following PowerShell could therefore be used to remove the extraneous template files from the content type folder in the Content Type Hub site collection:

Remove-PnPFile –SiteRelativeUrl “_cts/Black Marble Presentation/<template file name>”

Using the above PowerShell I removed all of the unused template files and then republished the content type with a simple blank Word template initially to test whether the content type was distributed successfully. Once that was shown to be successful I uploaded a revised PowerPoint template file and republished the content type. The revised template was also successfully distributed.

SPWakeUp (SPWakeUp3)–Wake Up On-Premises SharePoint and WSS Instances

Since I started working with on-premises SharePoint instances, one of the solutions that I’ve used to wake up (pre-compile) the site collections and sub-sites contained within the web applications hosted by the farm is SPWakeUp.

This was originally a solution hosted on CodePlex and provided binaries for SharePoint 2007, then later SharePoint 2010 (the archive containing those can still be downloaded from the CodePlex Archive). I created compiled binaries for SharePoint 2013 and SharePoint 2016 and made those available as well.

I recently had need to use SPWakeUp on SharePoint 2019, so decided to produce a compiled for that version. As SPWakeUp doesn’t seem to have an active home anymore, I thought that it may be worthwhile putting the code and compiled versions on GitHub in case anyone else wants to use them! Note that if anyone objects to this happening, let me know and I’ll pull it down.

At the moment the repository hosts the original source code, the source code upgraded for use with Visual Studio 2019, compiled versions of SPWakeUp for SharePoint 2013, SharePoint 2016 and SharePoint 2019 and some instructions on how to compile the source yourself using Visual Studio Community 2019.

I hope it’s useful to someone!

Correcting Legacy Microsoft Teams Settings

I recently noticed that some of the Microsoft Teams that we had in use exhibited different behaviour to others that had been created more recently. ‘Recently’ (for varying definitions of ‘recent’) created Teams allowed users to edit and delete their messages, whereas a few older Teams did not. The older Teams were all created very early during our rollout of Teams, when Microsoft Teams itself was relatively new.

Checking the Teams messaging policies showed that the correct settings were in place to allow users to edit and delete their messages:

Messaging policy settings

It appeared that these settings were not however being applied for the legacy Teams. Checking in the individual Team settings showed that these were overriding the global settings applied:

Individual Team settings

Note also that in the above screen shot, the ‘Owners can delete all messages’ setting was also unchecked, although this turned out to be the only Team for which this was the case.

I could go through each Team individually and manually check the Team settings, however PowerShell allows us to perform the same actions quickly. The following PowerShell checks for the user Team settings being mis-configured and corrects the settings:

Connect-MicrosoftTeams


$teams = Get-Team | where {$_.AllowUserDeleteMessages -eq $False -OR $_.AllowUserEditMessages -eq $False}


foreach ($t in $teams) {
     Set-Team -DisplayName $t.DisplayName -GroupId $t.GroupId -AllowUserEditMessages $True -AllowUserDeleteMessages $True
}

For the other mis-configured setting mentioned, use ‘AllowOwnerDeleteMessages’ as the search criteria.

Deploying Files to the Logged-In User’s Profile Using Configuration Manager

I’ve had a number of cases where it would have been useful to be able to deploy files to a logged-in user’s profile on Windows using Configuration Manager (SCCM), but due to the context in which the ‘installation’ runs (i.e. the local system), using parameters such as %AppData% in a batch file doesn’t work, and this has always been an issue.

We recently wanted to push some custom backgrounds out to Microsoft Teams and I thought I’d spend a while trying to solve this issue. The following may not be the most elegant solution, but it seems to work reliably for me!

  1. We’re going to use PowerShell to detect the presence of a file. Copy the following into a file for the moment; we’ll need this PowerShell snippet shortly:
    Function CurrentUser {
         $LoggedInUser = get-wmiobject win32_computersystem | select username
         $LoggedInUser = [string]$LoggedInUser
         $LoggedInUser = $LoggedInUser.split(“=”)
         $LoggedInUser = $LoggedInUser[1]
         $LoggedInUser = $LoggedInUser.split(“}”)
         $LoggedInUser = $LoggedInUser[0]
         $LoggedInUser = $LoggedInUser.split(“\”)
         $LoggedInUser = $LoggedInUser[1]
         Return $LoggedInUser
    }

  2. $user = CurrentUser


    start-sleep 30


    $AppPath = “C:\Users\” + $user + “\AppData\Roaming\Microsoft\Teams\Backgrounds\Uploads\CustomBackground.png”
    If (Test-Path $AppPath) {
         Write-Host “The application is installed”
    }

    We need the sleep function in the file as the detection runs pretty quickly after the deployment and we want to be sure that the file(s) we’re going to copy are in place before attempting to perform the detection. This script extracts the username (including domain) of the currently logged in user, then separates the actual username from the returned value allowing this to be inserted into the path for detecting the file.

  3. Create a PowerShell file similar to the detection script to perform the file deployment:
    Function CurrentUser {
         $LoggedInUser = get-wmiobject win32_computersystem | select username
         $LoggedInUser = [string]$LoggedInUser
         $LoggedInUser = $LoggedInUser.split(“=”)
         $LoggedInUser = $LoggedInUser[1]
         $LoggedInUser = $LoggedInUser.split(“}”)
         $LoggedInUser = $LoggedInUser[0]
         $LoggedInUser = $LoggedInUser.split(“\”)
         $LoggedInUser = $LoggedInUser[1]
         Return $LoggedInUser
    }

  4. $user = CurrentUser


    $AppPath = “C:\Users\” + $user + “\AppData\Roaming\Microsoft\Teams\Backgrounds\Uploads\”
    cp “.\Backgrounds\*.png” -Destination $AppPath -Confirm:$false –Force

    I saved mine as ‘Deploy-TeamsBackgrounds.ps1’. This script uses the same logic as the detection script, above, to determine the username and allows us to use this in the path to copy the file(s) to.

  5. Create a batch file to call the PowerShell file that does the actual file deployment:
    Powershell -NoProfile -ExecutionPolicy Bypass -file %~dp0Deploy-TeamsBackgrounds.ps1

    I saved this as ‘Deploy-TeamsBackgrounds.bat’. This batch file runs PowerShell and passes in the filename of the scripts used to deploy the files to the user’s profile location. Ensure that the batch file and the deployment PowerShell script are in the same location somewhere suitable for SCCM to use as the application source (usually a share on the SCCM server). I then have a folder called ‘Backgrounds’ in the same location that contains the actual image files to be copied.

  6. Create a new application in Configuration Manager selecting ‘Manually specify the application information’:
    Deploy-TeamsBackgrounds01
    Then enter information on the name, publisher and version of the application:
    Deploy-TeamsBackgrounds02
    Add any required information for the Software Center entry:
    Deploy-TeamsBackgrounds03
    Click ‘Add’ to add a deployment type:
    Deploy-TeamsBackgrounds04
    and select ‘Script installer’ from the drop-down. This will automatically select the ‘Manually specify the deployment type information’ option:
    Deploy-TeamsBackgrounds05
    Provide a name for the deployment type:
    Deploy-TeamsBackgrounds06
    Specify the location that contains the files created earlier and the batch file as the command used to install the content:
    Deploy-TeamsBackgrounds07
    For the detection method, select ‘Use a custom script to detect the presence of this deployment type, the click the ‘Edit…’ button:
    Deploy-TeamsBackgrounds08
    Select PowerShell from the Script type drop-down and then paste the detection script generated earlier:
    Deploy-TeamsBackgrounds09
    and click OK to close the script editor window.
    Define the user experience:
    Deploy-TeamsBackgrounds10
    Note that I saw a warning shown at this point.
    Define any requirements (e.g. only deploy on Windows 10) and dependencies, then click through to generate the application.
  7. Distribute the content, then configure a deployment. I used the ‘All Staff’ user collection to deploy to.

Once the application appears in the Software Center, an end-user can click to install the custom backgrounds and the ‘application’ is downloaded to the Configuration Manager cache, then the batch file is triggered, which in turn executes the PowerShell script to copy the custom background images to the correct location in the user’s profile. The detection script then runs and detects the presence of the specified file.

Surface Pro 3 Type Cover Not Working After Windows 10 1903 Image Applied

Symptoms:

  • Following imaging with Windows 10 1903 using Configuration Manager OSD, the Type Cover doesn’t work at all (keyboard, trackpad).
  • When rebooting the machine, the keyboard and trackpad both work when in the BIOS.
  • When imaging the machine, both the keyboard and trackpad work in Windows PE.

The Surface Pro 3 was imaged and then patched up-to-date and the most recent Surface Pro 3 drivers available from Microsoft were applied, however the issue persisted.

To correct this issue, complete the following steps:

  1. Open Control Panel and navigate to ‘Hardware and Sound’ and then ‘Devices and Printers’.
  2. Select the Surface Type Cover and open the properties for this device. Select the ‘Hardware’ tab on the dialog:
    Surface Pro 3 Type Cover properties
  3. In turn, select each of the device functions shown in the list and click the ‘Properties’ button:
    Surface Pro 3 Type Cover devie function properties
  4. Click the ‘Change Settings’ button, then from the dialog that is shown select ‘Uninstall Device’. If offered the option to delete the driver software for this device, ensure that the checkbox to do so is selected (not all devices offer this option) and click ‘Uninstall’:
    Surface Pro 3 Type Cover uninstall device including driver
  5. Ensure this has been completed for all device functions shown in the list, then close the main properties dialog.
  6. Open the Device Manager for the computer, right-click the computer name at the top and select ‘Scan for Hardware Changes’.
  7. Expand the firmware section within Device Manager. For each of the items shown, right click the item and select ‘Update Driver’. Click ‘Search automatically for updated driver software’ from the dialog that is shown:
    Surface Pro 3 Type Cover update dirmware
    Note that if you’ve installed the latest Surface Pro 3 drivers, none of the firmware items shown are likely to be updated, but attempt to update each item. If you’ve not installed the latest drivers, the firmware list may have more generic titles which will be updated as the appropriate firmware is applied.
  8. Repeat the process of updating the driver for each item under the Keyboards section of the Device Manager. Note that even with the most recent driver pack installed, all of these entries on the device I was working on were the generic ‘HID Keyboard Device’. We don’t know which one of the keyboard devices listed is the Type Cover, however when you get to the correct one you’ll that the driver that is installed is listed as ‘Surface Type Cover Filter Device’:
    Surface Pro 3 Type Cover driver updated
  9. As soon as this driver is installed, the Type Cover should start working again. In my case no reboot was required.

SCCM OSD on Surface Pro 6

Today we attempted to re-image Rik’s new Surface Pro 6 using the usual set of task sequences that we have configured for all of the PCs that are in use, and hit an issue.

The task sequence failed (very quickly) with error 0x80070490. Looking at what was going on onscreen, it was obvious that the partitioning of the disk within the device was failing.

Initially I assumed that it was driver related and so pulled down the Surface Pro 6 driver pack from Microsoft, added it to SCCM and updated the boot media to include appropriate drivers. This didn’t solve the issue however.

Looking at the disk configuration, it became apparent that the disk number associated with the SSD within the Pro 6 was not the ‘0’ that I expected, but ‘2’ instead! It appears, following some reading that the ‘disk’ in this device, which is a 1TB drive, is actually two SSDs configured as a RAID 0 set, hence the disk number being ‘2’.

Copying the task sequence that Rik wanted to use to deploy the OS and software to the device allowed us to modify the disk number that would be used to ‘2’, which allowed the task sequence to complete successfully.

We have a couple of options available to us for deployment of these task sequences in the future:

  • Create an additional device collection and populate with the Surface Pro 6 devices to target the modified task sequence and keep a separate task sequence for deploying the OS to these devices, or
  • Use some conditional queries to determine whether we’re dealing with a Surface Pro which has two disks configured as RAID 0 and hence has a disk ‘2’.

The latter is the more elegant method and means that I won’t need to keep even more task sequences around.

To implement this, we can utilise a couple of WMI queries to determine whether we’re dealing with one of these devices:

SELECT * FROM Win32_ComputerSystemProduct WHERE name = “Surface Pro”

SELECT * FROM Win32_DiskDrive WHERE Index = 2 AND InterfaceType = “SCSI”

Both are in the standard root\cimv2 namespace.

Within the task sequence, the default UEFI partitioning step should target disk 0 and the options should look like this:

Surface Pro 6 disk configuration detection

The Surface Pro 6 1TB UEFI partitioning step should target disk 2 and the conditions should have ‘all’ rather than ‘none’ in the IF statement.

Configuring PowerChute Network Shutdown on Server Core

Everyone installing Hyper-V servers is installing them as Server Core servers, right? Smile

I recently hit an issue configuring APC’s PowerChute Network Shutdown (PCNS) software on a Server Core installation of Windows Server 1809 (the most recent release of the semi-annual channel) whereby while the installation appeared to complete successfully, I could not communicate with the service to configure it post-installation.

After a little digging, it turned out that the installer had created the firewall rule exemptions for to wrong profile (i.e. public rather than domain). The solution was to run the following PowerShell to update the profile for the PCNS firewall rules to match the network profile the server was operating on:

Get-NetFirewallRule | where {$_.DisplayName -like “PCNS*”} | Set-NetFirewallRule -Profile Domain

Once the firewall rules were updated, communication was restored and configuration could be completed from a browser running on another machine.

Windows Admin Center Updating Automatically

It was great to see that the Windows Admin Center is now being updated automatically with other Windows Server OS updates when I updated the server on which it is installed the other day:

Windows Admin Center Update in Updates List

One fewer thing to have to check for manually!

Windows 10: We can’t add this account

A colleague recently started seeing an issue when attempting to add their work account to a Windows 10 device. Following a device re-image (this, as we’ll see becomes important…), a colleague saw the following error reported when attempting to add their work account:

Windows 10 we can't add this account

The full text of the error reads

We can’t add this account. Your organisation’s IT department has a policy that prevents us from adding this work or school account to Windows.

Initially we looked at whether recent policy changes had in fact impacted the ability to add a work account to a Windows 10 device, but were not seeing anything that appeared to impact this. We had other users who were receiving new PCs that were unaffected and had the same policies applied to them. In addition, nothing was showing up in the event viewer folder for Workplace Join on their machine when attempting to add the account.

Realising that the machine had just been reimaged, we checked in Azure AD to view the list of devices. The following is a screen shot for a different device ID, however this was similar to what we saw:

Device list in Azure AD

As can be seen, there are multiple instances of the ‘same’ machine. In each case, the machine has been reimaged and then had the work account added. In each case, Azure AD has obviously assigned a new device ID, hence what appears to be multiple copies of the same machine registered.

Once we’d deleted a few of the ‘old’ machines from the list, the user was able to successfully add their work account to the device.

There are a couple of potential solutions in our scenario:

  1. Periodically check the number of devices registered and trim as appropriate.
  2. Raise the limit of the number of devices that can be registered, either to a larger number, or to ‘unlimited’ in the device settings area of Azure AD.

Azure AD Device Settings

System Center Data Protection Manager 2016 Delegated Administrator

I recently had a requirement to add a delegated administrator to DPM 2016. While it’s possible to configure self-service recovery, there doesn’t appear to be any way that I can configure another user to perform the delegated admin role as there is in some other System Center products.

It is possible to configure another user to be a delegated DPM admin if you’re willing to roll up your sleeves and get a little grubby with the config however! Note that I’m fairly sure that doing this will impact support, but it’s easy to undo if required.

The problem:

  1. There’s nothing in the DPM interface that appears to allow configuration of a delegated admin.
  2. Adding a user as a local admin of the DPM server still doesn’t allow the user concerned to administer DPM. When trying to launch the DPM console, the following error is shown:
    Unable to connect to DPM server error
  3. Granting the user logon locally permissions still requires that the user elevates when launching the DPM console, so realistically they should be made a local admin on the DPM server.

The solution:

  1. Grant the user local admin rights on the DPM server. I’d strongly suggest creating a dedicated admin account for the user rather than using their day-to-day account for this purpose.
  2. On the SQL instance that DPM uses, configure the following:
    1. Create a new login for the account that will be used as a delegated admin.
    2. Right-click the new account and select ‘Properties’.
    3. Select the DPM database and in the database role membership section of the dialog, select the appropriate DPM-related permissions for the user. To give the user full admin permissions on DPM, select all of the ‘MSDPM…’ role checkboxes:
      DPM delegated admin SQL rights
    4. Click OK to close the dialog.
    5. Check that the user can a) log onto the DPM server and b) successfully launch the DPM admin console and administer the service.