<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>SharePoint++</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jonathd/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jonathd/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 16 Apr 2019 06:09:30 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>SharePoint 2013 Site Collection Export - String or binary data would be truncated</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/sharepoint-2013-site-collection-export-string-or-binary-data-would-be-truncated</link>
      <pubDate>Thu, 11 Jan 2018 17:25:28 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/?p=285</guid>
      <description><![CDATA[Problem: During a site collection export, we received the nebulous SQL Server error “String or...]]></description>
      <content:encoded><![CDATA[<strong>Problem</strong>: During a site collection export, we received the nebulous SQL Server error “String or binary data would be truncated.”  Based off some research and experience in the past, this is normally caused by a URL somewhere in the site exceeding the 260 character limit. We queried the AllDocs table in the content database to check if the combination of the DirName and the LeafName exceeded the limit of 260 for the site collection in question.  Our result came up empty.  

<strong>Solution</strong>: A <em>different</em> site in the content database had a URL that was over the limit and it was causing issues when trying to export the original site. See below for the technical details for more information. Thanks to Paul Feaser for figuring this one out! 

<strong>Technical Details</strong>: With our only trouble-shooting information being the generic error message, “String or binary data would be truncated”, we set up a SQL Server Profiler session to get more details while attempting to export the site collection again.  SQL profiler showed us that the error was being generated while running the stored procedure, DeplAddWebDependencies.   In order to do some testing, we made a copy-only SQL backup and restored it in our test environment.  Running the exact same SQL procedure, it completed successfully which made the problem even more complex.  

Since the error was still occurring in our production environment every time, the next step we took was to restore the same copy of the SQL database on the production environment.  Our production environment has over 100+ sql databases with most databases containing many different site collections.  The SQL Server itself is appropriately sized to handle the massive workload we are running.  In the production environment, we were able to recreate the error every time on the restored database copy running the procedure DeplAddWebDependencies.  The problem within the stored procedure was the fifth “Insert Into …Select” statement.  When commenting out the “Insert Into” part of the statement, the select runs and interestingly returns zero records.  So the question is how could an insert of zero records cause a data truncation error?  

After further investigation, it turns out the issues was with a query hint that was being used in the select statement: OPTION (FORCE ORDER).  The following screen capture shows the query hint along with the error.

<img src="https://msdnshared.blob.core.windows.net/media/2018/01/Image11.png" alt="" width="414" height="150" class="aligncenter size-full wp-image-295" /> 

This particular query hint tells the SQL Compiler to override its derived execution plan and join the tables in the order that they are listed.  The select statement in production was taking a little over 2 seconds with the FORCE ORDER hint.  Commenting out just the query hint resulted in an immediate response without the data truncation error.  With this in mind, we were able to figure out that the issue was some records in a different site collection were greater than the 260 allowed for the full URL.  Because SQL Server is executing parts of the query in parallel and then puts everything together in the end, SQL was actually bringing back all records from the AllDocs quicker than the WHERE clause was being evaluated.  The records from the different site collection where causing the data truncation error.  Since it is unsupported to modify SharePoint code, the fix was to have the owner of the different site collection fix the records that were greater than 260.  As soon as the offending site collection URLs were reduced, the original site collection exported correctly.
]]></content:encoded>
    </item>
    <item>
      <title>Patching AppFabric (Distributed Cache) for SharePoint 2013</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/patching-appfabric-distributed-cache-for-sharepoint-2013</link>
      <pubDate>Fri, 18 Aug 2017 16:50:26 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/?p=255</guid>
      <description><![CDATA[Patching App Fabric on a SharePoint 2013 Farm

Introduction
The Distributed Cache is a new...]]></description>
      <content:encoded><![CDATA[<strong>Patching App Fabric on a SharePoint 2013 Farm</strong>

<strong>Introduction</strong>
The Distributed Cache is a new feature in SharePoint 2013. It provides in-memory caching services to several features including Newsfeeds, Authentication, OneNote client access, Security Trimming, and Page load performance. It runs off a Microsoft technology called AppFabric, which means that any patching that AppFabric needs, your SharePoint 2013 environments will need as well.
Patching AppFabric is a little different from the normal SharePoint patches you may apply. Extra steps need to be taken to keep your farm in working order. In the words of Microsoft: “The Distributed Cache service can end up in a nonfunctioning or unrecoverable state if you do not follow the procedures that are listed in this article. In extreme scenarios, you might have to rebuild the server farm.” …Yikes!
All Distributed Cache configurations will be handled in PowerShell as the setup account. Do not attempt to administer the Distributed Cache through Central Administration. The only related thing you can use Central Administration for is to see what servers the Distributed Cache service is running on. Also, do not attempt to administer the AppFabric service through Windows Services.
<strong>Patching</strong>
In most cases, the Distributed Cache service is not running on every server in the farm, however the AppFabric bits are installed on every server in the farm. For this reason, AppFabric patches will need to be installed on every server in the farm, not just the servers running Distributed Cache.
<ul>
 	<li><strong>Patch non-Distributed Cache servers</strong> -To find out what servers in your farm are running the Distributed Cache service, you can log into Central Administration, Manage Services on Server, click the dropdown to cycle through each server in the farm, and see if it has the Distributed Cache service running. Note: unlike other services, you will not see Distributed Cache with a status of Stopped if that server is not running it. You simply won’t see a line entry for Distributed Cache at all. Additionally, if you know one of the servers running Distributed Cache, you can run the following PowerShell from that server as the setup account. These commands will not work from a server not running the Distributed Cache service.</li>
</ul>
<img width="599" height="105" class="wp-image-265 size-full aligncenter" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/12.jpg" />
<p style="padding-left: 30px">Once you know what servers in your farm are not running the Distributed Cache service, you may match them as normal.</p>

<ul>
 	<li><strong>Patch Distributed Cache servers</strong> – From the step above, we already found what servers in the farm are running the Distributed Cache service. To patch these servers, you must first stop the service one at a time. You can’t simply stop it like you would any other service as this can result in data loss.
<ul>
 	<li>You must use the script below to gracefully stop the service, transferring all data that lived in that cache to another server in the cluster. Microsoft documents that this script may take up to 15 minutes to run. I have set the timeout to 30 minutes to be safe.</li>
</ul>
</li>
</ul>
[caption id="attachment_266" align="aligncenter" width="961"]<img width="961" height="542" class="wp-image-266 size-full" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/22.jpg" /> This is a slightly modified version from this TechNet article: https://technet.microsoft.com/en-us/library/jj219613(v=office.15).aspx[/caption]
<ul>
 	<li style="list-style-type: none">
<ul>
 	<li>Once the script is complete, you may patch that server.</li>
 	<li>Once the server is patched, you can start the Distributed Cache service again by running:</li>
</ul>
</li>
</ul>
<img width="843" height="55" class="aligncenter size-full wp-image-275" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/31.jpg" />
<ul>
 	<li style="list-style-type: none">
<ul>
 	<li>Repeat the above steps on every other server in the farm that is running the Distributed Cache service.</li>
</ul>
</li>
</ul>
<strong>Making Sure Stuff Isn’t Jacked Up</strong>
Since this is an AppFabric patch, and not a SharePoint patch, we do not need to run PSConfig after patching, but we do want to make sure Distributed Cache is working correctly before we celebrate.
<ol>
 	<li>Log on to one of the servers in the farm that should have the Distributed Cache service running on it and run the following command again:<img width="599" height="105" class="aligncenter size-full wp-image-265" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/12.jpg" /></li>
 	<li>This should match what it looked like the first time you ran it before patching started. Verify the Service Status says Up for each entry.</li>
 	<li>Click on Central Administration for the farm. View the SharePoint Health Analyzer issues that appear on the top of the page. Make sure there are no entries referring to Distributed Cache.</li>
 	<li>Run Get-CacheClusterHealth. If anything is listed under Unallocated, make sure they go away after 15 minutes or so.</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>Consolidate SharePoint Content Databases</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/consolidate-sharepoint-content-databases</link>
      <pubDate>Fri, 28 Apr 2017 13:45:28 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/?p=245</guid>
      <description><![CDATA[When managing a SharePoint environment, there are times when the number of content databases grow,...]]></description>
      <content:encoded><![CDATA[When managing a SharePoint environment, there are times when the number of content databases grow, with most of them only being partially utilized. This could happen as a result of a migration, site collection creations that were not planned properly, or other reasons. This script will help you consolidate databases, showing you which site collections should be moved to which content databases. This script will not modify anything, rather it outputs to a .csv file the results. You can then manually move sites or use a second script to process the csv file.

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#Summary - This script will analyze all the content databases in your farm and give you
# - output of what sites you need to move to what database in order to free up
# - databases, allowing you to then delete them. It outputs to a .csv file where
# - you can process them manually or use the second script to process.
#
# -
# - This script will not make any changes to your farm.
#-----------------------SETTINGS---------------------------#

#When moving sites, don't let a database grow larger than this number (combined site's usage in GB)
$usageMaxinGB = 150

#When moving sites, don't let a database grow larger than this number (combined site's quota in GB)
$quotaMaxinGB = 400

#When moving sites, don't let a database contain more than this number of sites
$siteCountMax = 20

#Don't move sites from a dataabse that has one or more sites larger than this number (usage in GB)
$maxUsageForProcessingDBinGB = 50

#Will write the overall database consolidation results to this file
$outputFile = "C:\Users\svc.CNT1.setup\Desktop\ContentDBAnalyze\DatabaseOutput.txt"

#Will write specific site collection move results to this file
$SiteMovesOutput = "C:\Users\svc.CNT1.setup\Desktop\ContentDBAnalyze\SiteMovesOutput.txt"
#-----------------------SETTINGS---------------------------#

#Print header for output files
("Database Name~Original Site Count~Original Usage (GB)~Original Quota (GB)~After Site Count~After Usage (GB)~After Quota (GB)~Deleted") | Out-File $outputFile -Append -NoClobber
("Site URL~Site Usage (MB)~Original DB~Moved to DB") | Out-File $SiteMovesOutput -Append -NoClobber

#Loop through each web application to find sites we can shift around
foreach($wa in Get-SPWebApplication)
{
#This hash will contain each DB and their current sum usage and quota size
$hashOfDBValues = @{}
$originalHashValues = @{}

#Loop through each db in the web app
Write-Host ("Processing all content dbs in " + $wa)
foreach($db in $wa.ContentDatabases)
{
$currentUsageCount = 0
$currentQuotaCount = 0

#Loop through each site in the DB
foreach($site in $db.sites)
{
#if 0, something is wrong
if($site.Usage.Storage -eq 0)
{
Write-Host("" + $site.URL + " usage not reporting correctly.")
}
$currentUsageCount += $site.Usage.Storage
$currentQuotaCount += $site.Quota.StorageMaximumLevel
$site.Dispose()
}

$hashOfDBValues[$db.Name] = @{}
$hashOfDBValues[$db.Name]["usageSize"] = $currentUsageCount
$hashOfDBValues[$db.Name]["quotaSize"] = $currentQuotaCount
$hashOfDBValues[$db.Name]["flaggedForDelete"] = $null
$hashOfDBValues[$db.Name]["numberOfSites"] = $db.sites.count

#Store an original copy for future comparisson
$originalHashValues[$db.Name] = @{}
$originalHashValues[$db.Name]["usageSize"] = $currentUsageCount
$originalHashValues[$db.Name]["quotaSize"] = $currentQuotaCount
$originalHashValues[$db.Name]["flaggedForDelete"] = $null
$originalHashValues[$db.Name]["numberOfSites"] = $db.sites.count
}

#Keep looping until there are no more sites that can move around
$noMoreMoves = $false
while($noMoreMoves -eq $false)
{
#Find lowest usage DB that is not flagged to be deleted
$currentLowest = $null
foreach($database in $hashOfDBValues.getEnumerator())
{
#Don't process default DBs or OWA Dbs
if(($database.name -notlike "*default*") -and ($database.name -notlike "*OWA*"))
{
#If it is already flagged to be deleted or has had sites moved to it, skip over it
if($database.Value["flaggedForDelete"] -eq $null)
{
if($currentLowest -eq $null)
{
$currentLowest = $database
}
else
{
if($database.Value["usageSize"] -lt $currentLowest.Value["usageSize"])
{
$currentLowest = $database
}
}
}
}
}

#If currentLowest is $null at this point, the web app doesn't have any more DBs to process
if($currentLowest -eq $null)
{
$noMoreMoves = $true
}
else
{
#Don't process any DBs if over the usage limit variable
if(($currentLowest.Value["usageSize"] / 1GB) -lt $maxUsageForProcessingDBinGB)
{
#Now have current lowest usage db, loop through each site in the DB and find a new home for it
#Flag it for being deleted so we don't process it again
$currentLowest.Value["flaggedForDelete"] = $true
$databaseToMoveSitesFrom = Get-SPContentDatabase $currentLowest.name
$noMoreMoves = $false

foreach($site in $databaseToMoveSitesFrom.Sites)
{
$noMoreMoves = $true
foreach($db in $hashOfDBValues.getEnumerator())
{
#If same DB it is currently in, skip. Also, don't move sites into default or OWA
if(($db.Name -ne $site.ContentDatabase.Name) -and ($db.Name -notlike "*default*") -and ($db.Name -notlike "*OWA*"))
{
#If we already found a home for this DB, move on
if($noMoreMoves -eq $true)
{
#Can it fit usage wise
if((($site.Usage.Storage + $db.Value["usageSize"]) /1GB) -le $usageMaxinGB)
{
#Usage is good, check quota
if((($site.Quota.StorageMaximumLevel + $db.Value["quotaSize"]) /1GB) -le $quotaMaxinGB)
{
#Quota is good too, make sure we aren't already scheduled to delete this db
if($db.Value["flaggedForDelete"] -ne $true)
{
#Don't go over max number of sites per DB
if($db.Value["numberOfSites"] -lt $siteCountMax)
{
#Everything is good, hypothetically "move" site
Write-Host("Moving site " + $site.Url + " from " + $site.ContentDatabase.Name + " to " + $db.Name)
("" + $site.Url + "~" + [System.Math]::Round(($site.Usage.Storage / 1MB), 2) + "~" + $site.ContentDatabase.Name + "~" + $db.Name) | Out-File $SiteMovesOutput -Append -NoClobber

$db.Value["usageSize"] += $site.Usage.Storage
$db.Value["quotaSize"] += $site.Quota.StorageMaximumLevel
$db.Value["numberOfSites"]++
$db.Value["flaggedForDelete"] = $false
$hashOfDBValues[$currentLowest.name].numberOfSites--
$hashOfDBValues[$currentLowest.name].usageSize -= $site.Usage.Storage
$hashOfDBValues[$currentLowest.name].quotaSize -= $site.Quota.StorageMaximumLevel
$noMoreMoves = $false
}
}
}
}
}
}
}

#If there is still some sites left and no more moves available, set the DB to not be deleted
if($noMoreMoves -eq $true)
{
$hashOfDBValues[$currentLowest.name].flaggedForDelete = $false
}
}
}
else
{
$currentLowest.Value["flaggedForDelete"] = $false
}
}

} #End no more moves loop

#Do a before and after to compare what DBs looked like
foreach($database in $originalHashValues.getEnumerator())
{
("" + $database.Name + "~" + $database.Value["numberOfSites"] + "~" + [System.Math]::Round(($database.Value["usageSize"] / 1GB), 2) + "~" + [System.Math]::Round(($database.Value["quotaSize"] / 1GB), 2) + "~" + $hashOfDBValues[$database.name].numberOfSites + "~" + [System.Math]::Round(($hashOfDBValues[$database.name].usageSize / 1GB), 2) + "~" + [System.Math]::Round(($hashOfDBValues[$database.name].quotaSize / 1GB), 2) + "~" + $hashOfDBValues[$database.name].flaggedForDelete) | Out-File $outputFile -Append -NoClobber
}
}]]></content:encoded>
    </item>
    <item>
      <title>Nintex To-Do Task - First Response Applies</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/nintex-to-do-task-first-response-applies</link>
      <pubDate>Fri, 07 Aug 2015 10:03:02 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2015/08/07/nintex-to-do-task-first-response-applies/</guid>
      <description><![CDATA[When creating a Nintex workflow, one of the actions you can add is a &quot;to-do task&quot;. You are...]]></description>
      <content:encoded><![CDATA[<p>When creating a Nintex workflow, one of the actions you can add is a &quot;to-do task&quot;. You are then able to enter multiple assignees for this task.&nbsp; One of the task options is &quot;First response applies&quot;. This means that as long as one of the assignees approves, the workflow can continue without waiting for all assignees to approve.</p>
<p>When this workflow action kicks off, a list item will be entered for each assignee in the associated Tasks list. By default, when one of the assignees completes the task, the other list items remain in a &quot;Not Started&quot; state. To get around this, you want to add the &quot;Nintex Workflow Multi Outcome Task&quot; content type to the Tasks list. Now, when the first person completes the task, the other tasks will automatically be completed.</p>]]></content:encoded>
    </item>
    <item>
      <title>C# .NET version of SharePoint 2010's Add-SPShellAdmin</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/c-net-version-of-sharepoint-2010s-add-spshelladmin</link>
      <pubDate>Mon, 15 Jun 2015 05:44:45 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2015/06/15/c-net-version-of-sharepoint-2010s-add-spshelladmin/</guid>
      <description><![CDATA[When you need a user or group to have PowerShell access to a SharePoint content database, you simply...]]></description>
      <content:encoded><![CDATA[<p>When you need a user or group to have PowerShell access to a SharePoint content database, you simply run the PowerShell command &quot;Add-SPShellAdmin -Database &lt;TheDatabaseObject or GUID&gt;&quot;. This does all the backend work, creating the necessary database roles and schemas, and adding the users/groups to them. There may be times when using PowerShell is not as convenient. For example, if you have .NET custom code that creates content databases, you will need to write code to handle doing what Add-SPShellAdmin does if you want the process to be automated. If you don&#39;t, you will find that your admins do not have permissions to access the new database through PowerShell. The below code will handle it for you:</p>
<p><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlConnection</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> connection = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">null</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">;</span></span></p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Build SQL Query</span></span></span></p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">StringBuilder</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> sqlQueryBuilder = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">null</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">;</span></span></p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">try</span></span></span></p>
<p>{</p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Add Shell Admin to new DB (add to db_owner role and SharePoint_Shell_Access role</span></span></span></p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">String</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">[] accountsToPermissionForShellAdmin = (</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">&lt;Your comma delimited list of users/groups you want to add&gt;)</span></span></span></p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> connection = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">new</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlConnection</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">(&lt;Your new database connection string. If you have a SPContentDatabase object, you can call db.DatabaseConnectionString&gt;);</span></span></p>
<p style="margin-left:30px;">connection.Open();</p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Create the SharePoint_ShellAccess Schema</span></span></span></p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlCommand</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">new</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlCommand</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;CREATE SCHEMA [SharePoint_Shell_Access]&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, connection);</span></span></p>
<p style="margin-left:30px;">myCommand.ExecuteNonQuery();</p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Create the SharePoint_ShellAccess Role</span></span></span></p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">new</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlCommand</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;CREATE ROLE [SharePoint_Shell_Access]&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, connection);</span></span></p>
<p style="margin-left:30px;">myCommand.ExecuteNonQuery();</p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Have the new Role be the owner of the new Schema</span></span></span></p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand = </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">new</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">SqlCommand</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;ALTER AUTHORIZATION ON SCHEMA::[SharePoint_Shell_Access] to [SharePoint_Shell_Access]&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, connection);</span></span></p>
<p style="margin-left:30px;">myCommand.ExecuteNonQuery();</p>
<p style="margin-left:30px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">foreach</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> (</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">String</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> account </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">in</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> accountsToPermissionForShellAdmin)</span></span></p>
<p style="margin-left:30px;">{</p>
<p style="margin-left:60px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">try</span></span></span></p>
<p style="margin-left:60px;">{</p>
<p style="margin-left:90px;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Add as db_owner</span></span></span></p>
<p style="margin-left:90px;">myCommand = connection.CreateCommand();</p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.CommandText = </span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;sp_addrolemember&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">;</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.CommandType = System.Data.</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">CommandType</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">.StoredProcedure;</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.Parameters.AddWithValue(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;@rolename&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, </span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;db_owner&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">);</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.Parameters.AddWithValue(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;@membername&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, account);</span></span></p>
<p style="margin-left:90px;">myCommand.ExecuteNonQuery();</p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Add as SharePoint_Shell_Access</span></span></span></p>
<p style="margin-left:90px;">myCommand = connection.CreateCommand();</p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.CommandText = </span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;sp_addrolemember&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">;</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.CommandType = System.Data.</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">CommandType</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">.StoredProcedure;</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.Parameters.AddWithValue(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;@rolename&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, </span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;SharePoint_Shell_Access&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">);</span></span></p>
<p style="margin-left:90px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> myCommand.Parameters.AddWithValue(</span></span><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;"><span style="color:#a31515;font-family:Consolas;">&quot;@membername&quot;</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">, account);</span></span></p>
<p style="margin-left:90px;">myCommand.ExecuteNonQuery();</p>
<p style="margin-left:60px;">}</p>
<p style="margin-left:60px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">catch</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> (</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">Exception</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> ex)</span></span></p>
<p style="margin-left:60px;">{</p>
<p style="margin-left:60px;"><span style="font-family:Consolas;"><span style="font-family:Consolas;">&nbsp;</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">#Log error message somewhere</span></span></span></p>
<p style="margin-left:60px;">}</p>
<p style="margin-left:30px;">}</p>
<p>}</p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">catch</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> (</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">Exception</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> ex)</span></span></p>
<p>{</p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;">&nbsp;<span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">#Log error message somewhere</span></span></span></span></span></p>
<p>}</p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;"><span style="color:#008000;font-family:Consolas;">//Close connection</span></span></span></p>
<p><span style="font-family:Consolas;"><span style="font-family:Consolas;"> </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">if</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;"> ((connection != </span></span><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;"><span style="color:#0000ff;font-family:Consolas;">null</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">) &amp;&amp; (connection.State == System.Data.</span></span><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;"><span style="color:#2b91af;font-family:Consolas;">ConnectionState</span></span></span><span style="font-family:Consolas;"><span style="font-family:Consolas;">.Open))</span></span></p>
<p>{</p>
<p style="margin-left:30px;">connection.Close();</p>
<p>}</p>
<p><span style="font-family:Consolas;font-size:small;"><span style="font-family:Consolas;font-size:small;"></span></span></p>
<p></p>
<p></p>]]></content:encoded>
    </item>
    <item>
      <title>Differences in Email Attribute Between UPA and Active Directory</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/differences-in-email-attribute-between-upa-and-active-directory</link>
      <pubDate>Tue, 20 Jan 2015 09:35:27 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2015/01/20/differences-in-email-attribute-between-upa-and-active-directory/</guid>
      <description><![CDATA[There may be times when you receive a report where a user&#39;s email address in Active Directory...]]></description>
      <content:encoded><![CDATA[<p>There may be times when you receive a report where a user&#39;s email address in Active Directory (AD) differs from the one found in User Profile Application (UPA)&nbsp;for that user&#39;s profile. This usually occurs after a user has changed their email address in Active Directory and the UPA has not correctly picked up the change. Below you will find a PowerShell script that helps you identify these scenarios. It will loop through every profile in a UPA and obtain the email address. It then looks up that user by their ID in AD and compares the email address obtained from the UPA with the one stored in AD.</p>
<p>The output will be a comma delimited set of values which you can easily import into Excel. Hope you find this helpful!</p>
<p></p>
<p>Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue</p>
<p>$fileForOutput = &quot;C:\YourFilePath\Output.txt&quot;<br />#Print Headers<br />(&quot;&quot; + &quot;ACCOUNT ID&quot; + &quot;,&quot; + &quot;EMAIL IN UPA&quot; + &quot;,&quot; + &quot;EMAIL IN AD&quot; + &quot;,&quot; + &quot;NOTES&quot;) | Out-File $fileForOutput -Append</p>
<p>#Load required assemblies for SP and UPA<br />[System.Reflection.Assembly]::LoadWithPartialName(&quot;Microsoft.Office.Server&quot;)<br />[System.Reflection.Assembly]::LoadWithPartialName(&quot;Microsoft.Office.Server.UserProfiles&quot;)</p>
<p>#Create new context object<br />$contextWeb = New-Object Microsoft.SharePoint.SPSite(&quot;https://CanUseCAURL&quot;)<br />$serverContext = [Microsoft.Office.Server.ServerContext]::GetContext($contextWeb)</p>
<p>#Create connection to UPA and get profiles<br />$upaManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($serverContext)<br />$profiles = $upaManager.GetEnumerator()</p>
<p>$count = 0<br />foreach($profile in $profiles)<br />{<br />&nbsp;&nbsp;&nbsp; $count++<br />&nbsp;&nbsp;&nbsp; try<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Get email address that is stored in UPA<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $userEmailInUPA = $profile.Item(&quot;WorkEmail&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $userAccountNameInUPA = $profile.AccountName</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Get email address that is stored in AD<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Get rid of domain<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($userAccountNameInUPA.contains(&quot;\&quot;))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $slashLocation = $userAccountNameInUPA.indexOf(&quot;\&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $userAccountNameInUPA = $userAccountNameInUPA.Substring(($slashLocation+1),($userAccountNameInUPA.Length - ($slashLocation+1)))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $searcher = new-object DirectoryServices.DirectorySearcher([ADSI]&quot;&quot;)&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $searcher.filter = &quot;(&amp;(objectClass=user)(sAMAccountName= $userAccountNameInUPA))&quot;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Searcher.CacheResults = $true&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Searcher.SearchScope = &quot;Subtree&quot;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Searcher.PageSize = 1000&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $results = $searcher.findall()&nbsp; <br />&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #If results does not equal 1, can&#39;t do comparison<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($results.Count -eq 0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&quot;&quot; + $userAccountNameInUPA&nbsp; + &quot;,&quot; + $userEmailInUPA + &quot;,&quot; + &quot;NA&quot; + &quot;,&quot; + &quot;User Not Found in AD&quot;) | Out-File $fileForOutput -Append <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif($results.Count -gt 1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&quot;&quot; + $userAccountNameInUPA&nbsp; + &quot;,&quot; + $userEmailInUPA + &quot;,&quot; + &quot;NA&quot; + &quot;,&quot; + &quot;Multiple Users Found in AD&quot;) | Out-File $fileForOutput -Append<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif($results.Count -eq 1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $result = $results[0]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Get email address if they have one<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [string]$adEmailValue = &quot;&quot;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($result.Properties[&quot;proxyaddresses&quot;].Count -gt 0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $adEmailValue = $result.Properties[&quot;proxyaddresses&quot;][($result.Properties[&quot;proxyaddresses&quot;].Count -1)]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($adEmailValue.IndexOf(&quot;SMTP:&quot;) -eq 0)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $adEmailValue = $adEmailValue.Substring(5)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Compare the email found in UPA with what is in AD<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(($adEmailValue -eq $null) -and ($userEmailInUPA -eq $null))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&quot;&quot; + $userAccountNameInUPA +&nbsp; &quot;,&quot; + $userEmailInUPA + &quot;,&quot; + $adEmailValue + &quot;,&quot; + &quot;Match&quot;) | Out-File $fileForOutput -Append<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($adEmailValue -eq $userEmailInUPA)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&quot;&quot; + $userAccountNameInUPA + &quot;,&quot; + $userEmailInUPA + &quot;,&quot; + $adEmailValue + &quot;,&quot; + &quot;Match&quot;) | Out-File $fileForOutput -Append<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (&quot;&quot; + $userAccountNameInUPA + &quot;,&quot; + $userEmailInUPA + &quot;,&quot; + $adEmailValue + &quot;,&quot; + &quot;Does Not Match&quot;) | Out-File $fileForOutput -Append<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; catch<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Silently skipping any failures. Feel free to put your own logic here<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />}<br />$count | Out-File $fileForOutput -Append</p>]]></content:encoded>
    </item>
    <item>
      <title>Getting Current List of Users Who Have Permissions to a Site/Web</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/getting-current-list-of-users-who-have-permissions-to-a-siteweb</link>
      <pubDate>Tue, 11 Nov 2014 05:23:29 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2014/11/11/getting-current-list-of-users-who-have-permissions-to-a-siteweb/</guid>
      <description><![CDATA[I ventured out on the task this week of trying to generate a list of users who currently have some...]]></description>
      <content:encoded><![CDATA[<p>I ventured out on the task this week of trying to generate a list of users who <strong>currently</strong> have some level of permissions to a SharePoint site collection or sub site. This turned out to be a more challenging task than one would think. At the site collection level, there is the User Info table. You can find this by browsing to <a href="https://www.YourSiteCollectionUrl/_catalogs/users/simple.aspx">www.YourSiteCollectionUrl/_catalogs/users/simple.aspx</a>. You are able to traverse this list in PowerShell as well. The problem is that this list contains any user who browsed to the site or was given direct permissions to the site at some point in the past. If all permissions are removed for that user, he will still remain in this list.</p>
<p></p>
<p>At the web level, there are 3 properties that exist that should be able to provide some assistance: Users, AllUsers, and SiteUsers</p>
<ul>
<li>Users
<ul>
<li>MSDN Description: Gets the collection of user objects that are explicitly assigned permissions in the website.</li>
<li>Issue: Take an example where you break inheritance on a list, and permission a user directly to that list. That list is the only thing the user has permissions to on the site. The user will show up under this property. The problem is when that list is deleted, the user still shows up here. The reason is because that user still shows up under site actions - site settings - site permissions as &#39;Limited Access&#39; even though they have no current permissions to anything. Manually deleting them from here will get them to stop showing up under this property</li>
</ul>
</li>
<li>AllUsers<br />
<ul>
<li>MSDN Description: Gets the collection of user objects that represents all users who are either members of the site or who have browsed to the site as authenticated members of a domain group in the site.</li>
<li>Issue: The MSDN description is accurate. It shows you users who have browsed to the site through a domain group that has access. Once that group is removed and the user no longer has permissions, he continues to show up here.</li>
</ul>
</li>
<li>SiteUsers<br />
<ul>
<li>MSDN Description: Gets the collection of all users that belong to the site collection.</li>
<li>Issue: From what I can tell, this property just mimics what is found in the User Info table, which is not what we want.</li>
</ul>
</li>
</ul>
<p></p>
<p>Conclusion: All methods of finding users have some flaw when only looking for users who currently have permissions to something on the site. If you know of a way to do this, please share in the comments section!</p>]]></content:encoded>
    </item>
    <item>
      <title>ULS Logs Not Consistently Being Written to Usage Database</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/uls-logs-not-consistently-being-written-to-usage-database</link>
      <pubDate>Thu, 23 Oct 2014 04:13:19 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2014/10/23/uls-logs-not-consistently-being-written-to-usage-database/</guid>
      <description><![CDATA[SharePoint gives you the option to write ULS logs to the Usage database. In order for this to work,...]]></description>
      <content:encoded><![CDATA[<p>SharePoint gives you the option to write ULS logs to the Usage database. In order for this to work, your farm must have a &#39;Usage and Health Data Collection Service&#39; Application running. You can enable this by going into Central Administration - Monitoring - Configure usage and health data collection - Enable usage data collection.</p>
<p>To log ULS logs to this database you must enable the &#39;Diagnostic Data Provider: Trace Log&#39; timer job. By default, this job runs every 10 minutes and logs current ULS to one of 31 dbo.ULSTraceLog_Partition tabbles in the Usage database. There is one partition for each day of the month and every day at midnight, it will start logging to the next partition. By default, logs are only stored for 14 days, so only 14 partition tables should ever have data in it. This number is configurable.</p>
<p>There is also a configurable number which determines how large those partitions can grow. You can find this under the dbo.Configuration table in the Usage database under the property &#39;Max Total Bytes - ULSTraceLog&#39;. If you take this number, and divide it by &#39;Retention Period - ULSTraceLog&#39; (also found in dbo.Configuration), this is how many bytes each partition can grow. Taking the default values of 6200000000 for Max Total Bytes and 14 for Retention period, this only gives you 5.77GB worth of logs each day. This may be fine for a small-mid size farm, but for a large farm, this will probably need to be increased. If you are running out of space, you will find that the ULS logs are being written to the partitions correctly starting at midnight and are stopping some point throughout the day. To resolve this, either raise the value of &#39;Max Total Bytes - ULSTraceLog&#39;, lower the value of &nbsp;&#39;Retention Period - ULSTraceLog&#39;, or some combination of the two.</p>
<p>Hope this saves you some time!</p>]]></content:encoded>
    </item>
    <item>
      <title>PowerShell Script to Find Site Collections not Using a Storage Quota</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/powershell-script-to-find-site-collections-not-using-a-storage-quota</link>
      <pubDate>Thu, 18 Sep 2014 07:13:21 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2014/09/18/powershell-script-to-find-site-collections-not-using-a-storage-quota/</guid>
      <description><![CDATA[You may come across situations where you need to know which site collections in your farm are not...]]></description>
      <content:encoded><![CDATA[<p>You may come across situations where you need to know which site collections in your farm are not using one of the farm storage quotas. The script below will find and output these sites.</p>
<p></p>
<p>Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue</p>
<p>#Get available quota templates in farm<br />$Templates = [Microsoft.SharePoint.Administration.SPWebService]::ContentService.QuotaTemplates</p>
<p>#Loop through wach web app<br />foreach($webApp in Get-SPWebApplication)<br />{<br />&nbsp;&nbsp;&nbsp; #Loop through each site in the web app to check quota<br />&nbsp;&nbsp;&nbsp; foreach($site in $webApp.Sites)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $currentQuotaID = $site.Quota.QuotaID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $quotaFound = $false<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Loop through each quota template in the farm looking for a mact in IDs<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach($Template in $Templates)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #If there is a macth found, break out of the loop and move on to the next site<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($currentQuotaID -eq $Template.QuotaID)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $quotaFound = $true<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #If no match is found, output it<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($quotaFound -eq $false)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;No quota found for &quot; + $site.URL + &quot;. QuotaID: &quot; + $currentQuotaID)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $site.Dispose()<br />&nbsp;&nbsp;&nbsp; }<br />}</p>]]></content:encoded>
    </item>
    <item>
      <title>Changing Site Owner and Secondary Owners in a SharePoint Farm</title>
      <link>https://docs.microsoft.com/archive/blogs/jonathd/changing-site-owner-and-secondary-owners-in-a-sharepoint-farm</link>
      <pubDate>Fri, 08 Aug 2014 07:18:35 GMT</pubDate>
      <dc:creator><![CDATA[Ambergahill]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.technet.microsoft.com/jonathd/2014/08/08/changing-site-owner-and-secondary-owners-in-a-sharepoint-farm/</guid>
      <description><![CDATA[Sometimes a user who is a site owner or secondary owner across many SharePoint sites leaves the...]]></description>
      <content:encoded><![CDATA[<p>Sometimes a user who is a site owner or secondary owner across many SharePoint sites leaves the company or changes roles. This person needs to be removed from the owner roles on these sites. This change can only be done in Central Admin or PowerShell so the normal end user would not be able to make this change. Below is the PowerShell code to do this. It is also attached as a file on this post.&nbsp;The script&nbsp;loops through every site collection in the farm. If it finds the user who is leaving as a owner or secondary owner, it will change it out with a user of your choice. There is also an option to run the script in audit mode. This will show you where the trouble user exists, but will not change anything. You will need top modify the variables in the settings section before running.</p>
<p>Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue</p>
<p>#----------------------------------SETTINGS----------------------------------#</p>
<p>#Original owner that you are looking to globally swap out (Domain\Account)<br />$originalOwner = &quot;DOMAIN\account1&quot;</p>
<p>#Change from the original owner above to this person(Domain\Account)<br />$ownerToChangeTo = &quot;DOMAIN\account2&quot;</p>
<p>#When auditMode is set to $true, changes will not actually be made, just displayed to screen ($true/$false)<br />$auditMode = $true</p>
<p>#----------------------------------SETTINGS----------------------------------#</p>
<p>$sites = Get-SPSite -Limit All<br />foreach($site in $sites)<br />{<br />&nbsp;&nbsp;&nbsp; #Check primary owner<br />&nbsp;&nbsp;&nbsp; if($site.Owner.LoginName -eq $originalOwner)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host ($site.URL)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Owner: &quot; + $site.Owner + &quot;-MATCH&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Secondary: &quot; + $site.SecondaryContact)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Changing primary owner from &quot; + $originalOwner + &quot; to &quot; + $ownerToChangeTo)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Only process change if audit mode -eq $false<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($auditMode -eq $false)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set-SPSite -Identity $site -OwnerAlias $ownerToChangeTo<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; #Check secondary owner<br />&nbsp;&nbsp;&nbsp; if($site.SecondaryContact.LoginName -eq $originalOwner)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host ($site.URL)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Owner: &quot; + $site.Owner)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Secondary: &quot; + $site.SecondaryContact + &quot;-MATCH&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;-Changing secondary owner from &quot; + $originalOwner + &quot; to &quot; + $ownerToChangeTo)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Host (&quot;&quot;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Only process change if audit mode -eq $false<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if($auditMode -eq $false)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set-SPSite -Identity $site -SecondaryOwnerAlias $ownerToChangeTo<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; $site.Dispose()<br />}</p>
<p>#If Audit mode was on, notify<br />if($auditMode -ne $false)<br />{<br />&nbsp;&nbsp;&nbsp; Write-Host (&quot;This script was ran in Audit Mode. No changes were made. Edit this file and set that variable to false and run again to actually make the changes.&quot;)<br />}</p>]]></content:encoded>
    </item>
  </channel>
</rss>