View in Web Browser /SharePointThoughts/_layouts/VisioWebAccess/VisioWebAccess.aspx?listguid={ListId}&itemid={ItemId}&DefaultItemOpen=1 0x0 0x1 FileType vdw 255 Manage Subscriptions /_layouts/images/ReportServer/Manage_Subscription.gif /SharePointThoughts/_layouts/ReportServer/ManageSubscriptions.aspx?list={ListId}&ID={ItemId} 0x80 0x0 FileType rdl 350 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rdl 351 Manage Shared Datasets /SharePointThoughts/_layouts/ReportServer/DatasetList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rdl 352 Manage Parameters /SharePointThoughts/_layouts/ReportServer/ParameterList.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 353 Manage Processing Options /SharePointThoughts/_layouts/ReportServer/ReportExecution.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 354 Manage Cache Refresh Plans /SharePointThoughts/_layouts/ReportServer/CacheRefreshPlanList.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 355 View Report History /SharePointThoughts/_layouts/ReportServer/ReportHistory.aspx?list={ListId}&ID={ItemId} 0x0 0x40 FileType rdl 356 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsds 350 Edit Data Source Definition /SharePointThoughts/_layouts/ReportServer/SharedDataSource.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsds 351 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 350 Manage Clickthrough Reports /SharePointThoughts/_layouts/ReportServer/ModelClickThrough.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 352 Manage Model Item Security /SharePointThoughts/_layouts/ReportServer/ModelItemSecurity.aspx?list={ListId}&ID={ItemId} 0x0 0x2000000 FileType smdl 353 Regenerate Model /SharePointThoughts/_layouts/ReportServer/GenerateModel.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 354 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType smdl 351 Load in Report Builder /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderModelContext&list={ListId}&ID={ItemId} 0x0 0x2 FileType smdl 250 Edit in Report Builder /_layouts/images/ReportServer/EditReport.gif /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderReportContext&list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 250 Edit in Report Builder /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderDatasetContext&list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 250 Manage Caching Options /SharePointThoughts/_layouts/ReportServer/DatasetCachingOptions.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 350 Manage Cache Refresh Plans /SharePointThoughts/_layouts/ReportServer/CacheRefreshPlanList.aspx?list={ListId}&ID={ItemId}&IsDataset=true 0x0 0x4 FileType rsd 351 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rsd 352 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 353 Compliance Details javascript:commonShowModalDialog('{SiteUrl}/_layouts/itemexpiration.aspx?ID={ItemId}&List={ListId}', 'center:1;dialogHeight:500px;dialogWidth:500px;resizable:yes;status:no;location:no;menubar:no;help:no', function GotoPageAfterClose(pageid){if(pageid == 'hold') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/hold.aspx?ID={ItemId}&List={ListId}'); return false;} if(pageid == 'audit') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/Reporting.aspx?Category=Auditing&backtype=item&ID={ItemId}&List={ListId}'); return false;} if(pageid == 'config') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/expirationconfig.aspx?ID={ItemId}&List={ListId}'); return false;}}, null); return false; 0x0 0x1 ContentType 0x01 898 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XsnLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 FileType xsn 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.2 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.3 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.4 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsx 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsm 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsb 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType ods 255 |
|
|
| Over here in the skunk works division of our company... we've been busy the past few months working on some prototypes that will allow us to integrate physical data with the usefulness of SharePoint. We're unveiling a portion of our efforts at the SharePoint Evolutions Conference 2013 in London next week. You've heard me say this before - this conference rocks. I love this conference for many reasons but the one reason that sticks out in my mind is the simple fact that I spend a lot time creating new content. This year was no different! The fact we got to use soldering irons to put a demo together made this the most exciting presentation build... :) If you are attending the conference next week, swing by my session and check out the evolution of business data collection and management... Title: Remote monitoring with SharePoint 2013 and making it smart! Session: COM710 from 1500-1600 in the Rutherford room This should be a fun session with demos, hardware with blinky lights, and hopefully some good discussion! -Maurice |
| First, the title is a tongue in cheek. This past fall, I lost the MVP status that I had carried for the past 5 years. As everyone knows, Microsoft’s MVP status is an award bestowed to those that are actively involved in the “community”. Every year, the team looks at what you’ve done in the past 12 months to figure out if you deserve a marketing award. The short answer to the title was that I was busy working. Last year was an absolutely dizzying year. The net result was that I wasn’t an active blogger or speaker. I had a few posts and only 2 speaking engagements. Shame! What was I doing? Working on SharePoint and life’s other miscellaneous projects. :) Here’s a rough breakdown… SharePoint – Aptillon has been moving forward in leaps and bounds. Work was good. Work kept me traveling. By the end of January last year, I had already been in Jersey City, Dallas, Ft. Lauderdale, and Honolulu. 24,000 miles in 1 month. Ok, Ft. Lauderdale was not work related (more on that later). Mileage total for the year? Roughly 160,000 miles here in the US - none of that fancy travel to Europe or Australia or Antarctica.. and that was with me putting the kibosh on travel for nearly 2 months - twice. I reached Delta’s platinum level before most folks even start buckling their seat belts. SharePoint in the cloud? Just pray you don't have a screaming kid next to you. :) Businesses – I now own a part of 3 companies. I started out owning 2 and by year’s end, my wife and I started a new venture. Running a single company takes time and effort. Running two takes patience. Running three requires medication! Speaking - last year was the quietest year I've had since I first entered the speaking circuit. There were a couple of occasions where I just forgot to send in ideas and applications. Worse yet, I made a huge scheduling mistake when I double booked a conference with a client engagement. We got the project out the door that week, so it was a nice offset to missing the conference in Orlando. The Boat – Sailing has been a part of my life for quite some time. My big dream in life has been to buy a boat and go around the world. Luckily, the woman I married also shares that dream. We started looking for a boat in late 2011. We entered 2012 with some serious shopping plans (it’s why I was in Ft. Lauderdale in Jan). Well, long story short. We are now the proud owners of a beautiful Catana 472. We found her in San Diego and after a super long story involving an incompetent captain and a company that literally left us (and others) high and dry in Ensenada, she came home to Tacoma in late October. Tacoma – For those not from the Seattle area, Tacoma is roughly 35 miles south of Seattle. I’ve been in Seattle for 17+ years. In that time, I spent all of maybe a half day in Tacoma. It’s never been a destination for me. Either you’re driving through Tacoma on your way to Portlandia or taking the long route to the Olympic Peninsula. With the boat moored in Tacoma, we’ve had to learn a new city. I have to say it’s been a lot of fun learning more about the city. It’s got some hidden gems and you can definitely see where they have been trying to revitalize the city and the waterfront. The Boat (part 2) – With the boat moored in Tacoma, we literally took on a new primary job – boat maintenance. First, we’ve had to figure out everything there is about the boat. Have you ever bought a house or rented an apartment? How much time do you spend thinking about how things work in house? Probably next to nothing. You figure out where the light switches are located and then you move in. Boats, especially the larger they get, are complex machines. You need to know where the switches are… what is connected to them (outlets)... what they are connected to (breakers)... what are the emergency shutoff points... what parts are needed in case something breaks... etc.. etc... now rinse and repeat for water - all three types, fuel, etc... in a nutshell, understanding what we have and identifying all the things that need to be fixed (especially after a 1300 nm voyage up the West Coast) has been daunting. MCSM - even though I lost my MVP status, thankfully I didn't lose my Masters certification! To be honest, I am still having problems typing MCSM (Microsoft Certified Solutions Master) rather than MCM. You might have noticed my earlier post on how the certification program is changing things around. Not only was I excited to see these improvements make their way into production, but toward the end of year I also had a chance to work with the Masters certification team again. It was fun getting back into the frame of mind of building detailed courseware. My teammates David and Matt also helped out as we put together four different modules for the Masters program. Then I had to do double duty in late December as a student for the first rotation in the updated format. Somewhere in there... we had family come visit twice, we hopped on planes to visit them as few times as well. Oh yeah - I even had my tonsils taken out some time in April. That was a fun drug trip that did not involve planes at all. :P Pretty much 2012 was a whirlwind. SharePoint 24/7/365 + a boat ... and a lot of planes. My pledge to the long time readers of this blog ... I'll actually reserve some time this year to share more stories about SharePoint and how to make it do more for us. I might even throw a few boat stories... Have fun! -Maurice |
| Certifications. Need it? Want it? Worth it? Those are common questions that I hear from customers and the folks on the front line. The answer in the past was often times buried in the intricacies of perceived value but for a lot of folks it comes down to the simple process of evaluating talent. Either you’re selling talent or your trying to acquire talent. Certifications are intended to provide a measurement stick. It’s like looking at a resume and figuring out if the applicant can even spell Sharepoint. In the SharePoint space, though, the standard certifications have traditionally been too easy to obtain and thus the Worth portion of the equation was often times devalued due to the ease. Microsoft has realized that they needed to put the certify back into the certification process. Today, we’ll discuss the changes that have been made to Microsoft’s certification stack. Your answers to Need, Want, Worth will might change. Hopefully, you’ll start to see the promise of the new system. But first, let’s take a look back in time… Starting with the 2003 SharePoint certifications, and all the way through 2010, the “core” certifications for SharePoint always involved tests that centered on admin and developer topics. Then those topics were split into a “beginner” and “advanced” sections. The model was built around an arguably sound reasoning: some people are less experienced and then grow their talents. However, there was a key problem with those tests – they really didn’t measure your ability. They measured your capability to take a test. In a nutshell, the tests didn’t validate your knowledge or experience. Put differently - If administrators walk into a developer test, having never written a single line of code, and pass the test… is that a good developer test? Unfortunately, this gap between theoretical and actual validation caused a lot of problems. If it was too easy to get a certification, then folks that relied on certifications to measure experience were basically up the creek. Knowing there was a serious problem in this space, Microsoft introduced the Master’s level certification for SharePoint in early 2009. The Master’s certification was designed to validate a candidate as having actually used the product in real-life scenarios in addition to having completed very rigorous training and testing regimen. It was designed to be tough – you had complete all the underlying SharePoint exams for both admin and dev (ok, that part was easy), then submit a resume outlining your body of work in the SharePoint space, then if selected you would have to navigate a phone interview before final acceptance into the program, take a 3 week course, and cap it all off by taking a hands-on qualifying lab and written test. The Master’s program was without a doubt the hardest certification to obtain. The Master’s program was designed to provide the market place with proven experts within SharePoint. However, there was still one core problem… the program when looked at as a whole was imbalanced. The underlying exams were too easy and the Master’s program, being the next jump up, was too almost too deep for most people. There was no in between. We needed an in-between. It was like going from grade school to graduate school in one leap. The changed introduced by Microsoft in the last half of 2012 have been designed to update the process. We know have a defined path of increasing difficulty that is better tied to the components of the platform *and* allows candidates to grow their experience at their pace. We now have the opportunity from grade school to high school to undergrad and beyond. First, let’s take a look at what it takes to become the Certified Solutions Master. The program requirements are available at http://www.microsoft.com/learning/en/us/mcsm-sharepoint-certification.aspx. Digging deeper we find that administrator and developer certifications are truly geared toward testing your knowledge of the technologies (see also http://www.microsoft.com/learning/en/us/certification-overview.aspx). A quick read reveals a few key changes: SharePoint certification is no longer focused solely on SharePoint I love to tell folks that SharePoint is an ecosystem. If you treat as an application, you’ll fail. SharePoint has many components, all of which have different characteristics. Certification should be no different. Both the administrator and developer tracks now incorporate facets that live outside of SharePoint. This makes a ton of sense. I can’t be an administrator of a SharePoint farm without understanding the operating system, active directory, etc. and likewise, I can’t be a good developer without understanding other common development technologies and techniques that live outside of SharePoint. Commonalities make it easier to grow and cultivate your experience SharePoint certification now relies on tests that are validated, refined, and used by other segments of the technology stack. Think about this way, do you want SharePoint testing you on how to be server administrator or would you rather have the Windows team test you? Also, by leveraging the courseware in other technologies, a candidate has the opportunity to spend time in other areas without worrying about digging themselves into a hole. Courseware improvements reestablish the value of certification From the Master’s perspective, because the course is now spread out across the different segments of the platform, the SharePoint certification team can focus on teaching rather than trying to go through a laborious process involving interviews and resumes. The MCSM certification pre-requisites ensure the candidates actually fit the bill of a Master’s candidate. Keep on learning Digging deeper into the certification changes, you’ll also find that certifications are no longer static. This means that certifications will expire unless you go back and recertify. At first, I didn’t like this idea because it felt like a forced learning process. However, it makes sense. Technologies change and the platforms are ever evolving. The tests themselves will change. This is brilliant as complex platforms such as SharePoint will be incorporate field experience and other improvements into the tests. As SharePoint grows, the test will improve and the *next* time you have to take a SharePoint exam, the student will be able to validate new skillsets. Put differently – if you want to keep the shiny little badge of honor on your resume, you should be up to speed on the product and technology space. It’s worth noting the developer track hasn’t been fully announced but if initial talks are any indication, you will find that the developer courses will be heavily influenced by content from existing developer courses in other areas. Again, the concept is leverage knowledge as much as possible.
In general, the retooling of Microsoft’s certification process is a welcomed change. Need it, Want it, and Worth it? As you grow with SharePoint, I think the answer takes on a vastly different outlook than it did in the past. The courseware is more extensive and tests are shaping up to be much better than in the past. We’re no longer jumping from grade school over to doctoral work – there’s a middle ground and you get to figure out how to best tailor that experience for yourself. -Maurice |
| Every once and while you run into a silly bug that actually takes you a long time to figure out. Some time ago I ran into a problem with a custom SPDiagnosticServiceBase class that only surfaced via PowerShell. Let’s take a closer look at the problem... First, we start out by creating a custom diagnostic logging class that contains multiple categories. When it’s properly deployed, we’d see custom area ("Test Area") and all of the categories in Central Admin. Through the Diagnostic Logging page, you’d find you can change the throttle limits like any other out of box category. Now, let’s open up a PowerShell console and try to change one of the categories using Set-SPLogLevel. This commandlet allows you to specify the area and category using a very simple Area:Category format. In a simpler fashion, if you specify a string with no colon, the value you provide is treated as a category. In the next screenshot, you can see that I am trying to set the TraceSeverity to Verbose for category "dddd". Note the error that is returned!  Huh?! Didn’t I just see that category in Central Admin? How about if I try the more generic Area:Category format with a wildcard? Same result! I shot an email off to my teammate Gary Lapointe, who knows all things PowerShell, and a group of SharePoint Masters. No luck. No one apparently has seen this problem. This was going to be just one of those days... The biggest clue popped out when I tried using the most generic form of Set-SPLogLevel. If you don’t specify an Identity parameter (for example: "Set-SPLogLevel -TraceSeverity Verbose"), Set-SPLogLevel sets the provided value to all categories. However, for our custom diagnostic class, what do you see?  SP was seriously getting confused. Three problems jumped out: Trace Severity was set to the wrong value (None instead of Verbose), Event Severity was improperly changed to "Error", and finally only the first category was updated. To make a long debugging story short, I finally was able to isolate and fix the problem! Core problem: My problems all arose from how I initialized the categories themselves. If you call the simplest constructor (as I did and most likely a lot of other folks!), your code would look like ...  The real tricky part to isolating the problem is that you need to set the log levels via PowerShell first. If you set the log level via Central Admin, the problem is mostly hidden. The fix: Use the SPDiagnosticsCategory constructor that takes four parameters. In particular, specify a value for the category id. The updated initialization block looks like...  In my example, the id value is coming from an enum that is used for categorization of the items written to the diagnostic service. This could have easily been as simple as an incrementing counter (0, 1, 2, etc). Be sure to start the value sequence at 0. I eventually found that if you want to start your ID values at something other than 0, you’ll eventually run into the same problem. With the SPDiagnosticCategory initialized in this fashion, setting the log levels via PowerShell will work as expected. Log away! -Maurice |
| WebTemplates are definitely a powerful new construct in our SharePoint 2010 toolbox. WebTemplates definitely come in handy as they can be deployed as sandbox-compatible features.
Creating a site based on a web template is pretty straightforward via the UI. Basically it just shows up as another site template option. As a user creating a site, you’d never the know the difference between a farm-scoped or site-scoped WebTemplate. However, if you want to use PowerShell, you will notice that your PS scripts will take on a slightly different shape based on how the WebTemplate is scoped.
If the WebTemplate is deployed as a farm-scoped feature, then you can easily use New-SPWeb in the following manner:
new-spweb $url –template “{GUID}#WebTemplateName”
where GUID represents the parent feature ID.
If the WebTemplate is deployed as a site-scoped feature, then your PowerShell needs to be adjusted. Otherwise, if you attempt to use new-spweb, you’ll get the following error message: Template is not found and is not applied. This effectively means the cmdlet could not locate a farm-level template to apply to the new site.
For example...

