Archive for the ‘Tech’ Category

Web Service access + internal traffic + 407 Proxy Authentication Required

Friday, March 2nd, 2012

This had me stumped for a while. I was developing a SharePoint-based client to consume a simple web service. I started by writing a console app version of the code before deploying to SharePoint. Fairly straight-forward – added a web reference to my VS2010 project, and used

MyWebService srv = new MyWebService();
srv.DoSomething();

Early on in the project, I didn’t give much to the fact that when calling the method on the web service, I was given a 407 Proxy Authentication Error. I just setup a simple proxy for it:

WebProxy prox = new WebProxy("192.168.0.1:80"); // where 192.168.0.1 is the address of the proxy.
prox.UseDefaultCredentials = true;

// Tell the service to use the proxy
srv.Proxy = prox;

This “fixed” the issue – until the point where I deployed the code in to SharePoint with multiple application / frontend servers, and I unwittingly encountered the double hop authentication problem. In short, by using the “UseDefaultCredentials” option, you’re saying “use the credentials of the person currently logged in”. This will therefore work in a Windows Auth / NTLM scenario (assuming that user is allowed to authenticate against the proxy) where everything is all happening on the same server. But when you have multiple servers, and the action happens on Server A, which triggers something on Server B, to authenticate against Server C (i.e., your web service), then things fall over because NTLM does not support user delegation. See here for a really neat explanation of it.

After faffing about a lot with credentials, and the proxy server involved, googling and so on, my brain finally engaged: All traffic is internal, why is the proxy server even involved?! The proxy server is designed to marshal access to the outside world. All internal traffic should be fine! I went back to basics. My console app still suffered the error, but the excellent SoapUI which I use for testing web services didn’t need any proxy authentication! It turns out that by default, .NET applications will attempt to use a proxy, even if it doesn’t need one. Allegedly, if it doesn’t have a proxy override configured, then it will attempt to use the Internet Options configured on the machine it’s running on. The problem though is that if you do need a proxy for some stuff, and don’t need a proxy for other stuff (in this case) then you’re in a spot of bother. The trick is to tell your .NET app (or indeed your IIS website) to not use a default proxy. This can be done by adding this to your app.config or your web.config:

<system.net>
  <defaultProxy
    enabled="false"
    useDefaultCredentials="false">
    <proxy/>
    <bypasslist/>
    <module/>
  </defaultProxy>
</system.net>

Enjoy.

Creating SharePoint 2010 Content Organizer Rules programmatically

Thursday, February 23rd, 2012

The Content Organizer (gah! Organiser!) in SharePoint 2010 is a nifty new feature that enables documents to be added to a single library (the “Drop Off Library”) and then let SharePoint route them through to the correct final resting position based on a set of configured rules. Rules can be configured per content type and allow conditions to be set based on metadata on the item. You can even use it to send documents – and document sets – between site collections, e.g., to a Records Center. Very cool.

Depending on your requirements, you may find you need to create a lot of rules which as with most things SharePoint can be cumbersome if you need to do it all through the UI. Fortunately, creating the rules programmatically is straight-forward.

(more…)

Powershell tip – find all checked out files

Wednesday, February 15th, 2012

I needed to quickly find all files in a particular web that were checked out. I immediately went to Powershell, and after hacking about for a few minutes did what I should have done first – Google’d it. Doing this revealed that Gary had already done the bulk of what I needed to do. However, I made a couple of changes, namely that I only wanted it to traverse a specific web, but I needed it to traverse any subwebs in that web and lists.

