Listing all scopes in a Workflow Manager instance using PowerShell

August 12, 2013 4 comments

One of the pains I have encountered with setting up the Workflow Manager for use with SharePoint is that there is no clear visibility into the scopes that are currently on the Workflow Manager farm. It was hard to understand what scopes were already created, which of those were active, what the parent-child hierarchical relationships among those were and what applications were connected to those scopes.

So I tried to figure out if there was a way through OM code to get to this information or at least as much of it as I can get to without spending a whole lot of time and research. And below is what I could whip up.

param([parameter(mandatory=$true)][string]$Endpoint, [string]$Path = "/", [string]$Parent = "None")

[Reflection.Assembly]::Load("Microsoft.Workflow.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35") | Out-Null
Write-Output ""

function WriteScopeInfo([string]$scopeUri, [string]$path, [string]$parent) {
    $scopePath = $scopeUri + $path
    $client = New-Object -TypeName "Microsoft.Workflow.Client.WorkflowManagementClient" -ArgumentList $scopePath
    $manager = $client.CurrentScope
    $scope = $manager.Get()

    Write-Output "Name: `t`t`t$($scope.DisplayName)"
    Write-Output "Path: `t`t`t$($scope.Path)"
    Write-Output "Status: `t`t$($scope.Status.ToString())"
    Write-Output "User Comments: `t$($scope.UserComments)"
    Write-Output "Parent: `t`t$parent"
    Write-Output "Children: `t`t$($scope.ChildScopeCount)"
    Write-Output ""

    if ($scope.ChildScopeCount -gt 0) {
        $manager.GetChildScopes() | % { WriteScopeInfo $scopeUri $_.Path $scope.Path }
    }
}

WriteScopeInfo $Endpoint $Path $Parent

Note that the script requires 3 inputs, one of which is mandatory. The Endpoint parameter requires the URL to the workflow endpoint. This will likely be a web application on port 12290 or 12291 depending on whether you set up the Workflow Manager farm to just use HTTPS (which is the default) or also HTTP. Please refer to this post if you are not sure how to set up the Workflow Manager farm.

The other two parameters are just used to kick things off for the scope discovery function. The first called Path is used to determine the node in the scope tree that you want to begin with. By default, this assumes the value “/” representing the root scope on the farm. But if I know of another scope somewhere down the tree and the branches and spring thenceforth are the only ones I am concerned with, I would pass it so – “/myscope/subscope”. The second called Parent is only required to identify the parent of the scope node that I am starting at. It is not really required and assumes the value “None” by default.

When run the script produces an output as shown below. As you can see, I am providing the endpoint URL of the Workflow Manager instance installed on my machine.

clip_image001

For those that are unable to use PowerShell, here is the C# version of the same thing.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Workflow.Client;

namespace WorkflowClient
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string workflowEndpoint = string.Empty;
                if (args.Length < 1)
                {
                    Console.Write("Provide workflow endpoint URL: ");
                    workflowEndpoint = Console.ReadLine();
                }
                else
                {
                    workflowEndpoint = args[0];
                }
                Console.WriteLine("");
                WriteScopeInfo(workflowEndpoint, "/", "None");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);
            }
            finally
            {
                Console.WriteLine("Press any key to end...");
                Console.ReadKey(true);
            }
        }

        private static void WriteScopeInfo(string scopeUri, string path, string parent)
        {
            try
            {
                WorkflowManagementClient client = new WorkflowManagementClient(scopeUri + path);
                ScopeManager manager = client.CurrentScope;
                ScopeDescription scope = manager.Get();

                Console.WriteLine("Name: " + scope.DisplayName);
                Console.WriteLine("Path: " + scope.Path);
                Console.WriteLine("Status: " + scope.Status.ToString());
                Console.WriteLine("User Comments: " + scope.UserComments);
                Console.WriteLine("Parent: " + parent);
                Console.WriteLine("Children: " + scope.ChildScopeCount.ToString());
                Console.WriteLine("");

                if (scope.ChildScopeCount > 0)
                {
                    Collection<ScopeDescription> children = manager.GetChildScopes();
                    foreach (ScopeDescription child in children)
                    {
                        WriteScopeInfo(scopeUri, child.Path, scope.Path);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message + ex.StackTrace);
            }
        }
    }
}

I hope to be able to use this to keep things clean/sane when I have more applications using my workflow farm and needing more scopes and child scopes.

Managing Quota Templates on SharePoint through PowerShell

August 10, 2013 3 comments

