Monthly Archives: December 2013

ShareGate Choice List workaround Script

Update 3/6/2014

This script is no longer needed! ShareGate 4.5 was released and now copies these items natively- no workaround needed!

Hats off to the Share-Gate development team for this update!

The content below should be considered Archive/reference:

If you’re a user of Share-Gate, you may have run into an issue transferring SharePoint lists with Multiple choice fields.

The migrations work, so long as all the data in your list fits into the list of choices you have. But what if at one point the list of choices changed, and you now have data in your list that isn’t in the choice list?

The scenario is like this.
Say you have a choice field with “region”
It started out with North, South, East and West.
So you have data in the list that has those values in it.

Then someone says, “Hey lets restructure – going forward we want people to choose from: East, Central an West”

See what happened there?

The data that’s already in there could be North South East or West, but NEW data can only be West Central or East. This causes issues when the list is migrated.

The solution is to temporarily allow “Fill-in Choices:”

Field choices

 

Ideally, you would change the value “Allow ‘Fill-in’ choices:” above from “no” to “yes” before the migration, then set it back to no after the migration at the new location.

The trouble is,  a given web can have quite a few lists, and each list can have quite a few fields. Going through all of this manually, twice is not fun? What is fun you ask? I’m glad you ask – Running two PowerShell scripts…

I wrote this little PowerShell script…

Here’s what it does –

It enumerates though all the lists in your SP Web.
Then it checks each list to see if has any “Choice Fields” that are set to not allow fill-in choices.
Then it.. sets the Value to yes for “Allow Fill in Values”

How much would you pay for a timesaving script like this???

But wait! There’s more!

While it’s doing all this, its also generating a 2nd powershell script – filled with commands to turn these values back off.

$SourceURL = "https://yoururl.com/sitecollection/web"
$DestinationURL = $SourceURL #Feel free to replace this with the destination, or leave it the same for testing purposes 
$web = get-spweb $SourceURL
$actionweb = get-spweb $SourceURL

#build a "get back" script"
$script = ""
$script = '$web = get-spweb ' + $DestinationURL

foreach ($list in $web.lists)
{
    # get the list of fields with choices that are set to false (Assuming they exist)  
    $fields = $list.fields | where {$_.type -eq "choice" -and $_.FillInChoice -eq $false}
	if ($fields -ne $null)
	{
		write-host "Title: $($list.title)  ($($fields.count))" -foregroundcolor green
		foreach ($field in $fields)
		{
			$f = $actionweb.lists[$list.title].fields[$field.title] 
			$f.FillInChoice = $true
			$f.update()

			$line = '$field = $web.lists["' + $list.title + '"].fields["' + $field.title + '"]; $field.FillInChoice = $false; $field.Update()'
			write-host $line "#" $field.id
			if ($field.id -eq $null)
			{
				write-host "NULL FIELD! $($field.id)" -foregroundcolor yellow
				$field
				write-host "--------------------------------" -foregroundcolor yellow
			}
			$script = $script + "`r`n" + $line
		}#end foreach
	}#end if
}#end foreach

$script | out-file -filepath "Reset_$($DestinationURL)_FillInChoices_$(get-date -format 'yyyyMMdd_HHmmss').ps1"

Note in the above script – I needed two near identical $web objects – the reason for this is that as I went through the list in code, and did my .update() statements, it would invalidate the state of the $web object

Another upside is that the source and destination can be on different farms – just move the generated PS1 file to the destination and run it there.

If there’s a downside, it’s that this really only works for SP 2010 and SP 2013 On premise.

Delete all items in a SharePoint list with PowerShell

Disclaimer: There are several ways to do this – if you don’t need the list, just delete the whole list.

If you need the structure of the list and just need to delete the items in the list, this script will do it, but there are faster methods out there so if you have 1000’s of items, know that this approach is kinda slow.

You might think (As I did) that once you had the list you could do something clever like:

$list.items.delete() #this fails

write-host "This will delete data, type YES to continue"
$retval = read-host 
if ($retval -ne "YES") 
{
    write-host "exiting - you did not type yes" -foregroundcolor green
    exit
}
write-host "continuing"

$web = get-spweb https://url to your web
$list = $web.lists | where {$_.title -eq "Name_of_your_list"}
Write-host "List $($list.title) has $($list.items.count) entries"
$items = $list.items
foreach ($item in $items)
{
    Write-host "  Say Goodbye to $($item.id)" -foregroundcolor red
    $list.getitembyid($Item.id).Delete()
}

You might also wonder why we getitembyID.  You might wonder why we don’t just put $item.delete() inside the foreach loop – that fails too, so we get around that with the last line which seems to work, albeit slowly…

