Change List or Library URL and Name

Recently had a scenario where I needed to move a bunch of libraries from different sites, to another farm. Every library was titled the same, so when I went to import the libraries, I ran into a small issue. Using a combo of Export-SPweb and Import-SPweb, I moved a library over, then updated the library url and name to the source site name.

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

$webURL = “http://sharepointed.com/sites/taco”

$before = “LibBefore”
$after = “LibAfter”

#Change the URL of the library
$web = Get-SPWeb $webURL
$web.lists[$before].RootFolder.MoveTo($after)
$Web.Dispose()

#Update the library name
$web = Get-SPWeb $webURL
$list = $web.Lists[$after]
$list.Title = $after
$list.Update()
$web.Dispose()

Couple notes.
You might be able to shorten the script to rename and update in a couple lines of code.
If you use the script to change the URL of a list, the list will moved to the root of the site. it will no longer live at site/lists.

*I have not tested this with libraries or list that workflows associated with them. It’s also safe to assume any links to documents would be broken.*

One or more field types are not installed properly. Go to the list settings page to delete these fields

Error:
One or more field types are not installed properly. Go to the list settings page to delete these fields.

After much research, I have found that this error can be the result of a couple things.
1. Programmatically create a site column / content type and the process fails. The result is a broken column that you have to hunt down and remove from the content database.
2. Using a combination of Export-SP and Import-SPweb, an imported list or library will display the error.

In my case, #2 needed to be fixed. Basically, I had a lookup column that had become orphaned from its parent list.
When you look at the field settings (Library/List Settings –> click on your lookup column) you will see that the Get information from: property is empty.

So how do you reconnect or refresh the lookup field property?
Using PowerShell, the fields web ID and source list ID schemaXML need to be populated.

if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
$web = Get-SPWeb "http://sharepoint.com/site/"
$list = $web.Lists["Broken LoopField List"]
$lookupList = $web.Lists["Loopup Source List"]

$fixColumn = $list.Fields["My Broken Lookup Field"]

#Change schema XML on the lookup column
$fixColumn.SchemaXml = $fixColumn.SchemaXml.Replace($fixColumn.LookupWebId.ToString(), $web.ID.ToString())
$fixColumn.SchemaXml = $fixColumn.SchemaXml.Replace($fixColumn.LookupList.ToString(), $lookupList.ID.ToString())
$fixColumn.Update()

What’s going on here?
Load the SharePoint snapin.
Get site that holds the broken list / library.
Get broken list / library.
Get source list / library that the broken lookup references.
Get broken field.
Update the broken field schemaXML.

Parameter name: userProfileApplicationProxy

Had a contractor leave the company and return. Often this creates issues because we don’t run a ‘dead account cleaner’ often enough.

To get around this, I run the script below to get the ‘new’ Active Directory account synced with the new Active Directory account.

Script:

$user = Get-SPUser -web "http://sharepointed.com" -Identity "Mydomain\TheUser"
Move-SPUser -Identity $user -newalias "Mydomain\TheUser" -IgnoreSID 

Where I went wrong… I remoted’ into one of the servers in the farm using my personal NT login. By doing this, I was receiving the error below. Once I remoted’ into the server using the Admin account, I was able to run the script.

Error:
Move-SPUser : Value cannot be null.
Parameter name: userProfileApplicationProxy
At line:1 char:12
+ Move-SPUser <<<< -Identity $user -newalias "Mydomain\TheUser" -IgnoreSID + CategoryInfo : InvalidData: (Microsoft.Share...PCmdletMoveUser: SPCmdletMoveUser) [Move-SPUser], ArgumentNullException + FullyQualifiedErrorId : Microsoft.SharePoint.PowerShell.SPCmdletMoveUser

Inventory Web App Using PowerShell

Ask: We need an Excel spreadsheet that will list out all the Sites, List, Libraries for a given Web App in SharePoint.

Found this post link, then modified it for my needs.

function Get-WebAppInventory($WebAppName) {
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
    $farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
    foreach ($spService in $farm.Services) {
        if (!($spService -is [Microsoft.SharePoint.Administration.SPWebService])) {
            continue;
        }

        foreach ($webApp in $spService.WebApplications) {
            if ($webApp -is [Microsoft.SharePoint.Administration.SPAdministrationWebApplication]) { continue }
			if($webApp.name -eq $WebAppName)
			{
            foreach ($site in $webApp.Sites) {
                foreach ($web in $site.AllWebs) {
                        foreach ($list in $web.Lists) {
							$data = @{
								"Site" = $site.Url
                                "Web" = $web.Url
                                "list" = $list.Title
								"Type" = $list.BaseType	
								"Item Count" = $list.ItemCount
								"Last Item Modified" = $list.LastItemModifiedDate
							}
							
                            New-Object PSObject -Property $data
         
                    }
                }
            }
		}
        }
    }
}
#Get-WebAppInventory "SharePointed - name.sharepointed.com80" | Out-GridView
Get-WebAppInventory "SharePointed - name.sharepointed.com80" | Export-Csv -NoTypeInformation -Path c:\inventory2.csv

Above you have two options, Out-GridView or Export-CSV. You can use both or comment out one of the lines.

To get the parameter I’m passing to the function, you will need to look in Central Admin at your Web Apps list. Central Admin –> Application Management section –> Manage web applications. (_admin/WebApplicationList.aspx). In there, copy the name of the Web App.

You can modify the $data = @{ section to bring in other properties of the List.

Use PowerShell to Query The SharePoint Search Index

Needed to write a script to validate that the SharePoint crawler was picking up all items in a library.
One of my document libraries had over a 100,000 document, and I needed to make sure all of them were being indexed.
Document library can support millions of documents, IF you use a good foldering structure.

function GetSearchIndex ($site, $file)
	{
		$fOutPut = $null
		$kq = new-object Microsoft.Office.Server.Search.Query.KeywordQuery($site)
		
		$kq.ResultTypes= [Microsoft.Office.Server.Search.Query.ResultType]::RelevantResults
		$kq.QueryText = $file
		$kq.HiddenConstraints = 'scope:"All Sites"'
		$kq.RowLimit = 10
		$res = $kq.Execute()
		
		$table = new-object System.Data.DataTable
		$table.Load($res[$kq.ResultTypes],[System.Data.LoadOption]::OverwriteChanges)
		
		if($table.Rows.Count -eq 0)
		{
			$fOut = "Failed"
		}
		else
		{
			$fOut = "Passed"
		}
		return $fOut
	}

$file = "c:\indexCheck.txt"
$cfcSite = Get-SPWeb "http://SOMEsite.sharepointed.com/sites/test"
$nv = $cfcSite.Lists["bigLibrary"]

$spQuery = New-Object Microsoft.SharePoint.SPQuery 
$spQuery.ViewAttributes = "Scope='Recursive'"
$spQuery.RowLimit = 2000 
$caml = '<OrderBy Override="TRUE"><FieldRef Name="ID"/></OrderBy>' 
$spQuery.Query = $caml 

do
{
    $listItems = $nv.GetItems($spQuery)
    $spQuery.ListItemCollectionPosition = $listItems.ListItemCollectionPosition
    foreach($item in $listItems)
    {
        $sResult = GetSearchIndex "http://test.sharepointed.com" $item.Name
		
		if($sResult -eq "Failed")
		{
			$item.Name | Out-File $file -Append			
		}
    }
}
while ($spQuery.ListItemCollectionPosition -ne $null)

Query the list/library in batches of 2,000.
Looping through the returned items.
Call function to see if the item is in the index (query SharePoint).
From the function, return a value of Passed or Failed.
If Failed is true, log it to a text file on the C:\ drive.

SharePoint SQL Server Errors

Another day of SharePoint fun!
DBA changed a service account password, then failed-over the cluster to a different node. Roughly one hour later, one of the WFE boxes pegged the CPU at 100% for an extended period of time. We also run KnowledgeLake, and the search web part would not load.

First, I directed our load balanced traffic to another WFE box. Once all the open connections were closed, I fired off an iisReset. This alleviated the CPU load.

BUT, the KnowledgeLake web part would not load AND the logs on one of the app servers had the below errors.

Fix? After hours I rebooted the app server in question. Errors stopped appearing and the KnowledgeLake web part loaded.

Unknown SQL Exception -2146893055 occurred. Additional error information from SQL Server is included below.

A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 0 – The handle specified is invalid)

Event ID 5586

Cannot connect to SQL Server. ServerName not found. Additional error information from SQL Server is included below.

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

Event ID 3355

SQL Database ‘WSS_Logging’ on SQL Server instance ‘ServerName’ not found. Additional error information from SQL Server is included below.

Cannot open database “WSS_Logging” requested by the login. The login failed.
Login failed for user ‘domain\webAppAccount’.

Event ID 3760

Paused by system

If your Search Service Application shows a crawl status of Paused for:External request or Paused by system . You can use the following script to get it back online.

$ssa = Get-SPEnterpriseSearchServiceApplication “YOUR Search Service Application name here”

Resume-SPEnterpriseSearchServiceApplication $ssa

*NOTE*
Your Search App might be named something different than Search Service Application.
To find your Searh App name, navigate to your Central Admin site, under Application Management, click on Manage service applications. In the Type column, look for an item that says Search Service Application.

and credit for this post goes to a super smart coworker.

Use PowerShell to Create SharePoint Groups

Simple enough, needed to create a few SharePoint groups and thought PowerShell would be the best answer.


$SiteUrl = "http://sharepointed.com/sites/a"
$Web = Get-SPWeb $SiteUrl

$description = “Super cool stuff”
$permissionLevel = “Read”

$groups = “Group A”, “Group B”, “Group C”

foreach($groupName in $groups)
{
$web.SiteGroups.Add($groupName, $web.SiteUsers[“domain\SomeUser”], $web.SiteUsers[“domain\SomeUser”], $description)
$group = $web.SiteGroups[$groupName]
$roleAssignment = new-object Microsoft.SharePoint.SPRoleAssignment($group)
$roleDefinition = $web.Site.RootWeb.RoleDefinitions[$permissionLevel]
$roleAssignment.RoleDefinitionBindings.Add($roleDefinition)
$web.RoleAssignments.Add($roleAssignment)
$web.Update()
}

$web.SiteGroups.Add(name, owner, default user, description)

Parameters
name
Type: System.String
A string that represents the new group name.
owner
Type: Microsoft.SharePoint.SPMember
An SPMember object that specifies the owner.
defaultUser
Type: Microsoft.SharePoint.SPUser
An SPUser object that specifies the default user for the group.
description
Type: System.String
A string that contains a description for the group.

More details:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spgroupcollection.add.aspx

To get all the uses / groups from a site or web see this post:

http://www.sharepointed.com/2016/10/17/get-all-groups-and-users-in-a-site-collection-or-web/

 

Monitor and Report on Long Running Crawls

Ever needed to know if your SharePoint crawls are running too long? I wrote the below script to keep an eye on my crawls, and report if they are running too long.

In the script, I’m getting the Search Service App. Looping through its content sources, then finding crawls that are running longer than 5 minutes.

#Get PowerShell Snapin
if ((Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null)
{
	Add-PsSnapin Microsoft.SharePoint.PowerShell
}

#get your Search Service App
$ssa = Get-SPEnterpriseSearchServiceApplication "Search Service Application"

#get the content sources from your Search Service App
$contentsources = Get-SPEnterpriseSearchCrawlContentSource -SearchApplication $ssa 


#loop through the content sources
foreach($cs in $contentsources)
{
	#check for crawls that are running
	if ($cs.CrawlStatus -ne "Idle")
	{			
		$cLength = New-TimeSpan -Start ($cs.CrawlStarted) -End (Get-Date) 
		$cLength = $cLength.Minutes
		
		#if the crawl has been running for more than X minutes, send an email
		if($clength -gt 5)
		{
			#email someone that cares
		}
	}
}

SharePoint Crawls and Security Updates

Keeping an eye on my SharePoint crawls, I noticed some crawls were taking a long time.
The crawls were picking up a few items, but then I noticed the number of security updates.

Thanks to my friend Google, I found this posting on the subject.

A clip from the posting:

Question:

Why do security only crawls take so long?

Answer:

The time difference in crawl can be attributed to expansion of the SharePoint Group and also that the group is at the site collection level and affects items beyond the list. If a Sharepoint group has several thousand users at site collection level, you can see how this can be very expensive. Also, a large number of items within that site collection can add to the delay because new ACL changes will be pushed down to every item affected by the security change.

Question:

How can I work around this and prevent security only crawls from affecting incremental crawl times?

Answer:

Instead of users explicitly added to SharePoint groups, add AD groups instead. Managing adding/removing users from Active Directory security groups will not cause ACL changes within SharePoint. Because of this, no security only crawls will occur.

*Update*

Read this:

http://blogs.msdn.com/b/kaevans/archive/2013/05/06/clarifying-guidance-on-sharepoint-security-groups-versus-active-directory-domain-services-groups.aspx