Quota templates are a seldom used but practically important feature in SharePoint. Important because it allows administrators to keep tabs on what sites can consume what level of storage without having to keep close watch on them. Defining a quota template with a high water mark (for warning when its reached) and a maximum level is the first step to this. Depending upon use, an administrator may have to define a large number of quota templates but doing this through the UI in SharePoint Central Administration is tedious.

clip_image001

One of these forms needs to be filled out for each template and it could get tiresome if there are tens of templates to create or edit. The easier way to do this? PowerShell.

The files in the archive posted here are PowerShell scripts that will allow an administrator to get a quick view of all available quota templates in XML and then allow the same XML file to accrue additions, modifications and changes pertaining to deletions that can be applied back to the set.

The following need to be ensured before running the scripts

  1. Run the scripts locally using the SharePoint Management Shell on a computer where SharePoint Server 2013 is installed and configured.
  2. Run the scripts as a farm administrator with permissions to alter quota templates. If the user is able to use the Central Administration UI to manage quota templates, then the user will be able to run these scripts.
  3. If there are permission issues with executing the script, ensure Add-SPShellAdmin is run for the user running the script.
  4. Use Set-ExecutionPolicy to temporarily tone the restrictions down if the shell complains about the script not being signed.

GetQuotaTemplates.ps1

##########################################
# Script:   GetQuotaTemplates.ps1
# Function: Retrieves all quota templates
#           defined on the farm in XML
# Author:   Lenny Ankireddi (2013)
##########################################

function Get-SPQuotaTemplates
{
    # Prepare XML structure
    $xmlText =
@"
<?xml version="1.0" encoding="UTF-8" ?>
<QuotaTemplates AsOn="">
    <QuotaTemplate Name="Sample" Action="None|Add|Edit|Delete" StorageMaxLevelInMB="0" StorageWarnLevelInMB="0" UserCodeMaxLevel="0" UserCodeWarnLevel="0" />
</QuotaTemplates>
"@

    # Read the XML string into an object
    $xmlDoc = [xml]$xmlText

    # Read the sample element
    $sampleQuotaTemplate = @($xmlDoc.QuotaTemplates.QuotaTemplate)[0]

    # Get a reference to the content web service
    $service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService

    # Iterate through the list of quota templates
    $service.QuotaTemplates | ForEach-Object {
        # Clone the sample element
        $newQuotaTemplate = $sampleQuotaTemplate.Clone()

        # Set the attributes of the element with the quota template properties
        $newQuotaTemplate.Name = $_.Name
        $newQuotaTemplate.Action = "None"
        $newQuotaTemplate.StorageMaxLevelInMB = [string]($_.StorageMaximumLevel / 1024 / 1024)
        $newQuotaTemplate.StorageWarnLevelInMB = [string]($_.StorageWarningLevel / 1024 / 1024)
        $newQuotaTemplate.UserCodeMaxLevel = [string]$_.UserCodeMaximumLevel
        $newQuotaTemplate.UserCodeWarnLevel = [string]$_.UserCodeWarningLevel

        # Add the element to the QuotaTemplates node as a new child
        $xmlDoc.QuotaTemplates.AppendChild($newQuotaTemplate)
    }

    # Remove Sample node
    $sample = $xmlDoc.QuotaTemplates.QuotaTemplate | Where-Object { $_.Name -eq "Sample" }
    $xmlDoc.QuotaTemplates.RemoveChild($sample)

    # Set date and time when generated
    $now = Get-Date
    $xmlDoc.QuotaTemplates.AsOn = [string]$now

    # Save the XML as a file to the current location
    $currentLocation = Get-Location
    $xmlDoc.Save("$currentLocation\QuotaTemplates.xml")

    # Report completion
    Write-Host -f Green "The quota template information has been saved to QuotaTemplates.xml."
}

Get-SPQuotaTemplates

This script fetches the quota templates currently specified on the local SharePoint farm and their related properties and places these details in an XML file in the same location as the script file.

clip_image002

The XML file will be named QuotaTemplates.xml and will be of the following format.

<?xml version="1.0" encoding="UTF-8"?>
<QuotaTemplates AsOn="04/24/2013 14:58:32">
    <QuotaTemplate Name="Personal Site" Action="None" StorageMaxLevelInMB="100" StorageWarnLevelInMB="80" UserCodeMaxLevel="300" UserCodeWarnLevel="200" />
    <QuotaTemplate Name="Sample 01" Action="None" StorageMaxLevelInMB="4096" StorageWarnLevelInMB="2048" UserCodeMaxLevel="0" UserCodeWarnLevel="0" />
    <QuotaTemplate Name="Sample 02" Action="None" StorageMaxLevelInMB="5120" StorageWarnLevelInMB="4096" UserCodeMaxLevel="0" UserCodeWarnLevel="0" />
</QuotaTemplates>

