code it

Martins Tech Blog

FileNotFoundException im Konstruktor von SPSite

Als ich eben den Post zu AddFieldAsXml geschrieben habe, habe ich die Beispiele in einer Konsolenanwendung nachgestellt. Das Beispiel ist nicht sehr kompliziert und doch überraschte mich SharePoint direkt in der ersten Zeile mit einer FileNotFoundException.

Laut MSDN wird eine FileNotFoundException im SPSite-Konstruktor dann geworfen, wenn die SiteCollection unter der Url nicht gefunden werden konnte. Die Url ließ sich jedoch problemlos im Browser aufrufen - sowohl unter localhost als auch unter dem Rechnernamen wurde die SiteCollection gefunden. Nächster Versuch war also, die Credentials explizit mitzugeben, auch wenn das eigentlich nicht das Problem sein dürfte, weil sowohl Browser als auch Visual Studio mit dem gleichen Nutzeraccount verwendet wurden.

Was die MSDN-Seite verschweigt: Diese Exception wird auch dann geworfen, wenn das Platform-Target nicht stimmt. Konsolenanwendungen haben in der Visual Studio Vorlage grundsätzlich erst einmal das Platform Target x86; SharePoint aber ist eine 64-bit-Anwendung, daher muss das Platform Target der Konsolenanwendung auch x64 sein, damit es funktioniert. Also die Einstellung eben geändert, neu kompiliert und schon klappt es auch von der Konsole.

AddFieldAsXml - Bug oder Feature, das ist hier die Frage

Möchte man programmatisch Felder zu einer SharePoint-Liste hinzufügen, so stolpert man früher oder später über die Methoden Add bzw. AddFieldAsXml von SPFieldCollection. In vielen Fällen führen beide Methoden zum Ziel, wobei AddFieldAsXml den Vorteil hat, dass man recht einfach das Schema-Xml aus bereits bestehenden Listen übernehmen kann, es auch recht komplexe Szenarien zulässt und dann in meinen Augen besser lesbar ist als Quellcode, der über mehrere Zeilen oder Klassen verteilt versucht, ein Objekt vom Typ SPField zu erzeugen und mit den passenden Eigenschaften zu bestücken.

Damit möchte ich auch schon zum Problem kommen: Ein Objekt vom Typ SPField verfügt über zwei Eigenschaften, die in diesem Kontext eine Rolle spielen: Title stellt in der Liste den Spaltennamen dar, den der Nutzer zu Gesicht bekommt. Dieser kann natürlich auch Leerzeichen oder Sonderzeichen beinhalten. Im Gegensatz dazu ist InternalName die interne Referenz auf die Spalte und als solche ist sie in der jeweiligen Liste eindeutig und readonly. Zudem werden hier sämtliche Sonderzeichen maskiert dargestellt. Um es mal plastisch darzustellen im folgenden das Beispiel aus der MSDN.

using (var site = new SPSite("http://localhost/"))
{
    using (var web = site.RootWeb)
    {
            var list = web.Lists["Shared Documents"];

            var displayName = "My Custom Field";
            var staticName = "MyStaticName";

            var strInternalName = list.Fields.Add(displayName, SPFieldType.Text, false);
            var field = list.Fields.GetFieldByInternalName(strInternalName);

            field.StaticName = staticName;
            field.Update();
    }
}

In diesem Fall ist Title nun wie erwartet My Custom Field und der Internal Name My_x0020_Custom_x0020_Field.

Wie bereits angedeutet, geht das ganze auch mit AddFieldAsXml:

using (var site = new SPSite("http://localhost/"))
{
    using (var web = site.RootWeb)
    {
        var list = web.Lists["Shared Documents"];

        var fieldXml = "<Field Type=\"Text\" MaxLength=\"50\" DisplayName=\"My Custom Field\" ID=\"15C0D97B-3735-4AD9-8FE2-8A01E5B43486\" StaticName=\"MyStaticName\" Name=\"MyInternalName\" />";
        var strInternalName = list.Fields.AddFieldAsXml(fieldXml);

        var field = list.Fields.GetFieldByInternalName(strInternalName);

        field.Update();

    }
}

Was bei der Ausführung nun auffällt: Obwohl ich im XML einen Internal Name vorgegeben habe, wird dieser nicht verwendet, sondern weiterhin auf Basis des Display Name ein Internal Name generiert. Das ist insofern schlecht, da wie beschrieben der Internal Name ja der Identifier der Spalte ist und deshalb auch in CAML-Queries verwendet wird. Mehr...

