Saturday, May 14, 2011

Microsoft Tags = Really freaking cool!

So, I am headed to TechEd  this week and they are having a scavenger hunt with Microsoft Tags. I had seen the app in the Windows Phone marketplace but had not actually taken a look at it. I must say I’m really impressed.

If you are going to be in Atlanta for TechEd grab the free Microsoft Tag from here and join me in the scavenger hunt.

Once you have grabbed you can test it on the Tag below.

CraigToThePointTag

Have fun and if you are going to be there give me a shout!

PowerShell to remove web parts with errors from SharePoint 2010

One of the things that I run into whenever I do an upgrade from an older version of SharePoint to SharePoint 2010 is that not all of the custom functionality previously implemented still works. This is especially true when moving from WSS 2.0 to SharePoint 2010.

When a client has 50+ sites and these web parts are on every landing page the process of removing them manually is just out of the questions. So how do we solve this?

Well, in SharePoint 2007 I would have said that you should go bug a developer and have them write you a console application to loop through and remove any and all erroring web parts. However, in SharePoint 2010 the story is slightly different.

PowerShell to the rescue!!!

function Remove-SPErroringWebParts
{
[CmdletBinding()]

param
(
[parameter(ValueFromPipeline=$true,Mandatory=$true,Position=0)]
$Web
)

begin
{
Out-Host -InputObject "Beginning Remove-SPErroringWebParts..."
}

process
{
if ($Web -is [string]) {Out-Host -InputObject " This is a string.";$Web = Get-SPWeb $Web}
if ($Web -is [Microsoft.SharePoint.Administration.SPWebApplication]) {Out-Host -InputObject " This is a web app.";$Web = Get-SPSite -WebApplication $Web -Limit All -Confirm:$false}
if ($Web -is [Microsoft.SharePoint.SPSite[]]) {Out-Host -InputObject " This is an array of sites.";$Web | %{Set-AllBackToSiteDefinition -Web $_}}
if ($Web -is [Microsoft.SharePoint.SPSite] ) {Out-Host -InputObject " This is a site.";$Web = (Get-SPWeb -Site $Web -Limit All -Confirm:$false)}
if ($Web -is [array]) {" This is an array."; $Web | %{ Remove-SPErroringWebParts $_ } }
if ($Web -is [microsoft.SharePoint.SPWeb])
{
Out-Host -InputObject " This is a web."
$webpartmanager = $Web.GetLimitedWebPartManager(($Web.Url + "/default.aspx"), [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)

#Create a separate list of webparts to be deleted to avoid enumeration error
$webpartsToDelete = $webpartmanager.WebParts | ?{$_.ErrorMessage -ne $null}

foreach ($webpart in $webpartsToDelete)
{
if ($webpart.ErrorMessage -ne $null)
{
Out-Host -InputObject " Deleting webpart.."
$webpartmanager.DeleteWebPart($webpart)
}
}
$Web.Dispose()
}
}

end
{
Out-Host -InputObject "Finished Remove-SPErroringWebParts."
}
}



The function above looks far more complicated than it really is. I wrote it so that I could save it off and use it for later projects. To be honest, this function isn’t really done as I need to add a great deal of error handling, it only checks the “/default.aspx” page so if you have Publishing sites or even sites that use the Wiki Home Page it will not work, and there is some Out-Host commands that will most likely be changed to Out-Debug. However, I digress. Writing PowerShell for reusability is a completely different discussion that I will probably write about at a later date. Until then there are a couple really great blog posts you can check out if you are interested:




For now, lets take a look at what a more minimalistic approach would be.




$Web = Get-SPWeb "http://site/web"
$webpartmanager = $Web.GetLimitedWebPartManager(($Web.Url + "/default.aspx"), [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)
$webpartsToDelete = $webpartmanager.WebParts | ?{$_.ErrorMessage -ne $null}
foreach ($webpart in $webpartsToDelete)
{
if ($webpart.ErrorMessage -ne $null)
{
Out-Host -InputObject " Deleting webpart.."
$webpartmanager.DeleteWebPart($webpart)
}
}
$Web.Dispose()



Much less code there but less power as well. This will obviously only work on an SPWeb object and the code would need to be adjusted for any other scope. Let’s take a look at the usage of the original function.

On an SPWeb object:




Get-SPWeb "http://server/site/web" | Remove-SPErroringWebParts


On an SPSite object:


Get-SPSite "http://server/site" | Remove-SPErroringWebParts


On an SPWebApplication object:


Get-SPWebApplication "http://server" | Remove-SPErroringWebParts


Or on an string:


"http://server/site/web" | Remove-SPErroringWebParts





Either way the function will loop through all of the “/default.aspx” pages on the SPWeb objects of the given scope and remove any web parts that have errors.

I’m sure I don’t have to tell you that this can be just as dangerous as it is helpful if you have web parts that are erroring that you are not aware of. As always use caution and I’m not responsible for anything you break while using anything you find here. Smile


I hope this helps! Any and all feedback is welcomed and appreciated. Let me know what you think!

Friday, May 13, 2011

Sign on as different user to SharePoint 2010 site published through TMG 2010

As of Service Pack 1, TMG now officially supports publishing SharePoint 2010 sites. If you have tried this you may have ran into an issue when trying to use the “Sign in as Different User” functionality. Fortunately Microsoft has released an update that resolves the issue.

http://support.microsoft.com/kb/2445386

The update is included in Software Update 1 rollup 3 for TMG SP1. This rollup can be found here:

http://support.microsoft.com/kb/2498770

However, just having applied the rollup does not solve the issue.  You will also need to run one of the following scripts on one of your TMG front ends.

For HTML Forms Authentication with Kerberos Constrained Delegation:

Const SE_VPS_GUID = "{143F5698-103B-12D4-FF34-1F34767DEabc}"
Const SE_VPS_NAME = "EnableSharepointSignIn"
Const SE_VPS_VALUE = true

Sub SetValue()

' Create the root object.
Dim root ' The FPCLib.FPC root object
Set root = CreateObject("FPC.Root")

'Declare the other objects that are needed.
Dim array ' An FPCArray object
Dim VendorSets ' An FPCVendorParametersSets collection
Dim VendorSet ' An FPCVendorParametersSet object

' Get references to the array object
' and to the network rules collection.
Set array = root.GetContainingArray
Set VendorSets = array.VendorParametersSets

On Error Resume Next
Set VendorSet = VendorSets.Item( SE_VPS_GUID )

If Err.Number <> 0 Then
Err.Clear

' Add the item.
Set VendorSet = VendorSets.Add( SE_VPS_GUID )
CheckError
WScript.Echo "New VendorSet added... " & VendorSet.Name

Else
WScript.Echo "Existing VendorSet found... value- " & VendorSet.Value(SE_VPS_NAME)
End If

if VendorSet.Value(SE_VPS_NAME) <> SE_VPS_VALUE Then

Err.Clear
VendorSet.Value(SE_VPS_NAME) = SE_VPS_VALUE

If Err.Number <> 0 Then
CheckError
Else
VendorSets.Save false, true
CheckError

If Err.Number = 0 Then
WScript.Echo "Done with " & SE_VPS_NAME & ", saved!"
End If
End If
Else
WScript.Echo "Done with " & SE_VPS_NAME & ", no change!"
End If

End Sub

Sub CheckError()

If Err.Number <> 0 Then
WScript.Echo "An error occurred: 0x" & Hex(Err.Number) & " " & Err.Description
Err.Clear
End If

End Sub

SetValue





For Integrated Authentication with Kerberos Constrained Delegation: You will need to run the script above as well as the script below.




Const SE_VPS_GUID = "{143F5698-103B-12D4-FF34-1F34767DEabc}"
Const SE_VPS_NAME = "UseOnlyNTLMForWindowsAuth"
Const SE_VPS_VALUE = 1

Sub SetValue()

' Create the root object.
Dim root ' The FPCLib.FPC root object
Set root = CreateObject("FPC.Root")

'Declare the other objects that are needed.
Dim array ' An FPCArray object
Dim VendorSets ' An FPCVendorParametersSets collection
Dim VendorSet ' An FPCVendorParametersSet object

' Get references to the array object
' and to the network rules collection.
Set array = root.GetContainingArray
Set VendorSets = array.VendorParametersSets

On Error Resume Next
Set VendorSet = VendorSets.Item( SE_VPS_GUID )

If Err.Number <> 0 Then
Err.Clear

' Add the item.
Set VendorSet = VendorSets.Add( SE_VPS_GUID )
CheckError
WScript.Echo "New VendorSet added... " & VendorSet.Name

Else
WScript.Echo "Existing VendorSet found... value- " & VendorSet.Value(SE_VPS_NAME)
End If

if VendorSet.Value(SE_VPS_NAME) <> SE_VPS_VALUE Then

Err.Clear
VendorSet.Value(SE_VPS_NAME) = SE_VPS_VALUE

If Err.Number <> 0 Then
CheckError
Else
VendorSets.Save false, true
CheckError

If Err.Number = 0 Then
WScript.Echo "Done with " & SE_VPS_NAME & ", saved!"
End If
End If
Else
WScript.Echo "Done with " & SE_VPS_NAME & ", no change!"
End If

End Sub

Sub CheckError()

If Err.Number <> 0 Then
WScript.Echo "An error occurred: 0x" & Hex(Err.Number) & " " & Err.Description
Err.Clear
End If

End Sub

SetValue





Once this is complete you should be able to Log in as a Different User to your hearts content.



I hope this helps!