This file will serve as in input descriptor for the other script that manages the creation, edition and deletion of quota templates. Running the GetQuotaTemplates.ps1 script will overwrite any existing QuotaTemplates.xml file in the script file location. A file with the same name is expected as input by the ManageQuotaTemplates.ps1 script. Therefore if an input file is required for posterity, a copy of the file will need to be saved away manually.

ManageQuotaTemplates.ps1

###############################################
# Script:   ManageQuotaTemplates.ps1
# Function: Applies changes to quota templates
#           based on definition in XML
# Author:   Lenny Ankireddi (2013)
###############################################

function ManageQuotaTemplates
{
    # Get a reference to the content service
    $service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService

    # Read XML input file
    $currentLocation = Get-Location
    $xmlDoc = New-Object XML
    $xmlDoc.Load("$currentLocation\QuotaTemplates.xml");
    $xmlDoc.QuotaTemplates.QuotaTemplate | Foreach-Object {

        $Name = $_.Name
        $StorageMaxLevel = $_.StorageMaxLevelInMB
        $StorageWarnLevel = $_.StorageWarnLevelInMB
        $UserCodeMaxLevel = $_.UserCodeMaxLevelInMB
        $UserCodeWarnLevel = $_.UserCodeWarnLevelInMB

        switch ($_.Action)
        {
            "Add"
            {
                Write-Host "Attempting to add new quota template $name..."
                # Check if quota template already exists
                if ($service.QuotaTemplates[$Name] -ne $null)
                {
                    Write-Host -f Red "Quota Template $Name already exists. Cannot add a new one with the same name. Use the Edit action to alter the existing template."
                    Write-Host ""
                }
                else
                {
                    # Get a reference to a quota template object
                    Write-Host "    Getting a reference to a new quota template object..."
                    $quotaTemplate = New-Object Microsoft.SharePoint.Administration.SPQuotaTemplate

                    # Set mandatory properties on the quota template
                    Write-Host "    Setting quota template properties..."
                    $quotaTemplate.Name = $Name
                    $quotaTemplate.StorageMaximumLevel = [int]$StorageMaxLevel * 1024 * 1024
                    $quotaTemplate.StorageWarningLevel = [int]$StorageWarnLevel * 1024 * 1024
                    $quotaTemplate.UserCodeMaximumLevel = [double]$UserCodeMaxLevel
                    $quotaTemplate.UserCodeWarningLevel = [double]$UserCodeWarnLevel

                    # Add the new quota template to the list of quota templates
                    Write-Host "    Adding the quota template $Name..."
                    $service.QuotaTemplates.Add($quotaTemplate)

                    # Update the service
                    $service.Update()

                    Write-Host -f Green "Quota Template $Name has been added."
                    Write-Host ""
                }
            }

            "Edit"
            {
                Write-Host "Attempting to edit quota template $name..."
                # Check if quota template already exists
                if ($service.QuotaTemplates[$Name] -ne $null)
                {
                    # If found, edit the template with new property values
                    Write-Host "    Quota template was located; editing it..."
                    $service.QuotaTemplates[$Name].Name = $Name
                    $service.QuotaTemplates[$Name].StorageMaximumLevel = [int]$StorageMaxLevel * 1024 * 1024
                    $service.QuotaTemplates[$Name].StorageWarningLevel = [int]$StorageWarnLevel * 1024 * 1024
                    $service.QuotaTemplates[$Name].UserCodeMaximumLevel = [double]$UserCodeMaxLevel
                    $service.QuotaTemplates[$Name].UserCodeWarningLevel = [double]$UserCodeWarnLevel

                    # Update the service
                    $service.Update()

                    Write-Host -f Green "Quota Template $Name has been edited."
                    Write-Host ""
                }
                else
                {
                    Write-Host -f Red "Quota Template $Name was not found. Verify that it exists and name has been correctly typed in XML input. Use the Add action to add a new template by this name."
                    Write-Host ""
                }
            }

            "Delete"
            {
                Write-Host "Attempting to delete quota template $name..."
                # Check if quota template can be found
                if ($service.QuotaTemplates[$Name] -ne $null)
                {
                    # If found, delete it
                    Write-Host "    Quota template was located; deleting it..."
                    $service.QuotaTemplates.Delete($Name)

                    # Update the service
                    $service.Update()

                    #Report completion
                    Write-Host -f Green "Quota template $Name has been deleted."
                    Write-Host ""
                }
                else
                {
                    Write-Host -f Red "Quota template by name $Name was not found. Verify that it exists and name has been correctly typed in XML input."
                    Write-Host ""
                }
            }
        }
    }
}

ManageQuotaTemplates