function GetCheckedOutFiles($web)
{
Write-Host "Processing Web: $($web.Url)..."
        foreach ($list in ($web.Lists | ? {$_ -is [Microsoft.SharePoint.SPDocumentLibrary]})) {
            Write-Host "`tProcessing List: $($list.RootFolder.ServerRelativeUrl)..."
            foreach ($item in $list.CheckedOutFiles) {
                if (!$item.Url.EndsWith(".aspx")) { continue }
                $hash = @{
                    "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)");
                    "CheckedOutBy"=$item.CheckedOutBy;
                    "CheckedOutByEmail"=$item.CheckedOutByEmail
                }
                New-Object PSObject -Property $hash
            }
            foreach ($item in $list.Items) {
                if ($item.File.CheckOutStatus -ne "None") {
                    if (($list.CheckedOutFiles | where {$_.ListItemId -eq $item.ID}) -ne $null) { continue }
                    $hash = @{
                        "URL"=$web.Site.MakeFullUrl("$($web.ServerRelativeUrl.TrimEnd('/'))/$($item.Url)");
                        "CheckedOutBy"=$item.File.CheckedOutByUser;
                        "CheckedOutByEmail"=$item.File.CheckedOutByUser.Email
                    }
                    New-Object PSObject -Property $hash
                }
            }
        }
foreach($subWeb in $web.Webs)
{
GetCheckedOutFiles($subweb)
}
        $web.Dispose()
}

$web = get-spweb $args[0]

GetCheckedOutFiles($web)

Save it as GetCheckedOutFiles.ps1 and you would then call it with

./GetCheckedOutFiles http://urltoweb | Format-Table url | out-file output.txt -width 500

(or do as Gary does and save it as cmdlet for easy reuse.)

Quick tip: SharePoint powershell – get items in a list based on custom columns and other hints

Tuesday, February 14th, 2012

This may be handy when trying to find specific items in a list based on values of various fields:

$web = Get-SPWeb http://yourweb
$list = $web.Lists["Your Library Name"]

// this is the bit - get items of a particular content type
// ? is shorthand for where, and $_ is the item in the pipeline
$listItems = $list.Items | ?{$_.ContentType.Name -eq "Content Type Name"}

// or items based on a custom column - if using -like then the wildcard is *
$listItems = $list.Items | ?{$_["InternalFieldName"] -like "*this*"

// you could join them up using -and
$listItems = $list.Items | ?{$_.ContentType.Name -eq "Content Type Name" -and $_["InternalFieldName"] -like "*this*"

// or iterate the loop and print them out
foreach($item in $listItems) { Write-Host $item.Name, $item["InternalFieldName"] }

or more directly

$list.Items | ?{$_.ContentType.Name -eq "Content Type Name" -and $_["InternalFieldName"] -like "*this*" | foreach { $_.Name, $_["InternalFieldName"]

// or count them
$listItems.Count

or

$list.Items | ?{$_.ContentType.Name -eq "Content Type Name" -and $_["InternalFieldName"] -like "*this*" | foreach {$count++}
$count

Powershell can be infuriating – but when you find the syntax, it can be pretty helpful.

P.S For a bonus tip, next time you’re in Powershell, hit F7 ;)

SSRS error: Operation is not valid due to the current state of the object

Friday, February 10th, 2012

If you’re using SSRS in SharePoint integrated mode, you may come across this error when using report parameters that have a high number of items in them. A recent security bulletin highlighted some issues and vulnerabilities in ASP.net, and a patch was released to cover some of the items. One of these was the maximum number of items you can have in a collection. If you exceed the limit, then you’ll likely get an error like:

System.Web.HttpException:
The URL-encoded form data is not valid. —> System.InvalidOperationException: Operation is not valid due to the current state of the object.
at System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded()
at System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding)
at System.Web.HttpRequest.FillInFormCollection()
— End of inner exception stack trace —
at System.Web.HttpRequest.FillInFormCollection()
at System.Web.HttpRequest.get_Form()

The workaround to this is to add the following to your web.config for your IIS application:

<appSettings>
<add key=”aspnet:MaxHttpCollectionKeys” value=”5000″ />
</appSettings>

where 5000 is a number big enough to cover the number of items in your collection. Be aware of the security implications this could have. There’s some really useful info around the issue, here.