Falscher Redirect auf SharePoint-Formulare

SharePoint-Listen bringen auch immer ihre eigenen Formulare mit, mit denen Listenelemente angeschaut (DispForm.aspx), editiert (EditForm.aspx) oder erzeugt (NewForm.aspx) werden können. Im Standardfall beinhalten diese Formulare ein ListFormWebPart, mit dessen Eigenschaft FormType definiert wird, welche Funktion das WebPart bereitstellen soll. Diese Formulare können auch an eigene Bedürfnisse angepasst werden, um weitere Funktionalitäten an dieser Stelle bereitzustellen.

Editiert man diese Formulare zu intensiv, so kann es sein, dass SharePoint verweigert, auf die Formulare zu verweisen. Das merkt man daran, dass im Kontextmenü die Menüpunkte "Element anzeigen" oder "Element bearbeiten" auf die Hauptseite der SiteCollection verweisen und nicht mehr die Listenformulare aufgerufen werden. Gut ist beraten, wer dann noch die Originalversion der Listenformulare vorliegen hat (oder zumindest eine Version, die noch funktioniert hat). Hat man dies nicht, so hat man in der Regel extrem viel Spaß dabei, die Seite wiederherzustellen, denn SharePoint verwendet intern jede Menge Guids, die auch hier dann benötigt werden.

Eine kleine Hilfestellung, was man bei der Wiederherstellung der Standardformulare beachten muss, gibt Ben in seinem Blog. Am wichtigsten hierbei: Guid der Liste, Guid des WebParts und FormType des ListFormWebParts.

Id des Listenelements im EditForm.aspx anzeigen

Im Standard werden einige Felder nicht in EditForm.aspx oder DispForm.aspx angezeigt. Eines dieser Felder ist die ID des Listeneintrags. Auf eine SQL-Tabelle projiziert, handelt es sich dabei um den internen Identifier, der den Eintrag eindeutig identifiziert und automatisch inkrementiert wird.
 
Da diese Spalte von SharePoint automatisch verwaltet wird, ist es in vielen Anwendungsfällen auch durchaus gerechtfertigt, diese nicht anzuzeigen, um so auch nicht den Eindruck zu erwecken, dieses Feld könnte editiert werden. Nun gibt es aber auch Anwendungsfälle, da möchte man, dass ein solcher Identifier auch angezeigt wird, einfach weil man so schon eine laufende Nummer hat. Beispiel dafür ist ein Bugtracking oder auch ein Support-System, wie es das Help-Center-Template schon mitbringt.
 
Für das Problem, die ID des Listeneintrags anzuzeigen gibt es im Netz mehrere Lösungen. Meist läuft die Lösung darauf hinaus, mit JavaScript oder Codebehind den QueryString-Parameter ID aus der Url auszulesen. Eine weitere Möglichkeit, und wenn man die bestehenden Seiten mal etwas genauer betrachtet vermutlich die von den SharePoint-Entwicklern vorgesehene Lösung ist es, die Klasse ListItemProperty zu verwenden. Damit kann man, wie der Name schon vermuten lässt, auf die Eigenschaften des zugrundeliegenden ListItems zugreifen.
 
<SharePoint:ListItemProperty Property="ID" id="ID" runat="server"/>
 
Dieses Control findet man im SharePoint Designer in der Toolbox.
 
Noch ein kleiner Tipp am Rande: Ähnlich wie ListItemProperty gibt es auch noch ListProperty, mit dem man Eigenschaften der Liste anzeigen kann.

Seltsame Namenskonventionen in SharePoint

Sharepoint Server 2010 scheint seine Vergangenheit nicht verstecken zu können. Möchte man ein neues Web erstellen, sind einige Namen nicht möglich. 

Man erhält eine Fehlermeldung, wenn man einen der folgenden Namen verwendet CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8 oder LPT9. Auch wenn es sich bei SharePoint um eine Web-Anwendung handelt, die ihre Daten in einem SQL-Server verwaltet, scheint es Probleme zu geben, wenn man Namen verwendet, die im Dateisystem reserviert sind.

Mehrfachaktionen in kontextsensitiven Ribbons als Sandboxed Solution