This script is used to make changes to the quota templates currently defined within the system. This can be done by altering the XML file output generated by GetQuotaTemplates.ps1 shown above.

clip_image003

The Action attribute of the QuotaTemplate element can be altered to one of the following values.

 

Action Result
Add The script will attempt to create a new quota template. However if one already exists by the name used in the XML, no action is taken.
Edit The script will attempt to find an existing quota template by the given name and edit its properties. If one is not found, no action is taken.
Delete The script will attempt to find an existing quota template by the given name and delete it. If one is not found, script reports failure to find it.
None The quota template is left untouched.

Altering the XML

The following precautions need to be taken while altering the input file for the quota template management script

  1. Only edit the Action attribute on QuotaTemplate elements that need to be changed. It is None by default and these quota templates are not altered by the script.
  2. To add a new quota template, copy one of the existing elements over and change its attributes. Do not forget to set the Action attribute to Add.
  3. To edit an existing quota template, select the QuotaTemplate element with the corresponding Name attribute and change its attributes. Do not forget to set the Action attribute to Edit.
  4. To delete an existing quota template, select the QuotaTemplate element with the corresponding Name attribute and set its Action attribute to Delete.
  5. Add, Edit and Delete values on the Action attribute are case sensitive. Type exactly as shown here.
  6. Change the values of the attributes of the QuotaTemplate elements as necessary. Do NOT change any of the other XML constructs.
  7. Values for StorageMaxLevelInMB and StorageWarnLevelInMB are to be provided in integer megabytes. If you do not want to specify these, set them to zero.
  8. Values for UserCodeMaxLevel and UserCodeWarnLevel are to be provided in numerical points. If you do not want to specify these, set them to zero. If you want to set them to SharePoint standard values, specify 300 and 100 respectively.

Recommended approach

Run the GetQuotaTemplates.ps1 script first always to get a fresh updated XML from the server. Alter the XML as required and run ManageQuotaTemplates.ps1. The scripts have been written to avoid providing input parameters on the command line. Hope this helps.

Uninstalling the Office 15 Click-to-Run Extensibility component

August 10, 2013 142 comments

So I was trying to install some 64-bit Office products on my computer and saw the following error message. There seemed to be a 32-bit version of the Office 15 Click-to-Run Extensibility Component installed on my computer.

clip_image001

The Click-to-Run Extensibility Component does seamless transparent upgrades of the Office product in the back end. So there were good reasons for not removing it. But if it prevented me for installing additional features because it was 32-bit then it was time for it to go.

IMPORTANT: If you have 32-bit version of Office installed, DO NOT remove the Click-to-Run components. Office applications may stop working altogether. I was able to do this because my version of Office installation was 64-bit and this item was unrelated.

Problem was, I couldn’t find this program in the programs list in Control Panel. So I was wondering how to remove it. After digging through the registry for the installer (or uninstaller), I found the key related to it and it showed where the MSI was that installs it.

clip_image002

So went to that location, right-clicked on c2rint.msi and selected Uninstall. Confirmed on the Installer dialog.

clip_image003

That did the trick. The product was removed and so was the corresponding key in the registry. There were other products as you can see in the registry that were Click-to-Run related but since the 64-bit installer didn’t complain about these, I left them alone.

clip_image004

I was able to proceed with the installation of the 64-bit Office products I wanted. It may have been a remnant from an old 32-bit install. It is believed (but I can’t vouch for this) that the 32-bit version gets installed when you have preview versions of Office installed. In any case, there is a way to get it out if required. Now to see if I regret removing it eventually.

Replacing missing named caches to a SharePoint Distributed Cache cluster

July 30, 2013 4 comments

A couple of days ago, I started seeing a large number of trace messages being logged to the ULS logs on a SharePoint 2013 farm relating to the distributed cache that looked like those pasted below. These message would repeat with a searing frequency of almost every second. Needless to say, this looked very bad for the server from a performance perspective.

07/25/2013 11:08:18.29 w3wp.exe (0x31BC) 0x3358 SharePoint Foundation DistributedCache ah24w Unexpected Unexpected Exception in SPDistributedCachePointerWrapper::InitializeDataCacheFactory for usage 'DistributedLogonTokenCache' - Exception 'Microsoft.ApplicationServer.Caching.DataCacheException: ErrorCode(ERRCA009):SubStatus(ES0001):Cache referred to does not exist. Contact administrator or use the Cache administration tool to create a Cache. at Microsoft.ApplicationServer.Caching.DataCache.ThrowException(ResponseBody respBody, RequestBody reqBody) at Microsoft.ApplicationServer.Caching.DataCacheFactory.GetCacheProperties(RequestBody request, IClientChannel channel) at Microsoft.ApplicationServer.Caching.DataCacheFactory.GetCache(String cacheName) at Microsoft.SharePoint.DistributedCaching.SPDistributedCachePointerWrapper.InitializeDataCacheFactory()'. 238c329c-bfb9-f0d8-7a04-fe9ab695789e