There are two ways to circumvent this problem:
- Once the site is created, call ApplyWebTemplate
- Before the site created, grab a reference to the appropriate WebTemplate and provide it as a value to the SPWebCollection.Add method on the parent site.
Examples
Calling ApplyWebTemplate
$url = "http://sitecollection/site1"
$w = new-spweb $url
$w.ApplyWebTemplate("{GUID}#WebTemplateName")
Calling SPWebCollection.Add
$url = "http://sitecollection"
$w = get-spweb $url
$template = $w.GetAvailableWebTemplates(1033) | ? { $_.name -eq "{GUID}#WebTemplateName" }
$w.Webs.Add("site1", "sample site 1", "sample description", 1033, $template, $false, $false)
The difference between the two methods basically boils down to the language selection for the new site. With the simple call to ApplyWebTemplate, the new site uses the same language as the parent. By grabbing the reference to the web template beforehand, you have more control.
-Maurice |
| This year’s SharePoint Conference was probably one of the most interesting conferences that Microsoft has hosted in the past few years. The attendance was solid and presentations covered the spectrum from 101 fundamentals over all the way over to nitty-gritty details. Monday morning I had a chance to present on managing the Sandboxed Code Service (SP376). I was a little skeptical that we’d fill a room with 700 seats, but I was very pleasantly surprised to see the room fill up before we switched on the microphone. There were a ton of good questions afterwards as well. Thanks to everyone who attended and posted all the great messages on Twitter. If you have any questions I was unable to answer, please feel free to reach out. The conference was also a great chance to run into folks. I saw many old friends – some that I haven’t seen literally in years – as well as many clients and former Critical Path Training admin and dev students. It’s always amazing to see the positive energy! The Aptillon team also had record number of presentations at the conference. We had 7 presentations by 6 different teammates. As a company partner, that is definitely very cool stat however the nicer fact is that we had a chance to hang out. Since we’re spread out all over the US and constantly on the go, it’s rare to have more than 2 people in the same room at the same time. There was also a record number of Microsoft Certified Masters from across the globe at the conference. How cool is that? I remember the days when Spence and I were the only MCMs who weren’t employed by Microsoft. :) MSL also announced a new certification – Microsoft Certified Architect. It’s really nice to see program growing! Great conversations all around. New projects, new ideas, confirmation of design decisions... chatting about the sandbox, helping folks get a better perspectives on PowerPivot and it’s amazing potential, the cloud, getting out of the sandbox (aka azure), Windows Phone 7, watching cloud-servicing applications such as Sharevolution hit their stride, building new partnerships... truly exciting stuff! -Maurice |
| In an earlier post, I briefly touched on the value of creating your own InsertWebPartIntoWikiPage method. Part 1 – solved. Now comes Part 2 – where am I injecting my web part?
That’s a valid question that is easily answered whenever you’re using the SharePoint wiki page editing tools within the browser. The tools allow users to basically pick a spot in the rendered text, click on Add Web Part, and you are done. The tools know how to safely inject your web part without forming bad html under the hood.
From a programmatic sense, this is much harder because we don’t get the “smarts” of knowing where to insert the web part markup. Most users that try to use InsertWebPartIntoWikiPage invariably fail the first few times because they forget to account for the fact that they are injecting web part markup into an html blob and therefore need to properly account for well-formedness (is that a word?).
The net result is that folks will create code that looks like…
InsertWebPartIntoWikiPage (file, webpart, randomValueKeepFingersCrossedNothingBreaks)
The validity of the resulting HTML becomes something like rolling the dice at the casino. Most folks can start with an empty page and count the number of characters to the first legitimate location where web part markup can be injected. However, once the page is created and populated, all bets are off and IWPIWP becomes more of a hindrance than an aid but it doesn’t have to be that way.
Wouldn’t it be nice to be able to readily determine where the valid injection points are located? Sure! The answer comes in the form of good old fashioned regular expressions.
If you’re like me, you’ve got a nice little regex library for most any html operation (tag stripping, tag collection, validation, etc). Well, here’s one more that you can add to the list… a regex to safely identify the your Wiki page regions!
This little regex allows you to easily determine how many regions are in your Wiki page and, more importantly, where they begin and end. The regex groups the valid editable regions with the name “InnerHtml”. They represent the blue-bordered regions whenever you are editing a wiki page in the browser (as shown below).

