CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: web.config

Run web.config-dependant code in PowerShell

PowerShell is a great tool. It helps in SharePoint administration and tasks automation. Today I needed to provision a webpart on many similar pages. This third-party webpart’s constructor instantiates a dataaccess service and uses a connectionstring which is stored in the web.config file. So the webpart creation failed until I found a way to load the configuration into powershell.

First you can create a simple file powershell.exe.config, put it into $pshome (C:\Windows\System32\WindowsPowerShell\v1.0). In that file you can specify the connectionstring in the same way like in the web.config (or app.config). But it is not secure: the connectionstring can be changed in the future, and you really don’t want to copy your connectionstrings around. So there is a better way: Check out Ohad Israeli’s blog post about how a configuration file can be bound dynamically in a .net assembly: Binding to a custom App.Config file.

In PowerShell you can do the same, all we need is to modify the syntax: StackOverflow: Powershell Calling .NET Assembly that uses App.config:

[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)

In SharePoint the web.config file resides in:

C:\inetpub\wwwroot\wss\VirtualDirectories\80\web.config

So include this in the script which invokes web.config dependant code:

$config_path = "C:\inetpub\wwwroot\wss\VirtualDirectories\80\web.config"
[System.AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $config_path)

The ability to bind the configuration file dynamically can be even helpful in another part of the SharePoint world – timerjobs. The timer jobs are executed by owstimer.exe. This service has an own configuration file: {hive}\BIN\OWSTIMER.EXE.CONFIG If the timer job configuration shares connectionstrings or appSettings with web.config, it should be theoretically possible to bind the web.config to owstimer. Leave a comment below if you find this information useful.

Settings in Sharepoint_config database instead of appSettings

An alternative to store key-value paired properties in appSettings in web.config we can use Sharepoint_config database by creating our own SPPersistedObject.  First we have to create a class which inherits from SPPersistedObject and decorate its properties with [Persisted]:

namespace Takana.SharePoint
{
    public class Settings: SPPersistedObject
    {
        [Persisted]
        public string DbConString;
 
        public LinkCheckerPersistedSettings() { }
        public LinkCheckerPersistedSettings(string name, SPPersistedObject parent) : base(name, parent) { }
    }
}

Then we must create such an object. Let’s do it in Powershell:

if(-not(Get-PSSnapin | 
	Where { $_.Name -eq "Microsoft.SharePoint.PowerShell"})) { 
	Add-PSSnapin Microsoft.SharePoint.PowerShell }

[Reflection.Assembly]::LoadWithPartialName("takana.sharepoint")
$app = get-spwebapplication http://takana
$configName = "takana.sharepoint.settings"
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local
$settings = $farm.GetObject($configName, $app.Id, [takana.sharepoint.settings])
if ($settings -ne $null) { $settings.Delete() }             
#Create a new persisted settings object
$settings = New-Object Takana.Sharepoint.settings ($configName, $app)
$settings.DbConString = "Some Connection String"
$settings.Update();

To get a member by name we must use reflection:

public static string FindSettings(string key, SPWebApplication app)
{
  var s = string.Empty;
  try
  {
    var farm = Microsoft.SharePoint.Administration.SPFarm.Local;
    var settings = farm.GetObject("Takana.Sharepoint.Settings", app.Id, typeof(Settings)) as Settings;
      if (settings != null)
      {
        var type = typeof(Takana.SharePoint.Settings);
        var f = type.GetField(key);
        s = f.GetValue(settings) as string;
      }
  }
  catch (ArgumentException ex)
  {
    throw new ArgumentException("Settings could not be found."), ex);
  }
  return s;
}

To prevent errors, we must catch ArgumentException. Pay attention to the constructor of ArgumentException, we provide the original Exception as an InnerException argument and enable a better tracking.

SPWebConfigModification

SPWebConfigModification. Some links to start with:

http://panvega.wordpress.com/2009/09/02/using-spwebconfigmodification-within-a-feature-receiver/
http://www.onedotnetway.com/get-name-of-current-executing-assembly-in-c/
http://blogs.devhorizon.com/reza/?p=459
http://ikarstein.wordpress.com/2010/09/02/add-web-config-modification-with-powershell-spwebconfigmodification/
http://msdn.microsoft.com/en-us/library/bb861909.aspx

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
	var webapp = parent as SPWebApplication;
	if (webapp != null)
	{
		var mod1 = GetWebControlsConfigMod();
		webapp.WebConfigModifications.Add(mod1);
		var mod2 = GetConStringConfigMod();
		webapp.WebConfigModifications.Add(mod2);
		SaveChanges(webapp);
	}
	else
	{
		Log.Warning("no modifications to webapp are done");
	}
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
	var webapp = parent as SPWebApplication;
	if (webapp != null)
	{
		var mod = GetWebControlsConfigMod();
		var modsCollection = webapp.WebConfigModifications;
		var modToDelete =
			(from m in modsCollection
			 where m.Value.Equals(mod.Value, StringComparison.InvariantCultureIgnoreCase)
			 select m).FirstOrDefault();
		if (modToDelete != null)
		{
			modsCollection.Remove(modToDelete);
			SaveChanges(webapp);
		}
	}
}
private static void SaveChanges(SPPersistedObject webapp)
{
	var service = webapp.Farm.Services.GetValue();
	service.ApplyWebConfigModifications();
	webapp.Update();
}

