The Musings and Findings of Software Consultant David Klein (Sydney, Australia)
Saturday, 19 July 2008
You get the error "[Script Name].ps1 cannot be loaded because the execution of scripts is disabled on this system" when running Powershell scripts
File D:\Sc\Global\DDK.Solution\dev\DDK.ProjectName\deploy.ps1 cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.
You get this error because the default setting for Powershell is "Restricted" (aka locked down Alcatraz mode). In this mode, it does not load configuration files or run scripts.
To resolve this issue, you can run Powershell (powershell is typically in C:\WINNT\system32\WindowsPowerShell\v1.0\powershell.exe if it is not already in your path) and change the execution policy. For example, you could run the command "Set-ExecutionPolicy Unrestricted" if you want to allow unsigned scripts to run.
Once you have set your security policy appropriately, you can execute your powershell scripts without this error. See http://technet.microsoft.com/en-us/library/bb978644(TechNet.10).aspx for more information.
Deleting Folders in MOSS via Web Services and CAML
The typical format for the batch element Xml fragment is:
<Batch OnError='Return'>
<Method ID='1' Cmd='Delete'>
<Field Name='ID'>81</Field>
<Field Name='FileRef'>http://dev-moss/sites/home/PropertySharePoint/DocumentLibrary/300</Field>
</Method>
</Batch>
Your delete is successful if the return value is zero. You can test this out in the U2U CAML query builder from http://www.u2u.info/Blogs/Patrick/Lists/Posts/Post.aspx?ID=1315
This batchElement information can be passed into the sharepoint list web service as demonstrated in the method snippet below:
/// <summary> /// Delete folders as per http://msdn2.microsoft.com/en-us/library/ms429658.aspx for LPP-205 /// </summary> /// <param name="listName"></param> /// <param name="folderName"></param> /// <returns></returns>public XmlNode DeleteFolder(string listName, string folderName)
{ /*Use the CreateElement method of the document object to create elements for the parameters that use XML.*/ System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument(); XmlElement query = xmlDoc.CreateElement("Query"); XmlElement viewFields = xmlDoc.CreateElement("ViewFields"); XmlElement queryOptions = xmlDoc.CreateElement("QueryOptions");string rowLimit = int.MaxValue.ToString();
/*To specify values for the parameter elements (optional), assign CAML fragments to the InnerXml property of each element.*/ System.Text.StringBuilder sb= new System.Text.StringBuilder(); sb.Append("<Where><Eq><FieldRef Name=\"Title\" />");sb.Append(string.Format("<Value Type=\"Text\">{0}</Value></Eq></Where>", folderName));
viewFields.InnerXml = "<FieldRef Name=\"ID\" /><FieldRef Name=\"Title\" />";query.InnerXml = sb.ToString();
queryOptions.InnerXml = "";System.Xml.XmlNode nodeListItems = _listWebService.GetListItems(listName, string.Empty, query, viewFields, rowLimit, queryOptions, null);
string folderId = string.Empty;
string fileRef = string.Empty;
XmlDocument doc = new XmlDocument();doc.LoadXml(nodeListItems.InnerXml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);nsmgr.AddNamespace("z", "#RowsetSchema");
nsmgr.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
XmlNodeList xmlNodeList = doc.SelectNodes("/rs:data/z:row", nsmgr);foreach (XmlNode node in xmlNodeList)
{ folderId = node.Attributes["ows_ID"].Value; //fileRef = node.Attributes["ows_EncodedAbsUrl"].Value;fileRef = node.Attributes["ows_FileRef"].Value.Substring(node.Attributes["ows_FileRef"].Value.IndexOf("#") + 1);
break;}
System.Xml.XmlNode result = null; //Will be populated response from update batch.
if (folderId != string.Empty)
{ System.IO.StringWriter sw = new System.IO.StringWriter(); System.Xml.XmlTextWriter xw = new System.Xml.XmlTextWriter(sw);xw.WriteStartDocument();
// build batch node xw.WriteStartElement("Batch");xw.WriteAttributeString("OnError", "Return");
// Build method node xw.WriteStartElement("Method"); // Set transaction ID - doesn't really matter what the number isxw.WriteAttributeString("ID", System.Guid.NewGuid().ToString("n"));
xw.WriteAttributeString("Cmd", "Delete");
// Build field ID xw.WriteStartElement("Field");xw.WriteAttributeString("Name", "ID");
xw.WriteString(folderId);
xw.WriteEndElement(); // Field end // Build FileRef xw.WriteStartElement("Field");xw.WriteAttributeString("Name", "FileRef");
xw.WriteString(fileRef);
xw.WriteEndElement(); // Field end xw.WriteEndElement(); // Method end xw.WriteEndElement(); // Batch endxw.WriteEndDocument();
System.Xml.XmlDocument batchElement = new System.Xml.XmlDocument();batchElement.LoadXml(sw.GetStringBuilder().ToString());
//Setup web service // send update request to sharepoint to create the document folderresult = _listWebService.UpdateListItems(listName, batchElement);
}
return result;}
Tuesday, 8 July 2008
TortoiseSVN 1.5 and svnmerge Issue - "svn: This client is too old to work with working copy '.'; please get a newer Subversion client"
WARNING: TortoiseSVN 1.5 does silent upgrades (aka the touch of death) on your SVN working copies that renders it unusable with older SVN clients. This affects clients such as the 1.4 based version of svnmerge (the current version as I write this).
Before the most recent 1.5 upgrade for TortoiseSVN, the last major version was made over 2 years ago. So you could imagine that I was quite keen to upgrade to latest version when my TortoiseSVN notified me that I should upgrade to version 1.5.
I've generally had a good experience with TortoiseSVN thus far so I bit the bullet and downloaded the latest and greatest version of this handy tool. I only uncovered the implcations of this upgrade when all my svnmerge scripts started to fail (we use the svnmerge utility via a batch file to deploy our changes to trunk and onto our build server). Then things hit the proverbial fan. I started to get the following errors for all svnmerge operations (including simple status calls) :
"svn: This client is too old to work with working copy '.'; please get a newer Subversion client"
I thought it was unusual that:
- TortoiseSVN installer would affect svnmerge at all (I assumed some shared DLLs had been updated).
- (on a more minor note) That it would start telling me that I had an old version of the client tool when I had the very latest versions of TortoiseSVN and svnmerge (http://www.subversionary.org/binaries/installer-for-svnmerge). I would hope that a tool as popular as svnmerge would be updated within days of a new client version being released.
I thought the rollback process would be as simple as uninstalling 1.5 of TortoiseSVN - but I uninstalled and changed back to 1.4.8 - and got the same error! Even the 1.4 versions of svn started to get the same error.
It turns out that once you start working with the new version of the tool, the SVN metadata is silently upgraded to the latest version. Unfortunately, if you want to keep using svnmerge, the fix for this issue (until a new version of svnmerge comes out) is to:
- Roll back to a 1.4 version
- Essentially throw away your working copy
- Do a fresh checkout.
This will get you back to the place you started. This could take a while - especially if you're in Australia and the subversion server is in Atlanta! Phew!
The TortoiseSVN 1.5 touch of death at work (it is not backwards compatible with 1.4 clients):
Wednesday, 25 June 2008
How to change your LiveID email address to a new email address
- Going to https://account.live.com/
- Choosing your account (if you have several)
- Clicking on the "Change Email" tab
All your contacts will be automatically transferred to the new account - and you don't even need to notify your contacts of the change.
Friday, 20 June 2008
Performance Profiling in Firefox 3 and the YSlow Addin for FireBug
Tuesday, 17 June 2008
Using the power of PowerShell to Configure your Web.Config for Different Environments,Customize the Output of SQLMetal and Bulk Update Word Documents
With this in mind, it is extremely handy as a tool for ANYTHING XML or done previously in batch files:
- Modifying your web.config as part of your build process during deploy. In a previous post, Scott Guthrie has recommended using multiple config files, one for each environment (See http://weblogs.asp.net/scottgu/archive/2007/09/21/tip-trick-automating-dev-qa-staging-and-production-web-config-settings-with-vs-2005.aspx). The problem with this is you have complete duplication of settings files. This means it is more likely you will forget to update a setting for all different environments. Using one master config file that is configured for each environment by powershell is much better. Powershell can also do all your zipping, and FTPing to staging servers.
- Deployment and customization of Reporting Services Reports. RDL is a standard XML language can be customized if you don't like the output of the Visual Studio RDL editor/designer.
- Updating Word and Excel 2007 Documents automatically. The docx format is now all XML - so powershell can perform bulk updates to Word documents for you without the need to use Word automation or a separate executable.
- Updating LINQ DBML files to your liking. I will detail an example of this below.
This batch file and powershell script does the following to fix up what the SQLMetal dbml generator doesn't do:
- removes tables that are not needed in the DBML
- renames associations so they are more meaningful (e.g. if you have multiple relationships between 2 tables, they will get names such as Lookup1, Lookup2, so your LINQ code using these relationships won't make much sense.)
The Batch File:
sqlmetal /conn:"data source=myServerName\dev;initial catalog=MyDataBaseName;trusted_connection=false;Persist Security Info=True;User ID=UserName;Password=Password;" /dbml:PropertyPipelineDb.dbml /context:InvestmentManagementDataContext /namespace:LendLease.InvestmentManagement.Domain.Entity /pluralize /entitybase:"LendLease.Framework.Domain.Entity.MutableEntity" /views
powershell -command "$temp = .\CleanDbml.ps1 -dbml '.\PropertyPipelineDb.dbml'; $temp Out-File '.\PropertyPipelineDb.dbml' -Encoding Unicode"
sqlmetal /code:PropertyPipelineDb.designer.cs PropertyPipelineDb.dbml
pause
The PowerShell Script (CleanDBML.ps1)
Param
(
$DBML # File Path to DBML file
)
$removeTables = ("dbo.vRolePermission", ` "dbo.vOpportunityFlattenedFundInterests", ` "dbo.vOpportunityDetailsWithFlatFundInterests", ` "dbo.vAssetAddress", ` "dbo.vContactOpportunities", ` "dbo.vContactOpportunitiesWithFlatFundInterests", ` "dbo.vLookupHierarchy", ` "dbo.CachedUser", ` "dbo.CachedUserExtension", ` "dbo.OpportunityImport" `);
$renameTables = @{ "dbo.vOpportunitySearch" = @{ Type = "vOpportunitySearch" ; Member = "vOpportunitySearches"}; `"Code.NotificationType" = @{ Type = "NotificationType" ; Member = "NotificationTypes"}; `
"dbo.vPropertyPipelineFund" = @{ Type = "Fund" ; Member = "Funds"} `
};
$renameAssosciations = @{ "FK_OpportunityRelationship_Opportunity1" = @{ FKMember = "Opportunity1"; PluralMember = "OpportunityRelationship1s"}; `"FK_OpportunityRelationship_Opportunity2" = @{ FKMember = "Opportunity2"; PluralMember = "OpportunityRelationship2s"}; `
"FK_CompanyCompanyType_Company" = @{ FKMember = "Company"; PluralMember = "CompanyTypes"}; `
"FK_NotificationType_NotificationType" = @{ FKMember = "ParentNotificationType"; PluralMember = "ChildNotificationTypes"} `
};
$exists = Test-Path ($DBML);
if (! $exists){$DBML = Join-Path -path $pwd -childpath $DBML;
}
$exists = Test-Path ($DBML);
if( $exists ){$dbmlFileInfo = Get-Item -path $DBML;
[System.Xml.XmlReader]$local:reader = [System.Xml.XmlReader]::Create($dbmlFileInfo);
[System.Xml.XmlDocument]$local:doc = new-object System.Xml.XmlDocument;
$doc.set_PreserveWhitespace($true);$doc.Load($reader);
$reader.Close();
[System.Xml.XmlElement]$local:root = $doc.get_DocumentElement();
# Remove nodes that don't belong
$removedTypeMap = @{};$tableNodesRemoved = $doc.Database.Table `
ForEach-Object { $_; } ` Where-Object { $removeTables -contains $_.Name } ` ForEach-Object { $removedTypeMap.Add($_.Type.Name, $_.Name); $_ = $doc.Database.RemoveChild($_); $_; };# Remove any assosciations on other tables which reference a removed type
$assosciationNodesWithTypesRemoved = $doc.Database.Table `
Where-Object { $_.Type.Association -ne $null } ` ForEach-Object { $_.Type.Association; } ` Where-Object { $removedTypeMap[$_.Type] -ne $null } ` ForEach-Object { $_ = $_.get_ParentNode().RemoveChild($_); $_; };# Rename nodes for tables with their new aliases
$tableNodesToRename = $doc.Database.Table `
ForEach-Object { $_; } ` Where-Object { $renameTables[$_.Name] -ne $null }; $renamedTypeMap = @{}; $tableNodesToRename ForEach-Object { $newName = $renameTables[$_.Name].Type; $renamedTypeMap.Add($_.Type.Name, $newName); $_.Type.Name = $newName; }; $renamedMemberMap = @{}; $tableNodesToRename ForEach-Object { $newName = $renameTables[$_.Name].Member; $renamedMemberMap.Add($_.Member, $newName); $_.Member = $newName; };# Fix up any assosciations on other tables which reference a renamed type
$assosciationNodesWithTypesRenamed = $doc.Database.Table `
Where-Object { $_.Type.Association -ne $null } ` ForEach-Object { $_.Type.Association; } ` Where-Object { $renamedTypeMap[$_.Type] -ne $null} ` ForEach-Object { $_.Type = $renamedTypeMap[$_.Type]; $_; }; # Fix up member names for any assosciations on other tables which are Foreign Key assosciations and reference a renamed type$assosciationNodesWithFKMembersRenamed = $assosciationNodesWithTypesRenamed `
Where-Object { $renamedTypeMap[$_.Member] -ne $null -and $_.IsForeignKey -eq "true"} ` ForEach-Object { $_.Member = $renamedTypeMap[$_.Member]; $_; }; # Fix up member names for any assosciations on other tables which are Subset assosciations and reference a renamed member$assosciationNodesWithSubsetMembersRenamed = $assosciationNodesWithTypesRenamed `
Where-Object { $renamedMemberMap[$_.Member] -ne $null -and $_.IsForeignKey -eq $null } ` ForEach-Object { $_.Member = $renamedMemberMap[$_.Member]; $_; };$assosciationFKNodesRenamed = $doc.Database.Table `
Where-Object { $_.Type.Association -ne $null } ` ForEach-Object { $_.Type.Association; } ` Where-Object { $renameAssosciations[$_.Name] -ne $null -and $_.IsForeignKey -eq "true"} ` ForEach-Object { $_.Member = $renameAssosciations[$_.Name].FKMember; $_; };$assosciationSubsetNodesRenamed = $doc.Database.Table `
Where-Object { $_.Type.Association -ne $null } ` ForEach-Object { $_.Type.Association; } ` Where-Object { $renameAssosciations[$_.Name] -ne $null -and $_.IsForeignKey -eq $null} ` ForEach-Object { $_.Member = $renameAssosciations[$_.Name].PluralMember; $_; };[System.Xml.XmlWriterSettings]$writerSettings = new-object System.Xml.XmlWriterSettings;
$writerSettings.set_Indent($true);$writerSettings.set_NewLineHandling([System.Xml.NewLineHandling]::Replace);
$writerSettings.set_CloseOutput($true);$local:outputStream = new-object System.IO.StringWriter;
[System.Xml.XmlWriter]$local:writer = [System.Xml.XmlWriter]::Create($outputStream, $writerSettings);
$doc.Save($writer);
$writer.Flush();
$writer.Close();
$outputStream.Close();
$outputStream.ToString();
}
To assist your development of powershell scripts, you can use PowerShell Plus (http://www.powershell.com/) to parse and debug your scripts. Another amazing utility is the powershell add-in for reflector: http://www.hanselman.com/blog/ReflectorAddinsAndPowerShellLanguageSupportForReflector.aspx. This actually attempts to disassemble existing .NET DLLs to powershell scripts.
There are a whole host of plugins for Lutz Roeders application mentioned in the Hanselman article above (the Reflector compare of different dlls looks very useful) -but I'll have to save my comments for a later blog post...
DDK
Using Impersonation Batch Files and RunAs to Assist Web Application Testing

For example, you can use the following "PP_Test_ImpersonateSuperUser.bat" file to impersonate a Super User without logging off and logging in as that user. It will also open up IE for the http://pp-test web site (an intranet site).
@ECHO ******Running as SUPER USER (IMTEST11); password is SuperUsersPassWord
@ECHO OFF
COLOR 0A
runas /user:APAC\imtest11 /savecred "%ProgramFiles%/Internet Explorer/iexplore.exe \"pp-test\""
pause
You can now test to your hearts content without having to log off your normal Windows account or logging on into Terminal Services on another machine as a different user.