In it’s simplest form, you can now inject your web parts in the right places without destroying your existing HTML. For example, in the following clip, we add a web part at the start of the second region in the page.

Done! Page is updated with my web part in the right place and it all just works.
The really nice thing is that since we’re only identifying the HTML within the region, we can easily use the regex to update the text as needed in the region of my choice.
Here’s another example where we identify a region and then replace it with new text.

What other tricks can you come up with? How about identifying the web parts that exist in the page? How about placing the new web parts in mid-stream w/o breaking the existing HTML structure? All possible with regex, especially now that we’ve clearly identified the InnerHtml of your regions!
You got to love the power of regular expressions because with a little ingenuity you can solve each one of those problems.
-Maurice |
| Buried deep in the recess of the WebPartPages class, there is a static method that belongs to the WikiEditPage class and its sole purpose is to allow you to insert WebParts into a wiki page. The static method Microsoft.SharePoint.WebPartPages.WikiEditPage.InsertWebPartIntoWikiPage basically takes 3 parameters – the file, the webpart, and the text position of where you want to inject the web part. All is fine and dandy except for one thing – the html that is produced by the method is invalid. The method basically injects the html shown on the slide below.  Take special note of the next to last <div> tag. Self-closing tag results in broken wiki page! <div style='display:none' id="vid_{0}"/>
The tag as written is self-closing. Unfortunately, when the text is processed by SharePoint’s parser, the self-closing notation is not recognized as valid html and the parser leaves this tag open. This results in a very broken wiki page because the closing </div> does not exist for the segment of html that was just injected into the page. Take a look at the image below – 3 start tags but only 2 end tags.  The fix is pretty easy. Create your own version of InsertWebPartIntoWikiPage! All you need to do is change that next to last div tag from one that uses the self-closing notation over to one that properly uses an end tag.  Once you do this, your html segment will look like...  Nice and clean with the right number of start and end tags. More importantly, your wiki page will work as expected. Later this week, I’ll show you a really cool way to use regex to control the location of the web parts that you’re trying to add to the wiki page. -Maurice Reference Post: Regex for Wiki Page regions |
| Earlier today, Todd Klindt and I had a brief twitter chat. Basically, he ran into some problems with a site that had been run through the wringer with Import/Export. Todd asked a really good question for which the answer requires a little more space than twitter allows. :) For those that are relatively new to SharePoint, they don’t often times don’t get a chance to learn what works or what needs to be avoided until it’s too late. Let’s take a brief look at the history of this feature set so that if you’re new to SharePoint, you’ll know where some issues may pop up. Import/Export is one of those features that needs to be used with caution. Why? Well, we have to go back to RTM of 2007 when the world was first introduced to Import/Export (aka PRIME). It was a very broken toolset. Fast forward a year or so, then the Infrastructure Updates for 2007 was released. This was a special set of fixes designed to repair the underlying Import/Export engine. The IU made the feature set much more usable; however, there were a core set of things Import/Export still could not do. To the average SharePoint administrator, this basically means Import/Export is NOT a full fidelity solution for backing up and moving data. Again fast forward to 2010 RTM. Import/export is still pretty much unchanged. At the site (aka web) level, Import/Export is without a doubt a very problematic feature. Import/export does not offer full fidelity data export. Thus, at the site level, you’re somewhat gambling with your data. Sometimes it will work and other times it may not. There are a lot of threads all over the place that help us see that Import/Export-ed sites tends to have weird and random behaviors. As an administrator, the last thing I want to do is chase down problems with restored data. Is Import/Export really that unreliable? The answer is generally yes. However, we definitely need to give Import/Export some credit. At the list and item level, Import/Export can actually go the full cycle. The more granular you are (i.e. items), the easier it is for Import/Export to actually work as we expect it to. Using Import/Export to move items is what is known as “cherry picking”. It works and that leads us to the one of the possible options to Todd’s question... “What (are the) other options for breaking up a site collection?” Generally speaking you need to migrate your data. You’ll either need to ... - explore using Import/Export at the item level or
- work with a custom solution (written in C# or PowerShell) that extracts the data locally and pushes it to a new destination.
Migration is not nearly as simple as just clicking on the Central Admin ui to export a site, then repositioning it. However, it’s the only way you be assured that all the data you care about is where it needs to be and that your site is fully functional. Should you build or buy the tools to migrate your data? It depends on your needs, skills, and timeframes. There are lot of good tools – from free to pay. PowerShell and custom code are definitely viable options. Migration does take a little more planning but it inevitably makes for a much nicer end result. It’s a great way to reduce clutter (e.g. no need to migrate stuff that doesn’t matter!) and you can rest easier when the process is done. It’s worth calling out that with any migration plan, though, you should incorporate a testing strategy. Testing will validate that your migration technique will successfully meet your requirements. Happy migrations! -Maurice |
| Have you ever needed to process an assembly prior to having it packaged up for deployment? A classic example of this requirement is using an obfuscator or signing/watermarking tool. Prior to the introduction of the VS2010 SharePoint tools, the general advice was to use AfterBuild (reference How to: Extend the Visual Studio Build Process). Unfortunately, this doesn't really work when dealing with solution packages built in VS2010. The reason is pretty simple – AfterBuild is too late. You can run your assemblies through the tooling process, but the modified assemblies won’t be a part of your solution package. The packaging step picks up the assemblies before AfterBuild kicks off. How about AfterCompile? This window of opportunity for post-processing your assembly is ok, but not entirely what you want to use. You will get your processed assembly into the solution package; however, since the tool will modify your assembly, in the long run you will be wasting a lot of time and cpu as AfterCompile will be called multiple times. On a fast running process, you may never even notice this is happening. On a long running process, your mods will trigger multiple calls to compile and the time to completion will literally get out of hand. The right solution? Override AfterLayout. This target is new target that is listed as a dependency by the CreatePackage target found in Microsoft.VisualStudio.SharePoint.targets.  All you need to do is open up your project file and add a definition for AfterLayout as shown below:  As you can see, AfterLayout is the perfect solution! The really nice thing is you can use conditional expressions to define when to run the post-processing tool. In the example above, the tool is run only when working with Release builds. The build process will go through and copy all the files into the pkg folder. AfterLayout is called once all the files are dropped into the folder, but before they are bundled up into the wsp. Your post-processing tool can then reference the built assembly from the pkg folder.  Ta-da! Done. Your post-processing tool will run when you need it w/o taking the multi-run penalty of using AfterCompile. Just to give you an example of how efficient AfterLayout is compared to AfterCompile, we recently reduced our build times on one of projects from roughly 3 hours to under 32 minutes. Old habits of defaulting to AfterCompile basically cost us a lot of time early on in our dev cycle... I can’t tell you how nice it was to get builds back down to normal times. :)
Happy coding! -Maurice |
View in Web Browser /SharePointThoughts/_layouts/VisioWebAccess/VisioWebAccess.aspx?listguid={ListId}&itemid={ItemId}&DefaultItemOpen=1 0x0 0x1 FileType vdw 255 Manage Subscriptions /_layouts/images/ReportServer/Manage_Subscription.gif /SharePointThoughts/_layouts/ReportServer/ManageSubscriptions.aspx?list={ListId}&ID={ItemId} 0x80 0x0 FileType rdl 350 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rdl 351 Manage Shared Datasets /SharePointThoughts/_layouts/ReportServer/DatasetList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rdl 352 Manage Parameters /SharePointThoughts/_layouts/ReportServer/ParameterList.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 353 Manage Processing Options /SharePointThoughts/_layouts/ReportServer/ReportExecution.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 354 Manage Cache Refresh Plans /SharePointThoughts/_layouts/ReportServer/CacheRefreshPlanList.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 355 View Report History /SharePointThoughts/_layouts/ReportServer/ReportHistory.aspx?list={ListId}&ID={ItemId} 0x0 0x40 FileType rdl 356 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsds 350 Edit Data Source Definition /SharePointThoughts/_layouts/ReportServer/SharedDataSource.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsds 351 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 350 Manage Clickthrough Reports /SharePointThoughts/_layouts/ReportServer/ModelClickThrough.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 352 Manage Model Item Security /SharePointThoughts/_layouts/ReportServer/ModelItemSecurity.aspx?list={ListId}&ID={ItemId} 0x0 0x2000000 FileType smdl 353 Regenerate Model /SharePointThoughts/_layouts/ReportServer/GenerateModel.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType smdl 354 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType smdl 351 Load in Report Builder /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderModelContext&list={ListId}&ID={ItemId} 0x0 0x2 FileType smdl 250 Edit in Report Builder /_layouts/images/ReportServer/EditReport.gif /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderReportContext&list={ListId}&ID={ItemId} 0x0 0x4 FileType rdl 250 Edit in Report Builder /SharePointThoughts/_layouts/ReportServer/RSAction.aspx?RSAction=ReportBuilderDatasetContext&list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 250 Manage Caching Options /SharePointThoughts/_layouts/ReportServer/DatasetCachingOptions.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 350 Manage Cache Refresh Plans /SharePointThoughts/_layouts/ReportServer/CacheRefreshPlanList.aspx?list={ListId}&ID={ItemId}&IsDataset=true 0x0 0x4 FileType rsd 351 Manage Data Sources /SharePointThoughts/_layouts/ReportServer/DataSourceList.aspx?list={ListId}&ID={ItemId} 0x0 0x20 FileType rsd 352 View Dependent Items /SharePointThoughts/_layouts/ReportServer/DependentItems.aspx?list={ListId}&ID={ItemId} 0x0 0x4 FileType rsd 353 Compliance Details javascript:commonShowModalDialog('{SiteUrl}/_layouts/itemexpiration.aspx?ID={ItemId}&List={ListId}', 'center:1;dialogHeight:500px;dialogWidth:500px;resizable:yes;status:no;location:no;menubar:no;help:no', function GotoPageAfterClose(pageid){if(pageid == 'hold') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/hold.aspx?ID={ItemId}&List={ListId}'); return false;} if(pageid == 'audit') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/Reporting.aspx?Category=Auditing&backtype=item&ID={ItemId}&List={ListId}'); return false;} if(pageid == 'config') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/expirationconfig.aspx?ID={ItemId}&List={ListId}'); return false;}}, null); return false; 0x0 0x1 ContentType 0x01 898 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XsnLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 FileType xsn 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.2 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.3 255 Edit in Browser /_layouts/images/icxddoc.gif /SharePointThoughts/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.4 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsx 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsm 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsb 255 View in Browser /SharePointThoughts/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType ods 255 |
|
|