Spring Cleaning Your Dev Box


After some time your dev box ends up looking like a well-used tool shed complete with unused tools and cobwebs in the corners.

While it’s quick and easy to get rid of half the icons on your desktop and delete droves of temporary working files – I always end up returning to a few well used scripts to get my much needed disk space back as well as a cleaner and faster box.

Often the trigger is exhausted disk space.

These are the scripts I always end up using.

Delete old site collections

If you are making site definitions (or web templates) you’ll likely end up with tons of small test site collections over time. I often use scripts to create them named after the current time.

To clean that all up I use the PS script (run in the SharePoint Administrative Console):

    get-spsite http://* -limit all |? { $_.Url -Match "http://.*/" -and $_.LastContentModifiedDate -gt [DateTime]::Today.AddMonths(-2)} | remove-spsite

In human terms: “Delete every site collection that is not a root site collection and that have not been modified within the last two months”. Phew.

Do NOT run this in production.

Set Simple SQL Recovery Mode

Next I ensure that all my local databases run in simple recovery mode, i.e. avoid huge transactions logs that need to truncated once in a while.

I nicked this script somewhere in google (likely here):

USE MASTER
declare
	@isql varchar(2000),
	@dbname varchar(64)
	
	declare c1 cursor for select name from master..sysdatabases where name not in ('master','model','msdb','tempdb')
	open c1
	fetch next from c1 into @dbname
	While @@fetch_status  -1
		begin
		select @isql = 'ALTER DATABASE [@dbname] SET AUTO_CLOSE OFF'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		select @isql = 'ALTER DATABASE [@dbname] SET RECOVERY SIMPLE'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		select @isql='USE [@dbname] checkpoint'
		select @isql = replace(@isql,'@dbname',@dbname)
		print @isql
		exec(@isql)
		
		fetch next from c1 into @dbname
		end
	close c1
	deallocate c1

Run it within the SQL Server Management Studio.

Note that it is likely that the script will report a few minor errors if some DBs are detached/offline. Never mind.

Shrink DBs

Finally save some much needed space by shrinking the DB files. After site collection deletions and recovery mode changes there are likely a lot of space to be freed within the DB files.

This script will try to shrink all the DB files (I think I got it from here):

DROP TABLE #CommandQueue

CREATE TABLE #CommandQueue
(
    ID INT IDENTITY ( 1, 1 )
    , SqlStatement VARCHAR(1000)
)