Sharepoint 2010 bietet einige spannende Möglichkeiten, die es so bisher nicht gab. Zum einen gibt es das Client Object Model, das es erlaubt, auf Clientseite auf das Objektmodell von SharePoint zuzugreifen. Zum anderen bietet es die Möglichkeit, sogenannte Sandboxed Solutions bereitzustellen, die zwar mit geringeren Rechten ausgestattet sind, aber dafür von einer breiteren Anwendergruppe installiert werden können.

In diesem Blogpost wird gezeigt wie man diese Features kombinieren und in einer Aufgabenliste die Mehrfachaktion "Alle Aufgaben erledigen" implementieren kann, die dann als Sandboxed Solution bereitgestellt wird. Eine kurze Einführung in das Thema Sandboxed Solutions gibt Thorsten Hans in seinem Blogpost und auch das MSDN Magazine wartet mit einem Artikel dazu auf.

Erster Schritt ist es, ein neues SharePoint-Projekt in Visual Studio anzulegen. Dazu verwende ich das Projekttemplate "Empty SharePoint Project". Die Auswahl der Programmiersprache ist in diesem Fall irrelevant, da alles über XML und JavaScript gelöst wird. Visual Studio legt daraufhin eine neue Solution an, die bereits ein Feature beinhaltet. Allerdings ist der Name des Features recht unaussagekräftig und sollte direkt angepasst werden. In meinem Beispiel soll es TaskBatchCompleteFeature heißen. Hinzu kommt noch ein neues Element, da die Anpassungen über die Elements.xml durchgeführt werden. Damit auch hier klar ist, was das Element macht, bekommt es den Namen TaskBatchCompleteElement. Da die Solution komplett aus Konfigurationsdateien besteht, ist es sinnvoll, in den Projekteigenschaften noch "Include Assembly In Package" auf false zu setzen. Die Visual Studio Solution sollte nun ungefähr so aussehen:

 

Die nächsten Anpassungen erfolgen in der Elements.xml. Hier ist die Konfiguration der Ribbon-Anpassung zu hinterlegen. In der CustomAction definiert man, dass diese Aktion nur auf Listen des Typs Aufgabe im Ribbon sehen möchte. Dafür sind die Attribute RegistrationType und RegistrationId zuständig, wobei die List Template Id 107 für Aufgabenliste steht.

Über den Tag CommandUIDefinition kann man nun einen Button hinzufügen. Eine Kurzzusammenfassung, welche XML-Fragmente notwendig sind, um welches Ergebnis zu erreichen findet man in folgendem Post. Kurz erklärt definiert die Location dabei, in welcher Ribbon-Gruppe der Button hinzugefügt werden soll. Die Standard-Ribbons werden über die Datei CMDUI.xml im Ordner 14\template\global\xml definiert. Möchte man bestehende Ribbon-Gruppen anpassen, so kann man die Namen in dieser Datei ermitteln und auch anhand der bestehenden Sequence-Ids die Reihenfolge-Einordnung für das neue Control in der Gruppe bestimmen.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <CustomAction
    Id="TaskBatchCompleteRibbonAction"
    Location="CommandUI.Ribbon"
    RegistrationType="List"
    RegistrationId="107">
  <CommandUIExtension>
      
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.ListItem.Manage.Controls._children">
          <Button
              Id="TaskBatchCompleteRibbonButton"
              Alt="Aufgaben erledigen"
              LabelText="Aufgaben erledigen"
              Sequence="21"
              Command="TaskBatchCompleteRibbonCommand"
              Image32by32="_layouts/images/TaskDone.gif"
              Image16by16="_layouts/images/TaskDone.gif"
              TemplateAlias="o2"
              />
        </CommandUIDefinition>
      </CommandUIDefinitions>

      <!--TODO: add CommandUIHandler-->
    </CommandUIExtension>
    
    <!--TODO: add ScriptLink-->
  </CustomAction>
</Elements>

Da der Button nur dann aktiv sein soll, wenn mindestens ein Element gewählt wurde, wird ein CommandUIHandler hinzugefügt, der ein EnabledScript zugewiesen bekommt. Hier erfolgt die Prüfung auf die Anzahl der selektierten Elemente mit Hilfe der Funktion SP.ListOperation.Selection.getSelectedItems()