07/25/2013 11:08:18.29 w3wp.exe (0x31BC) 0x3358 SharePoint Foundation DistributedCache air4g Monitorable Token Cache: Failed to initialize SPDistributedSecurityTokenCache Exception: 'Microsoft.ApplicationServer.Caching.DataCacheException: ErrorCode:SubStatus:Cache referred to does not exist. Contact administrator or use the Cache administration tool to create a Cache. at Microsoft.ApplicationServer.Caching.DataCache.ThrowException(ResponseBody respBody, RequestBody reqBody) at Microsoft.ApplicationServer.Caching.DataCacheFactory.GetCacheProperties(RequestBody request, IClientChannel channel) at Microsoft.ApplicationServer.Caching.DataCacheFactory.GetCache(String cacheName) at Microsoft.SharePoint.DistributedCaching.SPDistributedCachePointerWrapper.InitializeDataCacheFactory() at Microsoft.SharePoint.DistributedCaching.SPDistributedCache..ctor(String nam... 238c329c-bfb9-f0d8-7a04-fe9ab695789e

07/25/2013 11:08:18.29* w3wp.exe (0x31BC) 0x3358 SharePoint Foundation DistributedCache air4g Monitorable ...e, TimeSpan timeToLive, SPDistributedCacheContainerType containerType, Boolean encryptData) at Microsoft.SharePoint.IdentityModel.SPDistributedSecurityTokenCache..ctor(String name, TimeSpan timeToLive, SPDistributedCacheContainerType containerType, Boolean encrptyData, TimeSpan minimumTokenExpirationWindow) at Microsoft.SharePoint.IdentityModel.SPDistributedSecurityTokenCacheInitializer.Init(Object state)'. 238c329c-bfb9-f0d8-7a04-fe9ab695789e

The key message above was the highlighted portion. Effectively, it was telling me that the DistributedLogonTokenCache was missing. So to investigate, I did the following through the PowerShell console.

clip_image001

This was alarming because the DistributedLogonTokenCache was not the only one missing. There should have been a bunch of other named caches here that seem to have gone missing too. To be precise, there should have been the following 10 named cache containers.

  1. DistributedDefaultCache
  2. DistributedAccessCache
  3. DistributedActivityFeedCache
  4. DistributedBouncerCache
  5. DistributedLogonTokenCache
  6. DistributedServerToAppServerAccessTokenCache
  7. DistributedSearchCache
  8. DistributedSecurityTrimmingCache
  9. DistributedActivityFeedLMTCache
  10. DistributedViewStateCache

Why? Because those are the several cache container types available in SharePoint 2013 and one of each of those is created during SharePoint configuration (psconfig) unless you chose to run configuration with the “/skipRegisterAsDistributedCachehost” switch during SharePoint installation on the server(s) in question. In fact, you can get the list above by checking the possible values of the SPDistributedCacheContainerType enumeration.

So now all of these seemed to be gone and try as I may, I couldn’t find the reason they vanished. I wasn’t seeing any errors relating to any of the other cache containers – only the DistributedLogonTokenCache. Maybe there wasn’t any activity on the farm I was monitoring that used the other caches or maybe the components that used those caches weren’t so dependent on them. Or maybe they just didn’t log failures to access the cache. In any case, I needed to restore them. I knew I could create a new named cache container using the New-Cache cmdlet but what I really needed to know was what the name of the named cache was to be.

I looked at my VM with a still healthy cluster for the answer and found the following:

clip_image002

Apparently, it uses the format SPDistributedCacheContainerType_FarmID to create the cache containers. Hoping that the whole setup was loosely coupled enough to allow the cache to be discoverable just through the naming convention, I tried the following command.

New-Cache -CacheName DistributedLogonTokenCache_<farmGUID>

Moments later, on checking the ULS logs again, the DistributedCache errors seemed to have ceased. This was good. I could now restore the other named cache containers in similar fashion. I still wish I knew what caused their mysterious disappearance but I am glad there is a way to get them back without complex wiring.

Previewing the Windows 8.1 Preview

June 29, 2013 3 comments

I found some time today to see what changed with the new Windows 8.1 Preview and took some quick notes that I thought I will post here just in case someone’s curious.

The Start Button

It is most definitely back and has taken its old place down at the left bottom corner in the desktop view. It responds however in the Windows 8 way, by bringing up the tiled Metro start screen interface.