INSERT INTO    #CommandQueue
(
    SqlStatement
)
SELECT
    'USE [' + A.name + '] DBCC SHRINKFILE (N''' + B.name + ''' , 1)'
FROM
    sys.databases A
    INNER JOIN sys.master_files B
    ON A.database_id = B.database_id
WHERE
    A.name NOT IN ( 'master', 'model', 'msdb', 'tempdb' )

DECLARE @id INT

select * from #CommandQueue

SELECT @id = MIN(ID)
FROM #CommandQueue

WHILE @id IS NOT NULL
BEGIN
    DECLARE @sqlStatement VARCHAR(1000)
    
    SELECT
        @sqlStatement = SqlStatement
    FROM
        #CommandQueue
    WHERE
        ID = @id

    PRINT 'Executing ''' + @sqlStatement + '''...'

    EXEC (@sqlStatement)

    DELETE FROM #CommandQueue
    WHERE ID = @id

    SELECT @id = MIN(ID)
    FROM #CommandQueue
END

Again expect some errors, inspect and accept them ;-)

Expand the Disk?

If the three steps above didn’t free enough space for you, the solution often is to just expand the VHDs on your virtual machines.

It’s a fairly easy process in both VMWare and HyperV it only requires you to turn off the VM, remove any snapshots, and expand the disk using the wizard for it. This will only expand the VHD; your partitions will not grow, so you need to do that next.

You can use the disk management tool for it – however I find it cumbersome. Especially if it is the system disk you’re expanding it is awkward. I prefer to use GPartED, which is a very nice linux partition editor. It is a downloadable iso that is a breeze to boot into and expand the partition whether it is the system or not.

One note: In a typical Linux way you are asked all sorts of questions at boot; just hit return at every one of them. Who cares about the keyboard layout for a GUI program with big buttons anyway?

It looks something like this:

(Note: Before using this program make sure that you close down the VM nicely from the guest)

Easy.

Quick tip: Handy Scripts for Local Hyper-V Management


Here is a quick post with a small script that I find incredibly handy for managing my local Hyper-V machines (on windows 8).

It simply ensures what set of VMs are running at a given time – attach that to a shortcut on the desktop and it saves me 3 minutes every day; I find it useful.

Why? Quite often, I need to switch from one set of VMs to another for different tasks (VMWare term is “teams”) e.g. switching between SP2010 and SP2013 development. Sometimes just turn them off if I need the resources for something else.

Normally you just go into Hyper-V manager and start/stop the relevant VMs. Automating that was quite simple and painless – the download is here.

  1. I have one PowerShell script (SetRunningVMs.ps1) that handles the VM management and then a couple of batch files for executing that script with proper parameters. The script is:
    <#
    .SYNOPSIS
    This is a simple Powershell script that adjust what VMs are running on the local Hyper-V host.
    
    .DESCRIPTION
    This script will start/resume the requested VMs and suspend all other VMs to give you maximum power and make it easy to switch from one
    development task to another, i.e. switch teams.
    
    .EXAMPLE
    Make sure that only the dev1 and ad01 machines are running:
    ./SetRunningVMs.ps1 'dev1' 'ad01'
    
    Stop all VMs (no arguments)
    ./SetRunningVMs.ps1 
    
    .NOTES
    Requires admin rights to run. Start using admin shell or use one of the provided batch files.
    Pauses on error.
    
    .LINK
    
    http://soerennielsen.wordpress.com
    
    #>
    
    param( [Parameter(ValueFromRemainingArguments=$true)][string[]] $allowedVMs = @() )
    
    try{
        get-vm |? { $_.State -eq "Running" -and $allowedVMs -notcontains $_.Name } |% { Write "Saving $($_.Name)"; Save-VM $_.Name }
    
        get-vm |? { $_.State -ne "Running" -and $allowedVMs -contains $_.Name } |% { Write "Starting $($_.Name)"; Start-VM $_.Name }
    
        write "SetRunningVMs succesfully done"
    }
    catch{
        Write-Error "Oops, error:" $_
        pause
    }

    I assume that the PowerShell Hyper-V module is loaded; it has always been the case in my tests.

  2. I have a number of batch files for easily executing the script, one for turning off (suspend) all VMs, one for a SP2010 team and one for the SP2013 team. It’s a one-liner bat file that will work with both PowerShell 2 and 3, with or without UAC.

    To Start my SP2010 team (StartSP2010Team.bat):

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0SetRunningVMs.ps1 \”AD01\” \”Dev1\”‘ -verb RunAs}”

    (where you replace the bold VM names above with your own)

    To start my SP2013 team (StartSP2013Team.bat)

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0SetRunningVMs.ps1 \”AD02\” \”SP2013\”‘ -verb RunAs}”

    To stop all VMs

    powershell -noprofile -command “&{ start-process powershell -ArgumentList ‘-noprofile -file %~dp0\SetRunningVMs.ps1′ -verb RunAs}”

If you have UAC enabled (as I do) you will be prompted, otherwise it will just suspend/resume the relevant VMs.

It took about two hours to write the scripts, where the hardest part was getting the batch files properly in shape with escape characters and UAC.

You gotta love PowerShell ;-)

How to Setup Hyper-V Networking on Windows 8


It seems that the best way to setup networking in Hyper-V on a Windows 8 machine is quite far from obvious. I have spent some time getting this working as it should, so read on…

The Goal

Is quite simply that I want my VMs to just work seamless with my Host machine and whatever network connection I’m using and – in my case – a guest AD.

This used to be really simple with VMWare Workstation but after converting my machines to Hyper-V there is a catch or two.

Note that this applies to a mobile working scenario where I run everything on a laptop and it frequently changes whether I’m using a wired, wifi or mobile net.

The Environment

I do SharePoint development and this post is written in that context, however it should all be generally applicable to Hyper-V.

My local Hyper-V (SharePoint Dev) environment consists of two guests:

  • An AD server that should not communicate outside my box
  • A SharePoint server that need to communicate with my host, the guest AD and generally networking

In addition I need to connect with Remote Desktop to the guest machines with the host (the Hyper-V console is useless for all but boot and network configurations).

The Hyper-V Network Settings

The steps to configure the network on the host are:

  1. Create an external virtual switch for each of your external network adapters in the Hyper-V manager
  2. Create an internal switch for the connection between host and virtual machines (and in my environment between the AD and SharePoint server)
  3. A catch: In my case the mobile adapter was not selectable (not sure if that is always the case) when I create a virtual switch.

    In that case create an internal switch (name it “External” something as it will be configured for that)

    1. Go to your Network Connections, choose your mobile adapter, Sharing and choose to share the connection with the newly created virtual switch (see the picture below)

  4. Name them all appropriately otherwise you’ll regularly end up being confused ;-)

    After that your Hyper-V settings look something like this:

  5. Finally you need to pick some static IP addresses for your internal network as you’ll want the host to communicate with the guests and the guests to be able to talk to each other. There is no DHCP on the internal switch (would be a reasonable feature request for the next version of Hyper-V). I this case I picked 192.168.10.2 for my host:

  6. If you want to be able to refer to your guest machines by their names you need to add a couple of entries to your hosts host file ;-) Edit the file C:\Windows\System32\Drivers\etc\hosts and add a line for each guest

    I picked 192.168.10.10 for my AD guest and 192.168.10.20 for my SharePoint guest:

The Guest Configuration

First of all you need to connect the virtual switches appropriately to your guests in the Hyper-V Manager:

  • For the guests that only need to communicate internally connect only the internal switch
  • For the guests that need full internet access connect all the switches

Finally we need to configure the guests themselves. Connect to each one using the Hyper-V console:

  1. For the AD guest server (internal communication only) assign the ip address 192.168.10.10 (the one picked above) – there should only by one network adapter
    1. When you change the IP address for an AD server you also need to change the address appropriately in the DNS manager. Simply start the DNS manager and click through the nodes and change all IP addresses to the new address
    2. If you have a registration for other clients (other guest machines) update those records to the IP you chose for them
    3. Reboot the guest
  2. For the guests that need network access
    1. Assign the chosen IP to the internal network, in my case, 192.168.10.20
    2. Add two lines to the guest machines host file to make sure that the AD guest server can be found:

      “192.168.10.10 ad01″ and “192.168.10.10 ad01.domain.local” where the second is the FQDN of the AD server

    3. You should now have a number of network adapters that are connected to the host’s physical adapters and it will automatically figure out which ones are connected and use whichever is appropriate. I recommend that you named them appropriately in the guest.
    4. Catch (do not skip this): I did however find that it was unable to correctly figure out whether the mobile adapter was connected or not (likely because I created it as an internal switch). I fixed that by prioritizing the mobile network connection last so it will only use the mobile if all others fail. You just need to set the “network metric” to something high (high is lowest priority), follow the process in the picture below

That’s it for the guests!

RDP Access

Finally you’ll want to access the guests through RDP so stuff like copy/paste and fullscreen works. You can of course use whatever RDP manager you prefer, here I’ve just used the standard one.

Make a connection for each Guest access and save it somewhere (Desktop?).

Run the command “mstsc” and setup the options you like and save the Connection. In particular enable “Clipboard” and “Drives” in the “Local Resources” tab. That will enable you to copy/paste both text and files between the guest and host. Will also grant access to the host’s drives.

In my case:

Going for the Advanced Mode?

While the settings above work fine; there is always room for improvement.

I think it would be better to install a third machine as a firewall/router so the firewall handled all external connections and boxed in the essentially rogue guest machines. They really only need to communicate externally on port 80/443.

I will give m0n0all a go soon :-)

Troubleshooting

Once in a while something goes wrong. Sadly.

My normal way to troubleshoot is simple to do a “tracert http://www.google.dk”; and to notice what network adapter is being used for the communication.

Sometimes it picks the wrong nic (one without Internet access) for whatever reason (you did remember to set the metric above, right? This is what it does). “Ipconfig /flushdns” sometime solves the problem otherwise disable the offending nic in the guest (temporarily).

Supercharge your (Resource) Efficiency with Macros


This is part 4 of 4 in a series on how to improve the way we usually work with resource (resx) files.

I generally like to – and do – use resource files for all string constants that are shown to end-users, however I do feel that it is needlessly cumbersome, therefore these posts:

  1. A Good Way to Handle Multi Language Resource Files
  2. Verify that your Resource Labels Exists
  3. Find/Remove Obsolete Resource Labels
  4. Supercharge your (Resource) Efficiency with Macros (this one)

Generally these issues are generic to .NET and not specific to SharePoint, though that is where I’m spending my time writing this.

What is it again?

This is a macro to increase developer productivity. It is a topic that lies very close to my hearth and a healthy fraction of my posts are about automation and productivity. Every developer should really know the macro features especially the record/play shortcuts.

Working with resources (in SharePoint) is actually quite tedious – we write “$Resources:” a thousand times and occasionally cannot be bored and skip the chore.

This is simple a Visual Studio macro to improve that workflow, usage is:

1. You highlight a string

2. Press a shortcut (of your choice)

3. Write a name for the resource key to create(optionally use an existing if one exists with same value)

4. And you’re done.

It will then add the resource key to your existing resx file, it will type in “$Resources:….” as needed. If it’s an aspx/ascx file it will also throw in some “<%=” and “%>” tags.

(It works very well for xml files too.)

The Gory Detail

This is a VB macro script that took an inordinate amount of time to write mainly because the Visual Studio Macro object model (DTE) is one of the most hideous, awkward, APIs I’ve ever worked with. If there is one place the VS team could improve it would be here – the macro IDE is also tedious to work with.

I’m very certain that there are ways to make the code perform better (speed is fine) and look better (is it important?) – let me know your nuggets in the comments it’s always good to learn something new.

What you need to know is:

  1. It looks for a resx file with the same name as the target name of your project, i.e. the dll/wsp name
    • It only works on the culture independent resx file
    • It even adds a comment in the resource file as to where a key was first used J
  2. It works only for text editor windows
    • I have not found a way to make the selection work in the designer windows, specifically the feature designer would have been nice. This is annoying.

      The workaround is to simply choose to open the .feature file in the “XML (text) editor” (choose “Open with” in the file open dialog)

  3. You may need to customize the replacement pattern for cs and as?x files as it calls a simple utility method “ResourceLookup.SPGetLocalizedString” to translate the “$Resources:…” key (see code below)
  4. It handles quotes in/around the selection

At the moment it is only tested with VS2010 – I’m certain that changes need to be made for VS2013. In due time…

The resource lookup method I’m using is:

        public static string SPGetLocalizedString(string key)
        {
            if (!key.StartsWith("$Resources:"))
            {
                return key;
            }
            var split = key.TrimEnd(';').Remove(0, "$Resources:".Length).Split(',');

            if (split.Length != 2 || string.IsNullOrEmpty(split[1]))
            {
                return key;
            }

            return SPUtility.GetLocalizedString(key, split[0], (uint)System.Globalization.CultureInfo.CurrentUICulture.LCID);
        }

Download and Installation

It is simple:

  1. Download the Macro project here
  2. Dump it somewhere on your disk – the usual location is in “Documents\Visual Studio 2010\Projects\VSMacros80″
  3. Choose “Tools / Macros / Load Macro Project” and pick the DGMacros.vsmacros file
  4. Bind a keyboard shortcut for the text editor to the macro. Just write “dgm” in the search box and pick the “ReplaceStringWithResource” macro

  5. Have a try and perhaps a look at point 3 of the gory details above ;-)

Find/Remove Obsolete Resource Labels


This is part 3 of 4 in a series on how to improve the way we usually work with resource (resx) files. At least the way my team and I work with them.

I generally like to – and do – use resource files for all string constants that are shown to end-users, however I do feel that it is needlessly cumbersome, therefore these posts:

  1. A Good Way to Handle Multi Language Resource Files
  2. Verify that your Resource Labels Exists
  3. Find Obsolete Resource Labels (this one)
  4. Supercharge your (Resource) Efficiency with Macros

Generally these issues are generic to .NET and not specific to SharePoint, though that is where I’m spending my time writing this.

So – Near the End of the Project – are those Resource Entries Still in Use?

The issue at hand is that you have hundreds of source files of various flavors and they are sprinkled with references to a number of resource files. When code is refactored or just deleted what happens to old resource labels? Likely nothing at all.

Are you happy with a ton of useless resource entries no longer in active use? What if you had to translate it to a couple of languages?

Quite obviously this is no biggie code/quality wise, but still…

The answer is that you run the PowerShell script below, that’ll check – and optionally fix – it ;-)

The Script

I made a small script to check and remove the excess resource entries to slim down those resource files a bit.

The script will, given a starting location (i.e. the root folder for your solution)

  1. Go through every code file (to be safe every file, except a list of binary extensions) and look for resource labels of the form “$Resources:filename,label_key
  2. Search recursively for resx files
  3. For every one of those resx files it will look through the resource labels in use and flag those that it cannot find
  4. (Optionally) Do a “safemode” check where every file is searched for the resource label, i.e. necessary if you are using multiple/other resource lookup methods then the $Resource moniker
  5. (Optionally) If you choose you may remove them automatically but do make a dry run first to sanity check that you got the paths right and that you have all the source files to be searched

Usage:

    PS> & VerifyResxLabels.ps1 “path to solution dir” [-remove] [-safemode]

(Tip: Download the script to somewhere, write an ampersand (&) and then drag the ps1 file into the PowerShell window and then drag the solution folder to the window.)

You’ll definitely want to pipe the output to a file.

Limitations

There are obviously some limitations

  • It will not: Check out the resx files from source control (but it will show the file error in the output)
  • It will not: Respect commented out code – it’s simple pattern matching so commented out code will be treated as actual code (hardly an issue)
  • Safemode is very slow of necessity and will likely find false positives, i.e. it will play it safe and keep entries that exists in some files, even though the same label may be used in a completely different context
    • It’s an (O(n*m) algorithm, with number of files and number of labels) – My test with 1000 unique labels, 28 resx files and 2400 files it takes a night

Download the script here

Verify that your Resource Labels Exists


This is part 2 of 4 in a series on how to improve the way we usually work with resource (resx) files. At least the way my team and I work with them.

I generally like to – and do – use resource files for all string constants that are shown to end-users, however I do feel that it is needlessly cumbersome, therefore these posts:

  1. A Good Way to Handle Multi Language Resource Files
  2. Verify that your Resource Labels Exists (this one)
  3. Find Obsolete Resource Labels
  4. Supercharge your Resource Efficiency with Macros

Generally these issues are generic to .NET and not specific to SharePoint, though that is where I’m spending my time writing this.

So, are you sure that your Resource Labels Exists?

The issue at hand is that you have hundreds of source files of various flavors and they are springled with references to a number of resource files. Usually only one for each project/wsp though.

So how can you be sure that you don’t use one in your code that isn’t defined in your resource file?

As missing resource labels are just output verbose to the end user/application this can be a major issue.

The answer is that you run the PowerShell script below, that’ll check it ;-)

The Script

I made a small script to check for resource labels after a major code rewrite that had me change literally hundreds of labels.

The script will, given a starting location (i.e. the root folder for your solution)

  1. Search recursively for resx files and store their locations
  2. Go through every code file (.xml, .cs, .vb, .as*x, .webpart, .dwp, .feature) and look for resource labels of the form “$Resources:filename,label_key
  3. For every one of those resource keys it’ll open the corresponding resx file and check that the key is present and write a warning to the console if not

Obviously this takes a minute or two – in my current project with 8500 files (including everything) it takes about 1 minute to complete (a VM on a power laptop) which is completely acceptable as you don’t really need to run it that often.

Enterprising people may want to add it to the buildserver’s list of tests. I haven’t found the need or the time yet ;-)

Usage:

    PS> & VerifyResourceLabelsExists.ps1 “path to solution dir

(Tip: Download the script to somewhere, write an ampersand (&) and then drag the ps1 file into the PowerShell window and then drag the solution folder to the window.)

Sample output:

Searching for resx files
Searching for labels
Parsing resx files
Checking labels
Warning: Could not find $Resources:Delegate.XXX.XXX,ContentType_XXX_Description in file C:\Dev\TFS\xxxx\Elements.xml
Warning: Could not find $Resources:Delegate.XXX.XXX,ListDefinition_XXX_Heading in file C:\Dev\TFS\xxxx\Schema.xml
...
 

You’ll likely want to pipe the results to a file and then run through your source files to add the missing labels (see part 4, when I finish it).

What it does not do

There are obviously some limitations. It will not

  • Add the missing labels for you
  • It simply looks at files. If you have some files that are excluded from your project files they will be counted in regardless
  • It simply does pattern matching – code commented out is still included by the script
  • It always works of the default non-language specific resx file – the task of ensuring that all labels are defined in all languages is a fairly simple xml comparison for which tools exists
  • Handle default resource files, i.e. the case where you define a default resource file in your feature.xml files and then use the “$Resources:label_key” shorthand with no file name

Download the script here

A Good Way to Handle Multi Language Resource Files


If you are working with SharePoint you should also be using ressource (resx) files in your projects.

The problem is that SharePoint is quite annoying in the way it handles fallback to the default language resx when there is no culture specific version.

For instance in a Danish site it will look for MySolution.da-DK.resx and fallback to MySolution.resx if it isn’t o found.

Nice.

The Problem

However SharePoint will spam your ULS log with messages like:

04/20/2012 13:56:37.25     w3wp.exe (0x3758)     0x344C    SharePoint Foundation     General     b9y9    High     Failed to read resource file "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources\MySolution.da-DK.resx" from feature id "(null)".    5b6991c9-5b39-4c95-b895-ed282bc00034 
04/20/2012 13:56:37.25     w3wp.exe (0x3758)     0x344C    SharePoint Foundation     General     8e26    Medium     Failed to open the language resource keyfile MySolution.    5b6991c9-5b39-4c95-b895-ed282bc00034 
04/20/2012 13:56:37.25     w3wp.exe (0x3758)     0x2C94    SharePoint Foundation     General     b9y3    High     Failed to open the file 'C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Resources\MySolution.da-DK.resx'.    492a45e8-e416-4321-a83a-12f56c0341c1 
04/20/2012 13:56:37.25     w3wp.exe (0x3758)     0x2C94    SharePoint Foundation     General     b9y4    High     #20015: "" kan ikke åbnes: Filen eller mappen findes ikke.    492a45e8-e416-4321-a83a-12f56c0341c1 
04/20/2012 13:56:37.25     w3wp.exe (0x3758)     0x2C94    SharePoint Foundation     General     b9y4    High     (#2: "" kan ikke åbnes: Filen eller mappen findes ikke.)    492a45e8-e416-4321-a83a-12f56c0341c1 

And to make matters worse they are actually marked with “high” importance. In my mind this is a very normal way to code (for non-SharePoint projects) and should certainly not be marked with high importance. For now I am forced to look for the “unexpected” importance instead when troubleshooting.

The Simple Fix

There are a number of ways to correct this, I chose:

  1. Delete the duplicate localized version (MySolution.da-DK.resx) from source control
  2. Add a prebuild event to copy MySolution.resx to MySolution.da-DK.resx
    1. Write something like ‘copy /Y “$(ProjectDir)Resources\$(TargetName).resx” “$(ProjectDir)Resources\$(TargetName).da-DK.resx” ‘ (change to suit your needs and ensure quotes are not html mangled)
  3. Make sure to include MySolution.da-DK.resx in the project and mark it with “Build Action: Content”, “Copy to Output Directory: Do not copy”.
  4. Choose to exclude MySolution.da-DK.resx from Source Control in Visual Studio (File / Source Control / Exclude …)

    (otherwise Visual Studio will likely face write protected files)

All in all it should look somewhat like this:

Resx handling in the project

Other Ways

Other possible solutions would be to symbolic soft/hard link to the file (mklink.exe), however care should be taken as TFS really don’t like symbolic links.

The trick with exclusion from source control would likely work too, however a file copy just seemed like a simpler solution…

Another creative way would be to mess around with the packaging options it’s likely possible.

How to Make List Items Visible to Anonymous Users (in Search)


I had a funny little issue with showing list items from a custom list (with a custom view form) to anonymous users on a publishing site.

My good colleague Bernd Rickenberg insisted that I blogged the resolution since he had found quite a few post detailing the problem but no viable solutions ;-)

The Issue

You want to show a custom list to anonymous users. In our setting it was through search, your use case is likely different, but the issue remains the same with or without search.

Quite simply forms (List forms) are generally not accessible to anonymous users when you have the lockdown feature enabled (ViewFormPagesLockdown). It is a critical feature to have enabled otherwise you expose way too much information to SharePoint savvy users. Many of the solutions to this issue suggest turning it off.

It is fairly simple to test if you have this problem. Start Firefox, assuming that you have not enabled the NTLM auto login setting, and hit the …/DispForm.aspx page for a specific item. If you receive the login prompt as anonymous in Firefox and sail through when logged in this blog is for you.

If the ordinary publishing pages are also not viewable then this blog is not for you.

Note: Never use IE to test for anonymous access or not, I can’t count the number of times it has tricked consultants into thinking it works because they are tricked by the auto login feature while on the corporate network.

The Resolution

Is fairly simple.

The basics for search is that the list must be made searchable (it is by default) in the list settings, anonymous users must have access rights to the site and the lockdown feature should(!) be enabled.

What the lockdown feature does is that it changes the anonymous permission mask at the root site (which is inherited by all by default). The mask is basically the permission level assigned to all anonymous users and is similar to the normal permission sets – but is not editable in the UI.

The “View Application Pages” permission level is removed, see the image below on where to find it (for non-anonymous users):

Permission level settings page

Permission level settings page – not available for anonymous users

The best option, security wise, is to break the permission inheritance for your particular list and then add the “View Application Pages” permission to the anonymous users. Do not do that at the web level as you do not want to expose e.g. All site content etc.)

The Script

You need to run the following the PowerShell commands on one of your servers (replace url and list name):

$web = get-spweb "http://yoursiteurl/subweb/subsubweb" 
$list = $web.Lists["ListName"]
$list.BreakRoleInheritance($true)
$list.AnonymousPermMask = $list.AnonymousPermMask -bor ([int][Microsoft.SharePoint.SPBasePermissions]::ViewFormPages) #binary or adding the permissions
$list.Update()
 

(Note: Do be careful if copying directly from this page to PowerShell – you need to re-type the quotes as WordPress mangles them)

Script to Import/Export Metadata Termstore


Recently I’ve been using the Managed Metadata Store in SharePoint 2010 and been amazed by the lack of proper import/export functionality.

It feels like a blast from the past to be able to only import a CSV file… CSV?!? What happened to proper XML? What happened to Export? What happened to being able to transfer (meta)data between farms (like test and production) since the builtin Import insists on creating new TermSets and not update existing ones (and yes your managed metadata linked site columns do in fact store a strong reference, not just a name, so you’ll loose the link).

I couldn’t find any existing Powershell commandlets to the rescue either.

I couldn’t readily bing ;-) any usable scripts for this.

What I did

So I built a powershell script to take a CSV file and import it into the Term Store and merge it with any existing term store already there.

CSV?!?? Yeah…

Point is then you can still use the CSV file you likely already hold. You can use the TermSetImporter to export CSV files from your existing environment.

If you are starting Greenfield, then I recommend to use excel with some macros to create the Term Sets (then your users can create them instead of you) or you might just let your users loose in the term store manager.

How to use

First download my small script and the sample excel and CSV files.

Second, fire up powershell (on a SharePoint server), write:

. ./MergeTermSets.ps1 csvfile groupname urlForASharePointSite

Do remember the “dot space” at the start of the line. The second “./” is just the path for the ps1 file in this case.

The urlForASharePointSite is optional and will default to http://localhost:2010 which likely corresponds to a valid SharePoint Central Admin site on 50% of all SharePoint installations. Watch the output log. If something goes wrong it’s likely that you should have a look in your CSV file for errors and/or whether or not the managed metadata store is connected properly.

Notes:

  • I’ve tried to do some tricks to handle encoding properly and I also trim spaces which really causes the term store to stumble (it will trim spaces and every subsequent comparison the script might do will fail).
  • Note that LCID and the parent Terms need to be set on every line in the excel sheet. Don’t blame me I didn’t make that part ;-)
  • Terms are only added not updated, i.e. I don’t try to keep stuff like descriptions in sync
  • No fancy stuff, no merging, no deletions, deprecation etc.

Hope it’s useful for you too.

SharePoint Advanced Large Scale Deployment Scripting – “Dev and QA gold-plating” (part 3 of 3)


I have been battling deployments for a while and finally decided to do something about it.

;-)

The challenge is to handle a dozen WSP packages on farms that host 20-50 web applications (or host header named site collections) to complete the deployments in a timely manner, ensure that the required features are uniformly activated every time while minimizing the human error element of the poor guy deploying through the night.

The deployment scripts require PowerShell v2 and are equally applicable to both SharePoint 2007 and 2010 – the need is roughly the same and the APIs are also largely unchanged. Some minor differences in service names are covered by the code.

To keep this post reasonable in length I’ve split the subject into three parts:

Part 1 is the main (powershell) deployment scripts primarily targeted at your test/QA/production deployments

Part 2 is the scripts and configuration for automatic large scale feature activations

Part 3 (this part) is about gold-plating the dev/test/QA deployment scenario where convenience to developers is prioritized while maintaining strict change control and records

Note: This took a long time to write and it will likely take you, dear reader, at least a few hours to implement in your environment.

If you have not done so already read the two other parts first.

The Challenge

When you have a number of developers working on the same service line you need to be able to keep strict control of your QA and test environment.
So either you have one guy as the gatekeeper or you automate as much as possible. I’m the last type of guy so I’ve developed a “one-click” deployment methodology where the focus is
1. Simple and consistent deployment
2. Easy collection of solutions for next production deployment – you should deploy the exact code that you tested not a “fresh” build(!)

The Solution

Our build server is set up to produce date labelled zip files with the wsp and manual installer (exe) within folder of the same name.
I’m sure yours are different therefore the scripts work with a solution drop directory that accepts both zip files (that includes a wsp file) and also plain wsp files.
The folder structure is up to you I’ll just search recursively for zip and wsp.

The script files are:

03 DeployAndStoreDropDir.bat: The starting batch file that will execute the deployment process as a specific install user. That way the developers can login with their personalized service accounts and use a specialized one for deployment purposes. You need to change the user name in this batch file. The first time you run this you need to enter the password for your install account subsequent runs will remember it  (“runas /savecred”).

03b DeployAndStoreDropDirAux.bat: The batch file doing half the work. It’ll archive old log files in “.\ArchivedDeploymentLogFiles” (created if not present) and it execute “QADeploymentProcess.ps1″ that is doing the hard work. At the end it’ll look for error log and write an alert that you should look for it. Saves a lot of time – I don’t go looking in log files if I don’t get that message.

SharePointLib\QADeploymentProcess.ps1: The script that is handling the unzipping and storage of the zip/wsp files and executing both the deployment and feature activation scripts. The goal is to have a simple drop dir where for WSP/zips and a single storage location, “SolutionsDeployed”, for the currently deployed code. The “SolutionsDeployed” folder will be updated at every deployment, so that there is only the latest version of each wsp deployed. You do not need to drop all wsps in the drop dir every time; it does not just delete the SolutionsDeployed folder at every deployment.

This is how the files are moved around for a couple of WSPs and a zip file:

In short:

  1. If you want to start it with a specific install user, just execute “03 DeployAndStoreDropDir.bat”
  2. If you want to start it in your own name, execute “03b DeployAndStoreDropDirAux.bat” and perhaps delete the other bat file.
  3. If you want to modify how it works go to the “QADeploymentProcess.ps1″ file.
  4. If you want to work with zip files they can have the name and internal folder structure that you like. The one important thing is that they should only contain one WSP file. It is pretty smart; at the next deployment your zip file may be named differently (e.g. with a date/time in the name) and it will still remove the old version from “SolutionsDeployed” and store your new version with the new folder/zip name.
  5. At the end of your build iteration SolutionsDeployed will contain the latest version of your deployed code (provided that you emptied it at the last production deployment)

Closing Notes

It is not a big challenge to connect the remaining dots and have your build server do the deployment at certain build types and have a “zero-click” deployment, however I opted to not do it. It should be a conscious decision to deploy to your test and QA environments, not something equivalent to a daily checkin. Your milage may wary.

I would generally provide these scripts to everyone in the team and encourage them to use them on their own dev box once in a while – it always pays to have your dev environment resemble the actual production environment this makes it feasible to keep the code (almost) in sync on all dev environments.

The challenge may be the complexity of the scripts and the effort to understand them – you shouldn’t rely too much on stuff you don’t understand ;-)

Feel free to adjust the script a bit (likely QADeploymentProcess.ps1) to suit your environment.

If you make something brilliant then let me know so I can include it in my “official” version. Please also leave credits in there so it’ll be possible for your successors to find the source and documentation.

Download

Grab the files here – part 1, 2 and 3 are all in there. I’ll update them a bit if I find any errors or make improvements.

Note: Updated Aug 29 2011, minor stuff.

Don’t forget to change the user name in “03 DeployAndStoreDropDir.bat” to your “install” account.

Follow

Get every new post delivered to your Inbox.