<CommandUIHandlers>
  <CommandUIHandler
     Command="TaskBatchCompleteRibbonCommand"
     CommandAction="javascript:BatchCompleteTasks();"
     EnabledScript="javascript:function isOneOrMoreEnabled() { 
                          var items = SP.ListOperation.Selection.getSelectedItems(); 
                          var ci = CountDictionary(items); 
                            return (ci > 0); 
                           } 
                          isOneOrMoreEnabled();" />
</CommandUIHandlers>

Als letzter Schritt wird nun noch die eigentliche Aktion benötigt. Diese wird in einer weiteren CustomAction hinterlegt. Die eigentliche Funktion ist recht simpel. Über die gleiche Methode wie eben werden die selektierten Elemente ermittelt und über die Kontextinformationen das zugehörige Web und die Liste geladen. Im Anschluss daran iteriert man durch die Elemente und setzt die Felder - bei einer Aufgabe sind das der Status und der Erledigungsgrad. Nachdem dies vorgenommen wurde, müssen die Daten noch zum Server übertragen werden. Dazu ruft man die Methode executeQueryAsync auf. Dieser übergibt man zwei Callbacks - in meinem Fall "success" und "failed", die dann noch eine Benachrichtigung für den Benutzer auslösen.

<CustomAction Id="TaskBatchCompleteRibbonScriptAction"
     Location ="ScriptLink"
     ScriptBlock="
BatchCompleteTasks = function () {
    var selectedItems = SP.ListOperation.Selection.getSelectedItems();
    var currentListGuid = SP.ListOperation.Selection.getSelectedList();

    var context = SP.ClientContext.get_current();
    var currentWeb = context.get_web();
    var currentList = currentWeb.get_lists().getById(currentListGuid);

    var k;
    for (k in selectedItems) {
        var listitem = currentList.getItemById(selectedItems[k].id);
        listitem.set_item('Status', 'Completed')
        listitem.set_item('PercentComplete', '1')
        listitem.update();
        context.executeQueryAsync(Function.createDelegate(this, this.success), Function.createDelegate(this, this.failed))
    }

}
             

function success() {
    SP.UI.Notify.addNotification('Aufgabe erfolgreich abgeschlossen');
}

function failed(sender, args) {
    var statusId = SP.UI.Status.addStatus(args.get_message());
    SP.UI.Status.setStatusPriColor(statusId, 'red');
    latestId = statusId;
}"
      />

Damit ist die Arbeit im Grunde auch schon getan. Nach einem Klick auf "Package" erscheint im Ausgabepfad eine wsp-Datei.

Sandboxed Solutions benötigen keine Farmadministratorrechte, um installiert zu werden. Aus diesem Grund erfolgt die Installation auch nicht in der Central Adminsitration sondern in der Solution Gallery der Site. Nachdem man die WSP-Datei hierher hochgeladen und die Solution aktiviert hat, steht das neue Feature in der Oberfläche zur Verfügung.

Mehrsprachige Websites in SharePoint 2010

Mehrsprachige Benutzeroberflächen (sog. MUIs) werden in SharePoint 2010 out-of-the-box unterstützt. Voraussetzung dafür ist, dass das passende Language Pack installiert ist. Ist die Einstellung in einer Site aktiviert, können Anwender über eine Sprachauswahl die Sprache umschalten. Im Gegensatz zu vorherigen SharePoint-Versionen können nun zusätzlich zu den systemeigenen Beschriftungen beispielsweise auch Spaltenüberschriften in Listen in anderen Sprachen dargestellt werden.

Aktivierung über die Benutzeroberfläche
Unter Site Administration -> Language Settings finden sich die Spracheinstellungen der Site.

Die Standardsprache ist nicht änderbar. Dabei handelt es sich um die Sprache, mit der die Site angelegt wurde. Es kann jedoch festgelegt werden, welche Sprachen die Site zusätzlich unterstützen soll.

Auswirkungen
Standard-Templates von SharePoint (wie z.B. die Teamsite) unterstützen dank der Language Packs direkt die gewählten Sprachen. Kehrt man nach der Änderung der Einstellung in die Site Administration zurück und hat wie ich zwar eine englische Site, aber einen Browser mit deutscher Sprachauswahl, so wird die Site Administration direkt in deutsch angezeigt und auch die Listen, Dokument-Bibliotheken und Spaltenüberschriften erscheinen auf deutsch.

Bei näherer Betrachtung fällt auf, dass es nun im Menü einen neuen Menüpunkt gibt, über den die Anzeigesprache geändert werden kann. Wer sich bereits mit Variations beschäftigt hat, dem sollte dieses Verhalten bekannt vorkommen. Bereits in Microsoft Office SharePoint Server 2007 gab es den Variation Label Picker, der ähnlich funktioniert hat.