clip_image001

In the start screen mode, you still have to grope down to the bottom left corner with your mouse (if you are using one) or use a hardware Windows button but it is certainly there. I haven’t tried this with a tablet or other touch device, though.

One thing I really liked was how you could right click on the Windows button in desktop mode and get a lot of really quick ways to get to different things. I am sure many of them will require you to be an Administrator on the machine but still very handy for things such as running PowerShell console as admin, accessing the Run box, launching Device Manager or Disk Management, Task Manager, Event Viewer etc. As an admin, the number of times I do those things makes it well worth the time saving.

clip_image002

There is an option to switch between Command Prompt and PowerShell on that popup menu. It is on this Navigation tab that has been added to the Taskbar properties dialog with a bunch of other new stuff. I would personally have preferred both but this is fine.

clip_image003

Oh by the way, right here is also the setting that allows you to boot directly to desktop mode. Not something I care much about but a lot of people seem to.

Tile resizing

Since it came to the Windows Phone 8, it was certain that the next upgrade of Windows would do this as well and right clicking or tapping and holding a tile now allows you to do one of four sizes – Large, Wide, Medium and Small. Not all apps may have tiles available in all sizes. A sample of each size is seen below.

clip_image004

All apps

The All apps charm has been replaced. You could right click on the start screen to bring up a charm in the menu at the bottom of the screen. Now you see a Customize option there instead that is used to customize tile positioning.

A new little arrow has been introduced at the bottom of the screen that brings up the All apps panorama now.

clip_image005

And there is a search box here that helps with filtering apps based on a search string.

clip_image006

Changes to Desktop Search

Type to search has changed. In Windows 8, when search text was typed in, it would bring up the complete app list in the larger pane on the left and start filtering for apps which match the search string. At the same time, it would present a bunch of apps in the smaller search pane that you could click on to search for the same string within that specific app.

clip_image007

Once you zeroed in on the app you wanted, if you wanted a context menu of actions you could invoke on it, you would right click as you always did in Windows and the menu would flow up from the bottom of the screen.

clip_image008

This has all changed and I am not sure I quite comprehend it but it looks like it went back to the way search used to happen within the "Start" dialog in Windows 7. You can still do Search based app filtering but that happens to through the other search interface as described above. Not sure why this separation was created.

clip_image009

The non-program results that you see above by the way are Bing Search suggested terms and clicking on one would bring up search results for that term in the Bing Search app.

Snap

The 3-app snap feature. You can put up to 3 apps snapped side to side. And they share the real estate equally. If you have a widescreen monitor, this really is very useful to work with.

clip_image010

With two apps, the snap feature now allows a 50-50 share of the screen real estate between apps which is a lot more useful than the small area in the corner one of the apps was reduced to with the older version. And then you can bring in a third up on top and decide which of the panes it will take over or place it in a pane of its own.

Each time you bring in an app as some are already tiled, as you hover over the next app, it will swivel a bit in one direction or the other depending on where your mouse is until you click in the direction it tilts to push it into the pane on that side.

clip_image011

Personalization

There is an additional personalization settings option that can be accessed from the Settings when accessed from the start screen view. For the really color-coordinated, there are a lot of color options to personalize the desktop pattern, background and accent colors.

clip_image012

Connectivity

Having run through the above, a lot of changes seem to have been made for convenience or familiarity or just providing more options. The large changes however seem to be made with making devices running Windows 8.1 really able to communicate with work networks.

clip_image013

A quick glimpse through the Network settings shows how VPN and proxy setup have been made important and easy to configure options.

clip_image014

I guess focus is largely on enabling people to connect their own personal devices of choice to work networks in a secure way and to enable administrators on work networks to still have control over the security of the network as a whole.

clip_image015

Since I am doing all this testing on a personal VM, I will not be trying to connect this to a work network but there are enhancements talked about including syncing work folders and being able to remotely wipe all business data off a user’s personal device. Surely there is more to the product under the cover than I could unveil in a two-hour fly-by and will take more exploration to discover but overall, it looks like a good middle ground for Windows 7 desktop lovers, touch screen users and people who like to get work done on their computers.

Categories: Windows Tags:

Creating an Active Directory Domain on Windows Server 2012

I am back again at the task, which I have likely performed too many times – that of creating a new Active Directory domain (and a domain controller) to join a set of virtualized lab machines to play around with. Only difference being, this time it is on Windows Server 2012. The overall experience is much the same with some minor differences.

This article is an exceptional resource for learning how to do this. All I do here is simplify it to the bare bones linear procedure required for the mentioned purpose.

