Tuesday, February 22, 2011

Powershell Script for Setting SharePoint's Developer Dashboard

Here's a script that can be used to enable, disable or allow toggle of the Developer Dashboard in SharePoint 2010. Note that if using the V3 interface, you can customize the master page to add the dashboard control so that it will render:
<SharePoint:DeveloperDashboard runat="server" />

$svc=[Microsoft.SharePoint.Administration.SPWebService]::ContentService

$ddsetting=$svc.DeveloperDashboardSettings

$choiceOnDemand = New-Object System.Management.Automation.Host.ChoiceDescription `
        "On &Demand","Dashboard can be toggled via icon near Welcome Menu"
$choiceOn = New-Object System.Management.Automation.Host.ChoiceDescription `
        "&On","Dashboard is on for all pages"
$choiceOff = New-Object System.Management.Automation.Host.ChoiceDescription `
        "O&ff","Dashboard is off"

$choices = [System.Management.Automation.Host.ChoiceDescription[]]($choiceOnDemand, $choiceOn, $choiceOff)
$caption = "Specify Developer Dashboard Setting for Farm"
$message = "Current the dashboard is: $($ddsetting.DisplayLevel)"
$result = $Host.UI.PromptForChoice($caption,$message,$choices,0)

switch ($result) {
    0 { Write-Host 'Dashboard is now On Demand, toggle via icon near Welcome Menu'
        $ddsetting.DisplayLevel=[Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::OnDemand 
        break
      }
     
    1 { Write-Host 'Dashboard is now On'  
        $ddsetting.DisplayLevel=[Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::On 
        break
      }
    2 { Write-Host "Dashboard is now Off"
        $ddsetting.DisplayLevel=[Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::Off 
        break
      }
      
    default { throw "Developer Error"}
}

if ($result -ne 2) {
  $ddsetting.TraceEnabled = $true
  Write-Host @"
  Trace was also enabled.
  Note: v3 interface requires this on the master page for the Dashboard to render:
     <SharePoint:DeveloperDashboard runat="server" />
"@
} else {
    $ddsetting.TraceEnabled = $false;
    Write-Host "Trace was also disabled."
}

$ddsetting.RequiredPermissions = 'EmptyMask'

$ddsetting.Update()

It also turns on trace, so it can be handy to find hard to debug problems.
In my case, it was helpful to find out why a delegate control wasn't rendering:
Tag(8e1n) Failed to create a user control from virtual path '/_controltemplates/CustomSearch.ascx': 
'Microsoft.SharePoint.WebControls.SearchArea, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' 
is not allowed here because it does not extend class 'System.Web.UI.UserControl'.


Based on approach from Praveen Battula's blog

SyntaxHighlighter Setup

This setup will use the latest version of hosted SyntaxHighlighter:
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPlain.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPowerShell.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPython.js' type='text/javascript'/>

<script language='javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'http://alexgorbatchev.com/pub/sh/current/scripts/clipboard.swf';
SyntaxHighlighter.all();
</script>

Just put this above the closing head tag.

Then put your code in a pre tag and apply the appropriate brush, like so:

<pre class=="brush: xml">

Remember to encode you code using something like Postable or String Functions

UPDATE 9/27/12:
I was having a problem with Chrome rendering significant whitespace under the code blocks (probably due to recent changes to Blogger). I was able to get rid of it by putting in a reset css from here:
http://meyerweb.com/eric/tools/css/reset/

This issue is reported as a bug in Chrome here:
https://groups.google.com/a/chromium.org/forum/?fromgroups=#!topic/chromium-bugs/QLkCD9cOaKc

Wednesday, February 9, 2011

Editing Files in a WSP

Sometimes you don't have the Visual Studio project handy for a wsp--but you want to change something (settings, etc). I can remember trying this a while back and finding it tedious--having to resort to makecab and the like. The need came up again so I figured it was worth a search to see if anything had changed, and behold, there is an easier way now. Thanks to Grumpy Wookie for posting about a nice archiving utility, IZArc, and how to use it to edit wsp's. I found a slightly simpler process. The steps are basically:
  • Rename the WSP to CAB
  • Extract the wsp to a folder
  • Edit the extracted files as needed
  • Select all the files in extracted folder (Ctrl-A) and create a zip archive (this avoids the problem Grumpy Wookie ran into with IZArc not handling subfolders)
  • Open the zip in IZArc and do Tools > Convert Archive and select Cabinet (.cab) as the Output Type to create it as a CAB
  • Edit the created cab file to change it back to a wsp
You can download IZArc from CNet.

I wouldn't normally blog about something this trivial, but I figure the more blog posts on this, the better.

Wednesday, April 21, 2010

Debugging Gotcha With .Net's System.Diagnostics.Debugger.Break()

In developing a SharePoint feature deployed at web application scope, I was trying to attach the debugger to the w3wp.exe process so I could see what was going on in my code. I used the iisapp command to try and pick the logical process... no dice. So then I connected to ALL of the w3wp process (there were 5 for them). It still wouldn't hit my breakpoint. So then I threw a System.Diagnostics.Debugger.Break(); statement into my feature's code. When the feature activated, as expected I was given the option of selecting the debugger I wanted to use. So I chose my current VS2008 session. And here's the kicker--the next thing that happens is a dialog pops up telling you that "There is no source available at the current location". Now I had already dealt with all kinds of problems with missing symbols getting to this point, and I thought this was just the next level in the rathole I had been down on that issue. I was about to give up, but then I notided that the Call Stack pane was actually showing that the process was stopped down inside the System.Diagnostics assembly (which makes sense). All I had to do was a Debug > "Step Out" and I was back in my code, ready to debug. File under "little things that kill".

Wednesday, November 11, 2009

Face Detection "Hello World" in IronPython using Emgu CV and OpenCV

While following the instructions for setting up IronPython to use Emgu CV:
http://www.emgu.com/wiki/index.php/Setting_up_Emgu_CV_and_IronPython
I had a few problems. I started by trying to use latest versions (2.0) of these packages but kept getting dll load errors like:
"SystemError: The type initializer for 'Emgu.CV.CvInvoke' threw an exception."
I put my best google-foo on it and tried things like upgrading .Net to 3.5 but no dice. So I backtracked to Emgu CV 1.5 and OpenCV 1.1 and was able to getting it working:


import sys
import clr

sys.path.append(r"C:\OpenCV11\bin")
sys.path.append(r"C:\apps\Emgu1.5")

clr.AddReferenceToFile("Emgu.CV.dll")
clr.AddReferenceToFile("Emgu.Util.dll")
clr.AddReferenceToFile("Emgu.CV.UI.dll")
clr.AddReference("System.Drawing")

from Emgu.CV import Image, HaarCascade
from Emgu.CV.UI import ImageViewer
from Emgu.CV.Structure import Gray
from System import Byte
from System.Drawing import Size
from Emgu.CV.CvEnum import HAAR_DETECTION_TYPE

detector = HaarCascade(r"C:\OpenCV11\data\haarcascades\haarcascade_frontalface_alt2.xml")

img = Image[Gray, Byte](r"C:\OpenCV11\samples\c\lena.jpg")

# http://www.cognotics.com/opencv/servo_2007_series/part_2/page_2.html
#http://www.emgu.com/wiki/files/2.0.0.0/html/11c784fc-7d30-a921-07ec-ecdb7d217bbe.htm
scaleIncreaseRate = 1.1
minNeighbors = 3
minSearchScale = Size(img.Width/8, img.Height/8) # As a ratio of the image size:
#Or a fixed pixel size: minSearchScale = Size(100,100)
iChannel = 0 # only 1 channel

objectsDetected = img.DetectHaarCascade(
detector,
scaleIncreaseRate,
minNeighbors,
HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
minSearchScale
)[iChannel]

for obj in objectsDetected:
print "Object Rectange: %s" % obj.rect
img.Draw(obj.rect, Gray(255), 1)

ImageViewer.Show(img)

A couple notes compared to the Emgu wiki version--I was able to get everything working without having to disturb the IronPython install (I didn't copy any files into the IronPython start directory). I simply linked used sys.path to add the locations where the dll's live. Also, I did explicit import for everything. It's a bit more work to figure out what needs to be imported, but it avoids namespace pollution issues. Also, the img.Draw line needed a few tweaks. I had to drop the [float] bit from the original. And with the original version, I was also getting an error on this same line, saying:

TypeError: expected MCvBox2D, got MCvAvgComp

I was able to work around this by passing in the ".rect" rectangle attribute to the Draw method (I'm guessing the api has evolved since the 1.4 Emgu version used for the original). Lastly, I was getting two objects detected--so I used parameters to the detector to only get the single face in the image (basically by telling it to use a larger minimum detection size, minSearchScale). Anyway, now it works the way I was hoping.

And here's some bits about the environment, and the results it prints out:

C:\temp>"C:\Program Files\IronPython 2.6\ipy"
IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.3603
Type "help", "copyright", "credits" or "license" for more information
>>> execfile(r"C:\work\EmguTest.py")
Object Rectange: {X=222,Y=206,Width=163,Height=163}

And lastly, I'd be remiss if I didn't include lovely Lena, with face detected (in B&W, sorry about that Lena).

UPDATE:
When I tried to port the above configuration to my target server, I started getting that Emgu.CV.CvInvoke exception again. I upgraded the server to .Net 3.5 but that didn't get it. Then I applied the Microsoft Visual C++ 2005 SP1 Redistributable Package (see link) to the server and then it ran without error. So to summarize, I was able to get this running using Emgu CV 1.5, OpenCv 1.1, and the Visual C++ 2005 SP1 package installation. It runs on IronPython 2.0.1 and 2.6. I'm not certain if a .Net 3.5 had any effect:

Microsoft Visual C++ 2005 SP1 Redistributable Package Download

Monday, August 17, 2009

Annoying cache problem in FF3.0.x

"If it ain't broke, fix it till it is"
Of course nobody would do that intentionally, but what if something looks broken. Well then you might start throwing the kitchen sink at it and actually break it--that's my recent experience doing some SharePoint branding. I'm making changes to the CSS to overwrite the background image for the brand. It works fine in IE but it keeps showing the image I'm trying to overwrite in FF (3.0.13 in this case). So I waste a couple hours between trying variations and replicating the problem with a simple test case--having no idea it was a caching issue. But when I couldn't replicate the problem, I used a completely different computer and realized it looked fine there on the same version of FF. Argh! All that time down the drain on something that wasn't broken. Mind you, I did suspect caching at one point early on and cleared out all the cache and tried restarting FF. Now onto the research phase... After spending some quality time with google on this subject, it seems FF3 did have some caching issues. You can read about it here:

http://www.west-wind.com/Weblog/posts/469125.aspx

And here:

http://forums.mozillazine.org/viewtopic.php?f=25&t=673135&sid=7859918dca9a1722635e233ef6f401db

The bottom line--I tried everything I could think to do with FF to get it to stop caching (about:config browser.cache settings, clearing cache umpteen different ways, physically deleting cache files, appending url parameters onto the files in question) but couldn't break the back of the beast. The one thing that finally solved it was creating a new profile for FF and using that (as suggested by jscher2000 in that second link). Here's how:

http://kb.mozillazine.org/Creating_a_new_Firefox_profile_on_Windows

As for the root cause, I'm not sure. The various posting on this show it's pretty complicated--possibly involving interactions between thinks like the type of request (GET, POST), the transport (http versus https), the cache header settings, if you have other tabs open, and installed addins (especially FireBug). The nice thing about the additional profile is I can keep it plugin free--which may be why it solved the problem. Hopefully this won't be a problem anymore in FF 3.5.

Interestingly, using about:cache and FireBug, I was able to determine that the CSS file that didn't seem to be having any effect was in fact being downloaded. But when I looked at the computed CSS in FireBug, it wasn't showing the change. That doesn't necessarily mean it's FireBug causing it, but it could be the Heisenberg Uncertainty Principal is at play.

UPDATE
A coworker suggested I try Ctrl-Shift-R which is supposed to completely bypass cache. So I fired up the handy Tamper Data FireFox plugin since it shows the "Load Flags" of each requested URL (presumably FireFox's decision about what action it needs to take regarding the request URL--pull from cache, download, etc). A quick test of this on a blogger.com page showed that it did indeed eliminate most cached elements with a status of LOAD_BYPASS_CACHE. However, a few URLs, in this case images of type .png and .gif, still had a LOAD_ONLY_IF_MODIFIED status without any further followup showing up in Tamper Data. So while Ctrl-Shift-R does resolve most caching, it is still doesn't eliminate it completely.

Friday, April 17, 2009

SharePoint Feature Scope Changes Ignored

The Problem
I ran into a situation where I had deployed a broadly scoped feature and then narrowed the feature scope down, but the feature was acting like it still had the original scope settings. The feature was a delegate control to deploy JQuery using the AdditionalPageHead delegate control, just like Jan Tielens described here. When I had the feature scoped to the site collection (Scope="Site"), it was auto-deploying across the site collection as expected. But then when I tightened the scope down to specific websites (Scope="Web") and added a Scope="false" to make it require manual activation, it was behaving as if the it was still scoped at the site collection and was still auto-deploying. This continued even when I completely deleted the solution.
The Fix
After completely deleting the solution, I updated the solution and feature with new GUIDs. Thereafter, it behaved as expected. It seemed to behave like some remenant of the solution wasn't fully removed by from the solution store even though the solution was deleted. Here's a related forum posting on the issue. If it was something I did wrong, then I doubt changing the feature and solution GUIDs would have fixed it--that's my story anyway.

I'll also mention that I tried developing this with VSeWSS 1.3 but was frustrated by it always creating an assembly (even for the "empty" project template) which couldn't be removed without breaking things. I fell back to STSDEV which is remains my tool of choice.