Als kleines Beispiel soll eine Liste dienen, die kleinere Projekte verwalten soll – so zum Beispiel den Hausbau von Familie Smith und den Bau einer Hundehütte bei Familie Doe. Da als Standard "English" definiert ist, lege ich auch die neuen Spalten in englisch an. Etwas unschön für die nicht-englischsprachige Anwender ist nun, dass selbst definierte Listenspalten und auch der Listentitel im Menü auch in englisch erscheint. Das lässt sich aber ganz einfach ändern. Dazu navigiert man in die Listeneinstellungen bzw. Spalteneinstellungen, wenn die entsprechende Sprache ausgewählt ist und überschreibt die Werte. Der Effekt ist, dass deutsche Benutzer nun eine fast perfekt übersetzte Seite sehen.

Die Listeninhalte sind natürlich weiterhin in der Sprache, in der sie angelegt wurden und sie sind auch nur in einer Instanz vorhanden – Änderungen wirken sich daher direkt auf andere Sprachen aus.

Aktivierung über die PowerShell
Die Einstellung gilt nur für die entsprechende Site. Besonders bei vielen Subsites ist es daher sinnvoll, eine skriptgesteuerte Variante für die Aktivierung von Mehrsprachigkeit zu haben. Die Einstellungen finden sich im Objekt vom Typ SPWeb. Das folgende Skript ermittelt das Rootweb der angegebenen Site-Collection und fügt die Sprache Deutsch zu den unterstützten Sprachen hinzu – also genau das was auch in der Beschreibung oben über die Benutzeroberfläche gemacht wurde.

Start-SPAssignment -Global

# add german language to alternate languages
$site = Get-SPSite "http://myServer/sites/mhytest"
$web = $site.RootWeb
$web.IsMultilingual = $True
$web.AddSupportedUICulture([System.Globalization.CultureInfo]::GetCultureInfo(1031))
$web.Update()

Stop-SPAssignment -Global;

Anonymen Zugriff in SharePoint mit PowerShell aktivieren

Um auf einer Site Collection anonymen Zugriff zu aktivieren, sind mehrere Schritte notwendig: Zunächst muss in der Central Administration grundsätzlich der anonyme Zugriff auf der Webanwendung aktiviert werden.

Im Anschluss daran kann man auf den gewünschten Site Collections dieser Webanwendung definieren, ob hier die komplette Site Collection oder Listen anonym erreichbar sein sollen, oder ob dieses Feature ganz unterbunden wird.

Eine gute Beschreibung, wie man der Reihe nach vorgehen muss, um diese Einstellungen über die Weboberfläche vorzunehmen, findet man im Post von Randy Drisgill.

Was über die Benutzeroberfläche geht, geht auch über die PowerShell - dem Tool der Wahl für die Administration des SharePoint über die Kommandozeile, allerdings sind die Einstellungen gut versteckt.

Um die Einstellungen in der Central Administration per Kommandozeile durchzuführen, sind ist das Cmdlet GET-SPWebApplication von zentraler Bedeutung. Ist das passende Objekt vom Typ SPWebApplication dann ermittelt, kann man darüber die SPIisSettings ermitteln, in denen der anonyme Zugriff gesetzt werden kann. Laut MSDN ist im Anschluss noch ein Re-Provisioning notwendig, damit sämtliche Frontendserver aktualisiert werden.

Nach diesem Schritt kann in den gewünschten SPSiteCollections die Eigenschaft AnonymousState des RootWebs auf On gesetzt werden. Hier schlägt die in diesem Punkt gewöhnungsbedüftige Syntax der PowerShell zu, nach der sogenannte Nested Types (wie es SPWeb.WebAnonymousState ist) nicht mit dem ".", sondern mit einem "+" dargestellt werden.

Start-SPAssignment -Global;

# set anonymous access in webapp
$webapp = Get-SPWebApplication "http://myserver";
$webAppZone = [Microsoft.SharePoint.Administration.SPUrlZone]::Default;
$webappsettings = $webapp.GetIisSettingsWithFallback($webAppZone);
$webappsettings.AllowAnonymous = $true;
$webapp.Update()
$webapp.Provision()