You can’t see a URL on your Web Front End (WFE) and neither can your Search crawler

There is a security feature in Windows that prevents certain network operations.

This will usually be a problem in two scenarios:

– You have a web front end, and on it is a website named www.mywebsite.com, if you try to access that site from ANY other computer, it works just fine, but if you try to access it from the Web Front End that’s hosting mywebsite.com, it doesn’t work!

– You have a web front end, and are trying to do search crawls of your site from the same box hosting the site. Web Crawls fail and are unable to get to the site.

There’s an easy explanation and fix for this – It’s been documented elsewhere so here are the links:

Here’s the Technet article:
http://support.microsoft.com/kb/896861

Bob Fox, MSFT PFE has an even better way of turning this off, only for specific domains:
http://blogs.technet.com/b/sharepoint_foxhole/archive/2010/06/21/disableloopbackcheck-lets-do-it-the-right-way.aspx

 

 

CRL, Loopback and things that can slow down code, and cause problems on servers with no internet access

I’ve run into a few issues in the past year or two that revolved around SSL certificates.

SSL certs usually get installed on your Web Front Ends.

As part of the whole grand scheme of how SSL’s work there is something called an CRL – a list of “bad” certificates that had to be “revoked”

If a hacker steals a Certificate for your bank and installs it on his server, and then directs traffic to his sever, your browser, all by itself, would not know the difference – this is where the CRL comes in – if the bank knows the certificate has been compromised, they can get it “Revoked” which puts it on the CRL, a sort of “black list” for bad certificates.

When the user at home opens his or her browser, part of the SSL authentication mechanism is that your browser checks the CRL list before allowing you to proceed.

This usually works just fine…

Unfortunately, with just the ‘right’ configuration, this can throw a nasty delay into network communications.

Here’s a scenario:

You have an SSL website.

Client PC’s connect to this SSL website from everywhere and everyone is happy.

A .Net developer writes some code to access content on the above server. Note here this is code running on one server (doesn’t have to be a web server) connecting to your SSL protected website on a different server.

What happens now is that the developers code “stalls” for about a minute as the server tries to access the CRL to see if the certificate presented by your SSL website has been revoked.

It stalls because the server the developer is running code on doesn’t have access to the internet (It can access your SSL website, because they are on the same internal network)

This can be an issue.

Ideally you’d fix the connectivity problem, but there may be times that’s out of your control (a demo laptop for example)

The next ideal fix would be a system wide fix like a global registry setting. This doesn’t exist.

Each app gets to decide how to deal with checking CRLS –

This article lists 14 different infrastructure pieces and how each is configured to disable CRL checking http://social.technet.microsoft.com/wiki/contents/articles/964.certificate-revocation-list-crl-verification-an-application-choice.aspx

One personal observation I’ve made is that Google Chome doesn’t seem to care about the CRL – (link) so if you think CRL is a problem on your server, and you can install Chrome, you could then compare how long IE takes to bring up your web page from scratch vs Chrome.

I’ve used the script below to turn off CRL checking for .net code:

#the following statement goes on one line
set-ItemProperty -path "HKCU:\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -name State -value 146944

#the following statement goes on one line also
set-ItemProperty -path "REGISTRY::\HKEY_USERS\.Default\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -name State -value 146944

get-ChildItem REGISTRY::HKEY_USERS | foreach-object {set-ItemProperty -ErrorAction silentlycontinue -path ($_.Name + "\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing")  -name State -value 146944}

Write-Host -ForegroundColor White " - Disabling Certificate Revocation List (CRL) check..."
ForEach($bitsize in ("","64")) 
{			
  $xml = [xml](Get-Content $env:windir\Microsoft.NET\Framework$bitsize\v2.0.50727\CONFIG\Machine.config)
  If (!$xml.DocumentElement.SelectSingleNode("runtime")) { 
    $runtime = $xml.CreateElement("runtime")
    $xml.DocumentElement.AppendChild($runtime) | Out-Null
  }
  If (!$xml.DocumentElement.SelectSingleNode("runtime/generatePublisherEvidence")) {
    $gpe = $xml.CreateElement("generatePublisherEvidence")
    $xml.DocumentElement.SelectSingleNode("runtime").AppendChild($gpe)  | Out-Null
  }
  $xml.DocumentElement.SelectSingleNode("runtime/generatePublisherEvidence").SetAttribute("enabled","false")  | Out-Null
  $xml.Save("$env:windir\Microsoft.NET\Framework$bitsize\v2.0.50727\CONFIG\Machine.config")
}

– Jack