Thursday, August 13, 2009

How to create a PFX file

makecert.exe -sv MyKey.pvk -n "CN=My Test Site" MyKey.cer -sky exchange

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\pvk2pfx.exe" -pvk MyKey.pvk -spc MyKey.cer -pfx MyPFX.pfx -po

Note: "-sky exchange" avoids errors like "SSL Certificate add failed, Error: 1312"

Friday, June 5, 2009

SharePoint: Code for extending a web app

This doesn't claim to be the code to extend a web app, but more like a boilerplate that you can adapt to your own needs. I tried it with a generous matrix of parameters and works correctly, but I have no doubt that some combinations may cause issues.

        private static void ExtendWebApplication(SPWebApplication webapp, string name, int port, SPUrlZone zone, bool secure, bool useWindowsAuth, bool allowAnonymous, bool useClaims)
{
if (webapp == null)
{
throw (new ArgumentNullException("webapp"));
}

SPServerBinding serverBinding = null;
SPSecureBinding secureBinding = null;
if (secure)
{
secureBinding = new SPSecureBinding();
secureBinding.Port = port;
}
else
{
serverBinding = new SPServerBinding();
serverBinding.Port = port;
}

string extendedAppPath = webapp.IisSettings[SPUrlZone.Default].Path.ToString().Substring(0, webapp.IisSettings[SPUrlZone.Default].Path.ToString().LastIndexOf(@"\") + 1) + port.ToString();
SPIisSettings iisSettings = new SPIisSettings(
string.Format(CultureInfo.InvariantCulture, "{0} - {1}", name, port),
false,
true,
serverBinding,
secureBinding,
new DirectoryInfo(extendedAppPath));
iisSettings.DisableKerberos = !useWindowsAuth;
iisSettings.UseWindowsIntegratedAuthentication = useWindowsAuth;
iisSettings.AllowAnonymous = allowAnonymous;
webapp.IisSettings.Add(zone, iisSettings);
webapp.AlternateUrls.SetResponseUrl(new SPAlternateUrl(GetAlternateUrl(port, secure), zone));
webapp.AlternateUrls.Update();
webapp.UseClaimsAuthentication = useClaims;
webapp.Update();
webapp.ProvisionGlobally();
}

Tuesday, June 2, 2009

C#: Running PowerShell from C#

This is a class that allows to execute PowerShell scripts from C#



using System.Management.Automation;
using System.Management.Automation.Runspaces;

/// <summary>
/// PowerShellExecutor
/// </summary>
public class PowerShellExecutor
{
Runspace _runspace = null;
Pipeline _pipeline = null;

/// <summary>
/// .ctor
/// </summary>
public PowerShellExecutor()
{
_runspace = RunspaceFactory.CreateRunspace();
_runspace = RegisterCmdlets(_runspace, _runspace.CreatePipeline());
_pipeline = _runspace.CreatePipeline();
}

public void ClearErrors()
{
_pipeline = _runspace.CreatePipeline("$error.Clear()");
_pipeline.Invoke();
}

/// <summary>
/// ExecuteCmdlet
/// </summary>
/// <param name="command"></param>
/// <param name="rs"></param>
/// <param name="pipe"></param>
/// <returns></returns>
/// <example>
/// PowerShellExecutor p = new PowerShellExecutor();
/// Collection<PSObject> c = p.ExecuteCmdlet("$w = Get-Web 'MySite - 80'", null);
/// c = p.ExecuteCmdlet("[System.Console]::WriteLine($w)", null);
/// </example>
public Collection<PSObject> ExecuteCmdlet(string command)
{
// create pipeline
_pipeline = _runspace.CreatePipeline();

// add script to execute
_pipeline.Commands.AddScript(command);

// execute
Collection<PSObject> results = _pipeline.Invoke();
StringBuilder result = new StringBuilder();

// check results
if (results.Count == 0)
{
result = new StringBuilder();
result.Append("$error");
_pipeline = _runspace.CreatePipeline(result.ToString());
results = _pipeline.Invoke();
}

// return
return results;
}

/// <summary>
/// RegisterCmdlets
/// </summary>
/// <param name="runspace"></param>
/// <param name="pipeline"></param>
/// <returns></returns>
private Runspace RegisterCmdlets(Runspace runspace, Pipeline pipeline)
{
Collection<PSObject> results;
StringBuilder command = new StringBuilder();
runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
command.Append("Set-Alias powershell $env:windir\\System32\\WindowsPowerShell\\v1.0\\powershell.exe");
pipeline = runspace.CreatePipeline(command.ToString());
results = pipeline.Invoke();

command = new StringBuilder();
command.Append("Add-pssnapin Microsoft.SharePoint.PowerShell");
pipeline = runspace.CreatePipeline(command.ToString());
results = pipeline.Invoke();
return runspace;
}
}

Monday, June 1, 2009

Architectural Concerns

Cheat-sheet on things to have in mind when looking at a system from an architectural perspective:

Simplicity
Testability
Usability
Deployment
Ecosystem
Modularity
Diagnosibility
Performance
Manageability
Compatibility
Layering
Reliability
Accessibility
Serviceability
Extensibility
Dependencies
Security
Globalizability
Supportability
Programmability
Maintenance

Saturday, May 30, 2009

WCF: System.ServiceModel.FaultException: The message could not be processed

Problem: exception thrown when connecting to a WCF service

System.ServiceModel.FaultException: The message could not be processed. This is most likely because the action 'http://tempuri.org/IStockService/GetSymbolData' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.

Solution: at least in my case, there was a mismatch between the binding specified in the client (SecurityMode.None) and the server (wsHttpBinding). After specifiying the right binding in the client (SecurityMode.Message), it worked correctly.

Tuesday, April 7, 2009

When to use AllowUnsafeUpdates, ValidateFormDigest() or else

For scenarios in which your code is processing a POST request, ValidateFormDigest() will, behind the scenes, set AllowUnsafeUpdates to true.

But some scenarios (e.g. web services) are not a POST request, therefore ValidateFormDigest() will fail.

So, here's a simple decision tree to help:

HttpContext.Current is null => Do nothing, no need to set AllowUnsafeUpdates to true nor to call ValidateFormDigest() because update will be carried out (e.g. code being called from an .exe from a cmd prompt)

HttpContext.Current is NOT null
- SPContext.Current is null => Need to set AllowUnsafeUpdates to true (e.g. web service)
- SPContext.Current is NOT null => Call ValidateFormDigest() (e.g. POST request processing)

Monday, April 6, 2009

SPSecurity.RunWithElevatedPrivileges() throws InvalidOperationException, "Operation is not valid due to the current state of the object."

There are several reasons for this to happen.

1) HttpContext.Current.User == null
2) code running under impersonation.

If it's 2), here's one recipe, save HttpContext, set it to null, restore it back:

            HttpContext prev = HttpContext.Current;
HttpContext.Current = null;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
...
});
}
finally
{
HttpContext.Current = prev;
}