# set anonymous access in website
$site = Get-SPSite "http://myserver/sites/mytest";
$web = $site.RootWeb;
$web.AnonymousState = [Microsoft.SharePoint.SPWeb+WebAnonymousState]::On;
$web.Update();

Stop-SPAssignment -Global;

Weiß man all diese Hürden zu umschiffen, hat man im Anschluss ein anonym zugreifbares Portal.

Zugriff auf Listeninhalte mit LINQ to SharePoint

In der in diesem Jahr erscheinenden Version bietet SharePoint mit der Assembly Microsoft.SharePoint.Linq.dll (zu finden im Ordner 14\ISAPI) die Möglichkeit, recht einfach Listeninhalte abzufragen. Wenn man sich etwas näher damit beschäftigt, kann man sehr viele Parallelelen zu LINQ to Objects und Linq to SQL entdecken.

Erster Schritt ist, eine Referenz auf die genannte Assembly hinzuzufügen. Ab diesem Zeitpunkt steht der Namespace Microsoft.SharePoint.Linq zur Verfügung. Dieser beinhaltet die Klasse DataContext, über die ähnlich wie bei LINQ to SQL auf die Inhalte zugegriffen werden kann. Die Initialisierung des Kontexts ist recht einfach – hierzu wird einfach im Konstruktor des Objekts die Url der zu verwendenden Site übergeben.

Vor dem Erfolg steht aber ein wenig Arbeit, denn der Zugriff ist typsicher und so müssen für die verwendeten Inhaltstypen Klassen angelegt werden, damit klar ist, welche Property sich in welchem Listenfeld abbildet und wie darauf zugegriffen werden muss. Diese kann man selbst schreiben, oder man nutzt dafür ein Tool ;). Auch hier zeigen sich wieder Parallelen zu bereits Bekanntem: Mit Hilfe des Tools SPMetal (zu finden im Ordner 14\BIN) können die Klassen auf Basis einer bestehenden Site automatisch erstellt werden.

Ab diesem Zeitpunkt ist es recht einfach, wie das folgende Beispiel zeigt:

DataContext data = new DataContext("http://mysite/");

EntityList<Page> wikiPages = data.GetList<Page>("Pages");
var filteredPages = from wikiPage in wikiPages
            where wikiPage.Name == "product-presentation.aspx"
            select wikiPage;

foreach (var filteredPage in filteredPages)
{
    Console.WriteLine(filteredPage.Path);
}

Wenn man der Dokumentation Glauben schenken darf, wird bei der Ausführung versucht, so viel wie möglich in CAML zu übersetzen und direkt und damit schnell auszuführen und der Rest wird dann mit Hilfe von LINQ to Objects im Speicher ausgeführt. Allerdings muss ich dazusagen, dass SharePoint 2010 noch nicht final ist und sich sowohl an den Schnittstellen als auch an der Doku noch einiges tun kann.

Wie neu ist "!Neu"?

Neben neuen Listeneinträgen erscheint im SharePoint immer das “!New”-Icon. Aber wie lange erscheint dieses Icon eigentlich? Wie immer ist die Antwort schnell gefunden, wenn man weiß, wo man suchen muss: Im Standard erscheint das Icon bis zum Ende des folgenden Kalendertages.

Die Einstellung dafür kann man mit Hilfe des Kommandozeilentools stsadm.exe (zu finden unter %COMMONPROGRAMFILES%\Microsoft Shared\web server extensions\12\BIN) auslesen und auch setzen. Der Vorteil dieser Möglichkeit liegt auf der Hand: Elemente können auch für einen längeren Zeitraum als neu erscheinen oder die Markierung kann ganz entfernt werden.

Um den aktuell gesetzten Wert auszulesen, verwendet man folgenden Befehl:

stsadm -o getproperty -pn days-to-show-new-icon -url http://localhost

Im Beispiel ist der Rückgabewert 2. das entspricht dem Standardverhalten. Das Icon wird also 2 Kalendertage lang angezeigt (bis zum Ende des Folgetages).

Mit Hilfe der Operation setproperty kann dieser Wert geändert werden. Beispielsweise unterdrückt der Wert 0 das “!New”-Icon, während der Wert 7 das Icon 7 Kalendertage lang erscheinen lässt.

stsadm -o setproperty -pn days-to-show-new-icon -pv 7 -url http://localhost

Diese Einstellung greift direkt – es ist kein Neustart (iisreset) notwendig.