I am doing this on a Hyper-V virtual machine hosted on a Windows 8 based Virtualization Server. The VM has 512 MB of RAM allocated and Windows Server 2012 was installed and a few networking related pre-requisites tasks were checked off in readiness for this. Most importantly, the virtual machine was set up to use a virtual switch created on Hyper-V to allow communication between all VMs connected to it. A static IP was assigned to the machine.

clip_image001

Started with the new Server Manager dashboard and chose to "Add roles and features"

clip_image002

The friendly Before You Begin screen that I always skip but not by default because it gives me quick link to the Remove Roles wizard. Clicked on Next >.

clip_image003

On the next screen you get to choose to install the role or feature on choose to install remote desktop services (RDS) which allows you to connect to virtual or session-based remote desktops where efficient, centralized, pooling and management of resources can be made possible. To learn more about these options, refer to this TechNet Article. It is also important to note that RDS and AD DS cannot be installed on the same server.

Chose Role-based or feature-based installation and hit Next >.

clip_image004

The following screen gives you the ability to pick a server from the pool. Since I have not added (and in fact do not even have to add) any other servers on this pool, I chose Next > to move on with the default selection. Adding servers to the pool will require going back to the Server Manager and choosing the option Add other servers to manage.

clip_image005

Next step, select to install Active Directory Domain Services.

clip_image006

Upon selection, the wizard presents a list of additional features required to run AD DS. There is really no choice about this. If you want to install AD DS, these are required. You can arguably skip installation of management tools but really, why would you? Clicked on Add Features to move on.

clip_image007

The following screen is the Add Features page and a couple are pre-selected – Group Policy Management and Remote Server Administration Tools. There are other eye-catching options but we shall not lose our focus here. Clicked Next > to move on.

clip_image008

Some best practice guidance and pointers are presented. Important to note here is how the wizard tells you that you will be prompted to install the DNS role on the server during the process. Clicked Next > again.

clip_image009

The next screen presents a summary of selections made. I selected to restart the server after installation if required and said Yes on the warning screen as well. I then went ahead and clicked Install to add the role.

clip_image010

And done. Clicked on Close to exit the wizard.

clip_image011

But now we see this in Server Manager on the AD DS node. All we did was add the role. We did not configure the server as a domain controller (DC) and that’s what this is all about. Clicked on the More… link.

clip_image012

The below is what you are shown. The substitute to good old "dcpromo". Clicked on Promote this server to a domain…

clip_image013

Since there is no existing setup, I added a new forest and chose a domain name to give it. Clicked Next >.

clip_image014

Quick notes on the next screen:

a. Chose no backward functional level compliance.
b. Selected to install the DNS Server role
c. The first DC in a forest is automatically a global catalog and cannot be read-only (no choice here).

Provided matching restore mode passwords and hit Next >.

clip_image015

Since there is a no authoritative parent zone for the server, DNS delegation cannot be configured. For a localized environment, this is just fine so hit Next >.

clip_image016

If you do choose in the above screen to see more information, the following is what you are presented. Essentially, this domain is not discoverable from anywhere and for what I am doing, that is just fine.

clip_image017

After jumping across those hurdles above, you end up on this screen where you choose the NETBIOS name for the domain. Was happy with the selection, so hit Next >.

clip_image018

The next screen is about where the files will go. Never messed with this before. No reason to start now. Hit Next >.

clip_image019

The following is a review screen. You can click on View script to view the PowerShell to run the configuration. I always keep the PowerShell even if I don’t intend to run it.

clip_image020

Here’s the PowerShell.

clip_image021

I hit Next > on the wizard to continue without the script.

A prerequisite check is performed.

clip_image022

A couple of warnings – one we have seen before but overall, ready to move ahead. Clicked on Install.

clip_image023

And since installation was successful, we need a computer restart.

clip_image024

When back, the picture in Server Manager looks different. We have the roles added and the server is now a domain controller in the new AD forest I created.

clip_image025

That’s it for now. I have big plans for this server to be realized soon and will probably post my notes on it.

PowerShell script to install SharePoint Root certificate to Trusted Root store

June 18, 2013 3 comments

Now this post is not really about why and how certificates are used by SharePoint. But in order to understand why we are doing what we are going to do shortly, let me start with a brief 2-minute (hopefully) primer on what this is about.

The public key infrastructure allows messages between users, applications and servers that host the applications to happen in a secure manner using digital certificates. The same happens within SharePoint when a message between entities needs to be secured. Now in order for the sender and receiver of messages secured through certificates to work, a trust needs to be established between the parties. The way this works is that both parties trust a third party which is the issuer of the certificate using which the message is signed. Bear in mind that this is a very high level overview of how this works and there are several variations that we shall not get into here. Having said the above, now in order for the receiver of a message to trust the certificate that is presented with it, it will need to be verified. Not only that certificate but its issuer’s certificate and that certificate’s issuer and so forth until we can trace back to a trusted root certificate. This is referred to as certificate chaining.