private static SPWebConfigModification GetWebControlsConfigMod()
{
	var assembly = System.Reflection.Assembly.GetAssembly(typeof(WebControls.OfficeEditor));
	var ass = assembly.FullName;
	var @namespace = assembly.GetName().Name + ".WebControls";
	var value = string.Format("", ass,
							  @namespace);
	const string path = "configuration/SharePoint/SafeControls";
	var mod = new SPWebConfigModification
	{
		Path = path,
		Name = "JustaName1",
		Sequence = 0,
		Owner = @namespace,
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Value = value
	};
	return mod;
}

private static SPWebConfigModification GetConStringConfigMod()
{
	const string name = "ContosoConString";
	const string conString =
		"Data Source=db.contoso.com;Initial Catalog=contoso_db;Persist Security Info=True;User ID=contoso_Contributor;Password=contoso";
	var mod = new SPWebConfigModification
	  {
		  Name = "JustaName2",
		  Path = "configuration/connectionStrings",
		  Owner = "contoso_connectionstrings",
		  Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		  Value = String.Format("", name, conString)
	  };
	return mod;
}

Powershell:

#ADDING
asnp microsoft.sharepoint.powershell
$url = "http://contoso"
$app = Get-SPWebApplication $url
$name = "ContosoConString";
$conString = "Data Source=db.contoso.com;Initial Catalog=contoso_db;Persist Security Info=True;User ID=contoso_Contributor;Password=contoso";
$mod = new-object Microsoft.SharePoint.Administration.SPWebConfigModification
$mod.Name = "JustName2"
$mod.Path = "configuration/connectionStrings"
$mod.Owner = "User Name"
$mod.Type = 0 #for the enum value "SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode"
$mod.Value = '<add name="{0}" connectionString="{1}" />' -f $name, $conString
$app.WebConfigModifications.Add($mod)
$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$service.ApplyWebConfigModifications()
$app.Update()
#ADDING snapin
asnp microsoft.sharepoint.powershell

$url = "http://contoso"
$app = Get-SPWebApplication $url

#SafeControl
$assembly = "Contoso.SP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=20c0327f8b01d979"
$namespace = "Contoso.SP.WebControls"
$mod = new-object Microsoft.SharePoint.Administration.SPWebConfigModification
$mod.Name = "ContosoSafeControls"
$mod.Path = "configuration/SharePoint/SafeControls"
$mod.Owner = "Contoso"
$mod.Type = 0 #for the enum value "SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode"
$mod.Value = '<SafeControl Assembly="{0}" Namespace="{1}" TypeName="*" Safe="True" />' -f $assembly, $namespace
$app.WebConfigModifications.Add($mod)

#applying changes
$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$service.ApplyWebConfigModifications()
$app.Update()

#REMOVING
asnp microsoft.sharepoint.powershell
$app = Get-SPWebApplication http://contoso
$modCol = $app.WebConfigModifications
$mod = $modCol| Where { $_.Owner.Equals("User Name") }
$modCol.Remove($mod)
$service = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$service.ApplyWebConfigModifications()
$app.Update()

#if you want to clear all web.config mods associated with the web app:
$modCol = $app.WebConfigModifications
while ($modCol -ne 0) { $modCol.Remove($modCol[0]) }
$service.ApplyWebConfigModifications()
$app.Update()

Allright, how can we apply changes in the whole farm? Ryan Dennis uses $app.Parent.Apply.. Rajkamal says we have to run service.Apply (if it would be in C#). To Get Service we can use generics in PowershellKeith Dahlby writes about SPWebService.ContentService.

Add the first connectionString

I encountered a problem adding the first connection string by this script. It just didn’t work. The solution is to add the parent element “connectionStrings”.

Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager - Coder, Speaker, Author

Office 365, SharePoint and Azure

SharePoint Dragons

Nikander & Margriet on SharePoint

Paul J. Swider - RealActivity

RealActivity is a specialized Microsoft healthcare services and solution advisory firm.

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

paul.tavares

Me and My doings!

Share SharePoint Points !

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

Aryan Nava

| Blockchain | Serverless Architecture | Microservices Architecture | DevOps | AWS Lambda | Teraform |

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know about SharePoint - CommunicoCuspis