Add and Remove Shell Access in SharePoint Using PowerShell

How do you add or remove shell access to a web apps content databases?

This script will grant shell access to a user on all the content databases associated with a content database.

$contentDbs = Get-SPContentDatabase -WebApplication "http://yourSharePointWebApp.com/"

foreach($db in $contentDbs)
{
	Add-SPShellAdmin -UserName "domain\user"  -database $db
}

Remove shell access

$contentDbs = Get-SPContentDatabase -WebApplication "http://yourSharePointWebApp.com/"

foreach($db in $contentDbs)
{
	Remove-SPShellAdmin -UserName "domain\user"  -database $db
}

After running the remove script, make sure you check the WSS_Admin_WPG and WSS_WPG groups on the servers in your farm.

Error When Using PowerShell to Call SharePoint Web Service

New-WebServiceProxy : The HTML document does not contain Web service discovery information.
At C:\myScript.ps1:91 char:17
+ ...    $Service = New-WebServiceProxy -UseDefaultCredential -uri $webServ
+                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (http://mySharePoint....bin/Search.asmx:Uri) [New-WebServiceProxy], InvalidOperationException
    + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.NewWebServiceProxy

First attempt at calling the search.asmx service.

$webServ = "http://mySharePointsite.com/_vti_bin/Search.asmx"
$Service = New-WebServiceProxy -UseDefaultCredential -uri $webServ
[xml]$Results = $Service.Query($QueryPacket.OuterXml)

After adding ?wsdl to the uri string, it worked.

$webServ = "http://mySharePointsite.com/_vti_bin/Search.asmx?wsdl"
$Service = New-WebServiceProxy -UseDefaultCredential -uri $webServ
[xml]$Results = $Service.Query($QueryPacket.OuterXml)

PowerShell to get all users group and objects from Active Directory

Get every object and property:

Get-ADUser -Filter * -Properties *| select * | Export-CSV "C:\PS_Every_Object.csv"

^ Depending on the number of user this could take a few minutes to run. This is also handy to hunt for properties.

This will export userId, email, employee Id, and company name.

Get-ADUser -Filter * -Properties SamAccountName,EmailAddress,EmployeeID,Company | select SamAccountName,EmailAddress,EmployeeID,Company | Export-CSV "C:\Email_Addresses.csv"

SOLVED: Exception calling “StartWorkflow” with “X” argument(s)

Trying to start a SharePoint workflow using PowerShell and I couldn’t get past this error:

Exception calling “StartWorkflow” with “4” argument(s): “Object reference not set to an instance of an object.”
or
Exception calling “StartWorkflow” with “3” argument(s): “Object reference not set to an instance of an object.”
 
NO clue if there is a bug in my farm, but the script below works.  Ended up having to re-get the item when running the workflow. $manager.StartWorkflow($list.GetItemById($item.ID),$assoc,$data,$true)

$web = Get-SPWeb "http://rootSiteCollection.com"
$list = $web.Lists["Shared Documents"]

$assoc = $list.WorkFlowAssociations |Where { $_.Name -eq "tacoWF"}
$data = $assoc.AssociationData
$manager = $web.Site.WorkflowManager

$sQuery = New-Object Microsoft.SharePoint.SPQuery 

#Get all items with an ID greater than 5 
$caml = '<Where><Gt><FieldRef Name="ID" /><Value Type="Counter">5</Value></Gt></Where>'
$sQuery.Query = $caml
$fItems = $list.GetItems($sQuery)

Foreach($item in $fItems)
{
	$manager.StartWorkflow($list.GetItemById($item.ID),$assoc,$data,$true)
}

 
Update.
Ran into this again on a SharePoint 2016 farm.
The following commands fixed the problem:
$webapp = Get-SPWebApplication -identity http://
$webapp.UpdateWorkflowConfigurationSettings()
https://support.microsoft.com/en-us/help/2674684/sharepoint-2010-workflow-fails-to-run-after-pause

Are SharePoint Designer Workflows Using Custom Features or Solutions (iLoveSharePoint)

Needed to audit a farm to see if a CodePlex solution was being used in SharePoint Designer workflows.  In my case, I needed to see where the iLove SharePoint  solution was being used. The script below is only targeted at one web and is looking for word “ILoveSharePoint” in the XML.

 


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

[Microsoft.SharePoint.SPSecurity]::RunWithElevatedPrivileges(
	{

		$resultsarray =@()
		#output file name
		$fileName = "C:\ilsp-" + $(Get-Date -Format "yyyyMMddHHmmss") + ".csv"
		#name of the feature we are looking for
		$wFeatureName = "ILoveSharePoint"

		Function GetFiles($folder)
 { 
			foreach($file in $folder.Files)
			{
				if($file.Name.Split('.')[-1] -eq "xoml")
				{
					$web2 = Get-SPWeb $file.Web.Url
					$wFile = $web2.GetFileOrFolderObject($web2.URL +"/"+ $file.URL)

					if ($wFile.Exists -eq "True")
					{
						[xml]$wXml = (New-Object System.Text.UTF8Encoding).GetString($wFile.OpenBinary());
						$nsDetail = $wXml.OuterXml.ToLower()
						
						$wFeatureName = $wFeatureName.ToLower()
							
						if($nsDetail -Like "*$wFeatureName*")
						{
							$outFolder = $folder -replace "Workflows/",""

							$outObject = new-object PSObject
							$outObject | add-member -membertype NoteProperty -name "URL" -Value $web2.Url
							$outObject | add-member -membertype NoteProperty -name "Workflow" -Value $outFolder
							$outObject | add-member -membertype NoteProperty -name "Created By" -Value $wFile.Author
							$outObject | add-member -membertype NoteProperty -name "Created Date" -Value $wFile.TimeCreated
							$outObject | add-member -membertype NoteProperty -name "Modified By" -Value $wFile.ModifiedBy
							$outObject | add-member -membertype NoteProperty -name "Modified Date" -Value $wFile.TimeLastModified

							$global:resultsarray += $outObject
						}
					} 
				} 
			}

			# Use recursion to loop through all subfolders.
			foreach ($subFolder in $folder.SubFolders)
			{
				GetFiles($Subfolder)
			}
		}

		$WebApplications = Get-SPWebApplication

		foreach($webApp in $WebApplications)
		{
			foreach($site in $webApp.Sites)
			{
				if ((Get-SPSite $site.url -ErrorAction SilentlyContinue) -ne $null) 
				{
					foreach($web in $site.AllWebs)
					{
						if ((Get-SPWeb $web.url -ErrorAction SilentlyContinue) -ne $null) 
						{
							$list1 = $web.Lists.TryGetList("Workflows")
							if($list1 -ne $null)
							{
								GetFiles($list1.RootFolder)
							}
						}
					}
				}
			}
		}

		#output file
		$resultsarray | Export-csv $fileName -notypeinformation

	}
)

Document ID Service and Migrating Documents

You are using the Document ID Service in SharePoint and you want to move your documents to another location.  For whatever reason, you notice when you move the documents that your document id’s are lost or reset.  This can be real bad if other systems outside of SharePoint leverage the document id to locate documents in SharePoint.

Here are the steps I used to get around this.
Move the documents from location A to B, keeping the original documents in A.
Run a crawl.
Execute the script below (input your own values for the site and libraries).
Remove / delete the documents from location A. For safe measures, also empty the recycle bin, both at the site and site collection level.
Run another crawl.
Trigger the Document Id Settings to update.

What the script is doing:
Get all the documents in the Shared Documents library of site A.
Loop through the documents.
Locate the document by name in the Shared Documents library of site B.
Update the Document ID of the item.

Things you could improve on:
Get all the documents in site A and output the Name and Document ID to a csv file.
– Then process the csv file with the script.
Add logging.
– Output your pass / fail items to csv file.
Expand the search to query a site.
– Then update the returned item.

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

$sSite = Get-SPWeb "http://sharepoint.net/sites/A"
$sList = $sSite.lists["Shared Documents"]

$dSite = Get-SPWeb "http://sharepoint.net/sites/B"
$dList = $dSite.lists["Shared Documents"]

$sQuery = New-Object Microsoft.SharePoint.SPQuery
$sQuery.ViewAttributes = "Scope='Recursive'"
$sQuery.RowLimit = 2000
$sQuery.Query = '<Where><Gt><FieldRef Name="ID" /><Value Type="Counter">0</Value></Gt></Where>'

do
{
	$sItems = $sList.GetItems($sQuery)
	$sQuery.ListItemCollectionPosition = $sItems.ListItemCollectionPosition
	foreach($sI in $sItems)
	{
		$docName = $sI["Name"].ToString()
		Write-Host $docName

		$dQuery = New-Object Microsoft.SharePoint.SPQuery
		$dQuery.ViewAttributes = "Scope='Recursive'"
		$dQuery.RowLimit = 2000
		$dQuery.Query = '<Where><Eq><FieldRef Name="FileLeafRef"/><Value Type="File">' + $docName + '</Value></Eq></Where>'

		do
		{
			$dItems = $dList.GetItems($dQuery)
			$dQuery.ListItemCollectionPosition = $dItems.ListItemCollectionPosition
			foreach($dI in $dItems)
			{
				try
				{
					$dI["Document ID Value"] = $sI["Document ID Value"]
					$dI.Update()
					Write-Host $dI["Name"] " has been updated"
				}
				catch
				{
					Write-Host $dI["Name"] " ---- " $_.Exception.Message
				}
			}
		}
		while ($dQuery.ListItemCollectionPosition -ne $null)
	}
}
while ($sQuery.ListItemCollectionPosition -ne $null)

Find all Lists and Libraries Where InfoPath is Used

Recently had the need to find and update most every InfoPath form in a production farm. This, mixed with the future demise of InfoPath, prompted the need to find or write a script. The below script will traverse every list and library in a given web app. The script can be easily modified to include every web app in a farm.

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

$fileName = "C:\xsn-" + $(Get-Date -Format "yyyyMMddHHmmss") + ".csv"

$webApp = Get-SPWebApplication "http://webApp.sharepointed.com" 
"Title `t URL `t Type" | out-file $fileName

$(foreach($siteColl in $webApp.Sites)
{
                foreach($web in $siteColl.AllWebs)
                {
                foreach($list in $web.Lists) {                        
                
                                if ($list.BaseType -eq "DocumentLibrary" -and $list.BaseTemplate -eq "XMLForm"){
                                                "$($list.title) `t $($list.parentweb.url)$($list.DefaultViewUrl) `t Library" | out-file $fileName -Append 
                                                                
                                                
                                }elseif ($list.ContentTypes[0].ResourceFolder.Properties["_ipfs_infopathenabled"]){
                                
                                                "$($list.title) `t $($list.ParentWeb.URL)$($list.DefaultViewUrl) `t List" | out-file $fileName -Append
                                                
                                                }
												else{
												$check = 0
								foreach($c in $list.ContentTypes) {
												if($c.DocumentTemplateUrl.ToString().EndsWith("xsn") -eq $true)
												{
													$check++			
												}
												}
												if($check -gt 0)
												{
													"$($list.title) `t $($list.ParentWeb.URL)$($list.DefaultViewUrl) `t List" | out-file $fileName -Append
												}
												}
												}}})

PowerShell Unable to index into an object of type Microsoft.SharePoint.SPList.

Made a change to an existing PowerShell script, then ran into this error: Unable to index into an object of type Microsoft.SharePoint.SPList

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell }

$web = Get-SPWeb "http://sharepointed.com/sitename"
$listTask = $web.Lists["My List"]
$sItem = $listTask.GetItemById(9)

$title = $listTask["Title"]

In the script, you will notice that I’m trying to capture the title of the item. The above script wasn’t working because I failed work with this list item, instead I was trying to work with the list object.

Correct script:

If ((Get-PSSnapIn -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue) -eq $null )
{ Add-PSSnapIn -Name Microsoft.SharePoint.PowerShell }

$web = Get-SPWeb "http://sharepointed.com/sitename"
$listTask = $web.Lists["My List"]
$sItem = $listTask.GetItemById(9)

$title = $sItem["Title"]

Convert yyyyMMdd string to date and time using PowerShell

 

How do you convert an input string to a date and time format.


[System.Globalization.CultureInfo]$provider = [System.Globalization.CultureInfo]::InvariantCulture
$sInput = 19991231
$format = "yyyyMMdd"
[ref]$parsed = get-date
[DateTime]::TryParseExact($sInput, $format, $provider, [System.Globalization.DateTimeStyles]::None, $parsed)

$parsed is the returned value.

Update users display name in SharePoint

The script below will allow you to change a users display name in SharePoint.


# add SharePoint snap-in if needed

 	$ntName = "domain\XXX"
	$displayName = "New Name"
 	$webApp = "http://webapp.sharepointed.com/"
	$user = Get-SPUser -web $webApp -Identity $ntName
	
	Get-SPWebApplication $webApp | Get-SPSite -Limit ALL | Get-SPWeb -Limit ALL | ForEach-Object {
		Set-SPUser -Identity $user -DisplayName $displayName -Web $_.URL
	}