Within SharePoint, one instance where this happens is when the Security Token Service issues a token and signs it with a certificate. This certificate will need to be verified as mentioned above through building a chain back to a trusted root certificate. Also, a Certificate Revocation List (CRL) needs to be verified to ensure the certificate has not been revoked. This last is yet another topic requiring much detailed explanation that I shall try to address in a future post. But the idea here is that each certificate in the chain needs to be verified and one needs to lead to a trusted root CA store. If this doesn’t happen, certificate validation errors will occur and cause delays in response time to the users. To avoid this, we need to ensure that the SharePoint Root Authority certificate is installed to the Trusted Root Certification Authorities certificate store on each server in the SharePoint farm. The link above provides steps to do this but involves several manual steps. What I have included below, is a PowerShell script that does it all end to end.

The following are prerequisites to running the script.

  • To be run locally on each machine.
  • To be run as a user with Shell_Admin_Access role on the farm databases [If this is not available run Add-SPShellAdmin before proceeding].
  • To be run as a user with local administrator privileges on the server.

Another thing worth verifying before executing the script is the execution policy on the server. You can determine this by running the Get-ExecutionPolicy cmdlet. This typically shouldn’t be a problem unless you are running the script from a remote share. If you do have a problem though, you can work around it by using the Set-ExecutionPolicy cmdlet.

function CopySharePointRootCertToLocalTrustedCertStore {

    # Add the SharePoint PowerShell snap-in
    if (-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) {
	    Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
    }

    # Get the SharePoint root certificate
    $rootCert = (Get-SPCertificateAuthority).RootCertificate

    # Store current location
    $location = Get-Location

    # Go to trusted root certificate store on local machine
    cd Cert:\LocalMachine\Root

    # Check if the certificate already exists
    # If it does, report and end
    if ((dir | ? { $_.Thumbprint -eq $rootCert.Thumbprint })) {
        Write-Host -f Green "SharePoint Root Authority already exists in local machine trusted root certificate store."
        cd $location
        return
    }

    # Get the certificate store for "Trusted Root Certification Authorities" (Cert:\LocalMachine\Root)
    $certStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store Root, LocalMachine

    # Open the store with maximum allowed privileges
    $certStore.Open("MaxAllowed")

    # Add the certificate to the store
    $certStore.Add($rootCert)

    # Close the store
    $certStore.Close()

    # Get the certificate if it exists
    if ((dir | ? { $_.Thumbprint -eq $rootCert.Thumbprint })) {
	    Write-Host -f Green "Certificate was successfully added to the Trusted Root store."
    }
    else {
	    Write-Host -f Red "The certificate could not be added to the Trusted Root store."
    }

    # Set location back to where it was
    cd $location
}

CopySharePointRootCertToLocalTrustedCertStore

You can save the script as a .ps1 file and run on each of the servers where the SharePoint root certificate needs to be copied. The way to verify that this has actually worked is to pull up a management console and add the Certificates snap-in as described in the Microsoft Support KB Article referenced above. If however, your objective is to just export the certificate from SharePoint, you may want to use the script provided below. Just make sure you set the $certPath to where you would actually like to export the certificate and by what name.

# Set the certificate file path
$certPath = "C:\SharePointRootAuthority.cer"

# Add the SharePoint PowerShell snap-in
if (-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) {
	Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
}

# Get the SharePoint root certificate
$rootCert = (Get-SPCertificateAuthority).RootCertificate

# Export the certificate to disk as a certificate file
$rootCert.Export("Cert") | Set-Content $certPath -Encoding byte

Once you have exported the certificate, you can manually add it to the certificate store by using the Management Console or by using the second half of the first script presented above. The only difference is that you will need to construct an X509 certificate object from the certificate file as shown in the script snippet below.

# Set the certificate file path
$certPath = "C:\SharePointRootAuthority.cer"

# Get the certificate store for "Trusted Root Certification Authorities" (Cert:\LocalMachine\Root)
$certStore = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store Root, LocalMachine

# Get the certificate from the location where it was placed by the export process
$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 $certPath

# Open the store with maximum allowed privileges
$certStore.Open("MaxAllowed")

# Add the certificate to the store
$certStore.Add($cert)

# Close the store
$certStore.Close()

That’s it for now. Hopefully, I will find some time to write up more about troubleshooting certificates in SharePoint soon. In the meanwhile, happy scripting!

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: