Portscan-Einzeiler mit Bordmitteln

Das seit einigen Jahren mit der PowerShell 4.0 eingeführte Cmdlet Test-NetConnection ist mit Sicherheit inzwischen ein vielgenutzter Helfer und ein sinnvoller Ersatz für die Verwendung von Telnet, um zu prüfen, ob ein Port offen ist.
Wer sich darüber hinaus die Zeit nimmt und die verfügbaren Parameter anschaut, findet neben des einfachen Socket-Connects noch eine ganze Menge weiterer hilfreicher Optionen.

Leider akzeptiert der Parameter „Port“ nur einen einzelnen Integer und kein Array, um mehrere Ports zu testen. Da der Parameter allerdings Pipelineeingaben akzeptiert, kann man das Problem schnell lösen.

PSPortScan

@(22, 80, 139, 443) | % { Write-Host Port $_":" $(Test-NetConnection 10.0.27.1 -Port $_ -InformationLevel Quiet -WarningAction SilentlyContinue) }

Gut kombinierbar ist das zudem mit der Array-Initialisierung mit Hilfe des Range-Operators (..), mit dem man größere Bereiche abdecken kann.

Das Ergebnis ist ein im Standard des Betriebssystems enthaltener Portscanner. Zwar eine sehr einfache, auf das absolute Minimum reduzierte Version eines Portscanners aber für einen schnellen Test meist ausreichend.

SharePoint 2013 Quick Edit ausgegraut

Der absolute Klassiker zum Thema Quick Edit und dennoch immer wieder gern gesucht bzw. nspmql1achgefragt: Was tun, wenn trotz aller Bemühungen die Datenblattansicht sich nicht zur Mitarbeit überreden lassen möchte?

Die Symptome: Die Schaltfläche „QuickEdit“ im Ribbon-Menü ist ausgegraut, ein wenig sagender Hinweis im Tool-Tip verweist eher auf fehlende Berechtigungen und die Ansicht sieht mehr nach SharePoint 2010 als nach 2013 aus. Gerne tritt das Verhalten auch nach der Migration von Seiten aus der Vorgängerversion auf.

Eine Checkliste zur Lösung des Problems:

  1. Prüfen, ob die Verwendung der Funktion in den Listeneinstellungen unter „Erweiterte Einstellungen“ zugelassen ist. Sind die Einstellungen nicht erreichbar, so wie es für einige wenige Listen-Typen im Standard vorgesehen ist, so kann mittels PowerShell auf dem Listen-Objekt die Property „DisableGridEditing“ auf false gesetzt werden (Update-Methode nicht vergessen auszuführen!)
  2. Prüfen, ob sich eine neue Ansicht nach Vorlage der Datenblattansicht erstellen lässt
  3. Einstellungen der Ansicht…
    1. Entfernen eventuell vorhandener Gruppierungen auf der Ansicht
      (bei Verwendung der Gruppierung steht Quick-Edit nicht zur Verfügung)
    2. Evtl. gesetzte Formatierungen des Views wie „Magazin“, „Schattiert“ etc. entfernen
      (zurück auf Standard stellen)
    3. Verwendung von Kontrollkästchen zulassen
  4. Ergänzen der möglicherweise fehlenden JavaScript-Bibliothek unter <JSLink> in den Quellen (.aspx) der Ansicht…
    1. SharePoint Designer öffnen
    2. Defekte Ansicht öffnen
      spmql2
    3. JSLink mit clienttemplates.js ergänzen
      spmql3

In 99% aller Fälle sollte damit die größte Not vorüber sein. Falls nicht, immer her damit!

Lync Server 2013 & Skype for Business 2015 Protocol Workloads

Ein Muss für jeden Lync- bzw. Skype for Business-Admin, der noch ein Stückchen Tapete in seinem Büro sehen kann!

lyncposter

Die Poster offenbaren keine großen Geheimnisse mehr – dennoch wurden beide Visualisierungen auf den aktuellen Stand gebracht und ganz frisch in den Microsoft Download-Bereich als PDF und Visio-Grafik entlassen. Die umfangreichen Darstellungen der Kommunikationsrichtungen und Verbindungen zwischen Clients und Serversystemen lassen kaum Wünsche offen.

Inhalte

  • Server/Client-Kommunikation und Protokolle für…
    • Instant Messaging & Presence
    • A/V & Web Conferencing
    • Application Sharing
    • Enterprise Voice
  • Notwendige/Optionale Zertifikat-Konfiguration
  • DNS-Konfiguration
  • CMS

Download

 

Benachrichtigung bei Änderung von Homematic-Systemvariablen

HomeMaticNotification_SysVar-NotifyDie aktualisierte Version des Homematic-Benachrichtigungsdienstes ist online. Bislang informierte der Dienst stets nur über geänderte Zustände von Homematic-Sensoren bzw. -Aktoren.

Mit dem neuen Release (RC-Version 1.1.10 bzw. Version 1.2) kann man sich nun auch über geänderte Systemvariablen informieren lassen, was beispielsweise die Alarm-Benachrichtigung oder Informationen zu von Homematic-Programmen gesetzten Systemzuständen vereinfacht.
Die bislang verfügbaren Benachrichtigungsprovider (PushOver, Pushalot, E-Mail und Telegram) funktionieren natürlich auch für die neue Funktion wie gehabt.

Konfiguration

Um für eine Systemvariable Benachrichtigungen zu erhalten, muss diese mit ihrer Homematic-internen ID (IseId) in der Konfigurationsdatei als notifyVariable-Element angelegt werden:

<notifyVariable Name="Anwesenheit" IseId="1234" IsImportant="false" />

Weitere Details zur Konfiguration gibt es in der Beispielkonfiguration ConfigTemplate.xml

Die IseId kann man mit Hilfe des für den Service ohnehin benötigten Addons XML-API herausfinden, indem man die Seite sysvarlist.cgi aufruft. In der XML-Struktur kann man die IseId als Attribut der einzelnen Variablen finden, die auf der CCU2 definiert sind.

Den aktuellen Build findet man an der üblichen Stelle im OneDrive (MD5: 5820d546af62c43ada0eaa3b517ea4dd). Alternativ dazu ist der jeweils aktuelle Quellcode im GitHub-Repo HomeMatic-Notification-Service zu finden.

Viel Spaß beim Ausprobieren. Über Feedback, Anregungen und Ideen freue ich mich!

Push Notification via Telegram

Bis vor ca. zwei Wochen hatte ich mit dem Benachrichtigungsdienst Pushalot von Maciej Olesiński eine wirklich gute und verlässliche Plattform, um mir allerlei Statusmeldungen an zentraler Stelle zukommen zu lassen. Dann wurde es plötzlich ruhig auf meinen mobilen Endgeräten. Kein Server mehr, der mir seinem Gemütszustand mitteilte, keine Wohnungstür mehr, die mich über ihren Status informiert…
Inzwischen bin ich auch nicht mehr gänzlich allein mit dem Thema, wie man beispielsweise auf Reddit lesen kann. Das beruhigt ein wenig, da es nicht an mir zu liegen scheint, andererseits löst es aber auch das Problem nicht.

TelegramPushNotificationsWie dem auch sei – diesem Umstand geschuldet habe ich mich kurzerhand mit der API des Messenger-Dienstes Telegram befasst und entschieden, den Messenger für meine Zwecke und damit als Ersatz für die ausbleibenden Benachrichtigungen von Pushalot zu verwenden.
Die API ist überaus funktional, reich an Funktionen und durchgehend gut dokumentiert. Der Service lässt sich unkompliziert über die heute gängigen Wege ansprechen.
Spannend ist das Konzept der Telegram-Bots als unpersonalisierte Service-Accounts, mit denen man in seiner Rolle als Nutzer interagieren kann. Dabei können vorhandene genutzt oder individuelle, neue Bots angelegt werden. Telegram geht diesen Weg sehr konsequent, so dass ebenfalls die Bedienung der Plattform auf Ebene des Entwicklers über einen solchen Bot läuft. Will man einen Bot erstellen und konfigurieren, so chattet man mit dem @BotFather, dem man über definierte Kommandos die entsprechenden Einstellungen übergibt bis hin zum Profilfoto des eigenen Bots.

Mit relativ geringem Aufwand haben in den letzten Tagen die beiden im vergangenen Jahr veröffentlichten Tools – der Homematic Notification Service sowie das PushMonitoring – einen zusätzlichen Benachrichtigungskanal für die Nutzung von Telegram erhalten.

Das Setup…

…der beiden Tools für die Verwendung der Telegram-Bots funktioniert wie folgt:

  1. Telegram installieren
  2. Als Empfänger die eigene Chat-ID herausbekommen
    (z.B. dem Bot @get_id_bot eine Nachricht mit /my_id senden)
  3. Die Chat-ID in der Konfiguration des Service/Tools ( <notifyBy /> bzw. <sendTo />) hinterlegen
  4. Den jeweiligen Bot – „Homematic Alert“ bzw. „PushMonitoring“ – aufrufen und mit der Nachricht /start aktivieren

Homematic Notification Service

<notifyBy NotifyProvider="Telegram">123456789</notifyBy>

PushMonitoring

  <sendInterfaces>
    <sendTo Type="Telegram" ApiKey="123456789" />
  </sendInterfaces>

Alternativ können statt der eigenen Chat-ID noch Gruppen-IDs öffentlicher Gruppen verwendet werden, wenn der Bot in der Gruppe Mitglied ist.

Die Push-Messages, die über die beiden Tools versendet werden verhalten sich wie normale Chat-Nachrichten, die man vom Kontakt des jeweiligen Bots erhält:

TelegramPushWindowsPhone

Es ist ein wenig schade, dass Pushalot so ganz ohne weitere Informationen abgetaucht ist. An dieser Stelle vielen Dank an die Plattform und ihren Betreiber für die lange Zeit an Zuverlässigkeit sowie das kostenfreie Angebot!

Die beiden Tools (Homematic Notification Service + PushMonitoring) gibt es in aktualisierter Version an der üblichen Stelle im OneDrive oder den Quellcode unter GitHub.

Win32 oder .NET in UWP-App konvertieren

Bestehende Windows Desktop-Anwendungen mit nur wenig Kenntnis der UWP-Apps in eine vollwertige Windows 10 App konvertieren. Dieses Ziel hat man sich bei Microsoft mit dem Projekt Centennial gesetzt.
Der auf der Build 2016 vorgestellte Desktop App Converter war bereits vor einigen Monaten als Preview zum Download zu haben.

Der Konverter führt die Desktop-Anwendung bzw. deren Installer in einer isolierten Windows-Umgebung aus, welche dem Konverter als Windows Basis-Image beiliegt. Dabei werden alle Aktionen in Registry und Dateisystem erfasst und als Grundlage für ein neues AppX-Package verwendet. Diese UWP-App verfügt über ihre eigene Identität, was für die Verwendung der WinRT-APIs sowie die Integration von Features wie Live-Toasts, -Kacheln, Hintergrundaufgaben und Ähnliches erforderlich ist.

Microsoft sieht für Entwickler, die sich mit dem Schwenk auf die neue Plattform schwer tun, einen fließenden Migrationsprozess vor. Zuerst soll die Portierung auf die UWP-App per Konverter erfolgen. Nach dem Bereitstellen und Testen der App könne man UWP-Features ergänzen und die Anwendung Schritt für Schritt optimieren. Zu guter Letzt soll die UWP-App dann für alle Windows-Zielplattformen portiert werden können.

Vor ein paar Tagen gab es eine neue Version v0.1.21 im Downloadbereich inklusive der Windows Base Images 14371 und 14372. Einen guten Einstieg ins Thema bietet die Dokumentation des Konverters.

Ich wage zu bezweifeln, dass dies den mit großer Wahrscheinlichkeit erhofften Durchbruch für die Windows Apps bringen wird, bin aber gespannt, ob der Konverter eine echte Alternative gegenüber dem manuellen Portieren ist und einen entsprechenden Mehrwert bietet. Sollte dem so sein, werde ich ganz sicher ein wenig ausführlicher darüber berichten.

ListItem-Update führt zu „Catastrophic failure“

In einer SharePoint Liste ohne EventReceiver mit einem nicht angepassten Standardformular meldet das System beim Versuch ein Listenelement zu aktualisieren Folgendes:

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

Neben der doch sehr drastischen Wortwahl deutet bereits das HRESULT auf eine durchgereichte COM-Exeption hin. Gerade bei solch vermeintlich tiefgreifenden Offenbarungen erhält man üblicherweise den bekannten, ganzseitigen Dialog mit der beschwichtigenden Entschuldigung, etwas hätte leider nicht geklappt. Nicht so hier. Die Meldung erscheint ohne viel Drumherum und ohne Korrelationsid in roten Lettern direkt unterhalb der Angaben zu Erstellt/Geändert und dem Speichern-Button.
Das Anlegen von Listenelementen in besagter Liste funktioniert weiterhin problemlos – nur unangenehmerweise das Update nicht mehr.

Ein Blick ins ULS (Methodensignaturen auf das Wesentliche gekürzt) gibt ein wenig mehr Informationen preis:

Original error: Microsoft.SharePoint.SPException: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) 
---> System.Runtime.InteropServices.COMException: Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))    
 at Microsoft.SharePoint.Library.SPRequestInternalClass.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.Library.SPRequest.AddOrUpdateItem( /* --- snip --- */ )     -
-- End of inner exception stack trace ---    
 at Microsoft.SharePoint.SPGlobal.HandleComException(COMException comEx)    
 at Microsoft.SharePoint.Library.SPRequest.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.AddOrUpdateItem( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.UpdateInternal( /* --- snip --- */ )    
 at Microsoft.SharePoint.SPListItem.Update()    
 at Microsoft.SharePoint.SPListItem.ValidateUpdateListItem_Client( /* --- snip --- */ )    
 at Microsoft.SharePoint.ServerStub.SPListItemServerStub.InvokeMethod( /* --- snip --- */ )    
 at Microsoft.SharePoint.Client.ServerStub.InvokeMethodWithMonitoredScope( /* --- snip --- */ )

Hier erfährt man, wo die Exception geworfen wurde. Leider führt auch mit diesen detaillierteren Angaben eine Suche im Netz schnell in die Irre, was mir Grund und Anlass für diesen kurzen Post sein soll.
Gut gemeinte Tipps wie „iisreset“ oder „Liste löschen und neu anlegen“ über „Entfernen von Inhaltstypen lowlevel in der Config-DB“ bis hin zu „ein ernstzunehmendes Problem mit möglicherweise korrupten DLLs und man möge den 0x8000FFFF bitte nicht auf die leichte Schulter nehmen“ waren dabei nicht ernsthaft vielversprechend. Lediglich ein Hinweis auf einen Schreibfehler einer Feldbezeichnung in der Schema.xml hatte Potential.

Was ich noch erwähnen sollte: Die Liste ist Teil einer per WSP im SharePoint ausgerollten Solution mit deklarativ definierten Listen.

Die Lösung

Da es recht sicher war, dass der Fehler im Zusammenhang mit der Listendefinition stehen musste, schien die Eingrenzung des Fehlers sinnvoll. Durch das Löschen aller benutzerdefinierten Felder der Liste, bis ein Update wieder möglich war, konnte als Übeltäter ein Auswahlfeld (Choice-Field) identifiziert werden. Mit einem von Hand auf der Liste angelegten Feld gleichen Namens und Typs bestand das Problem nicht länger.

Die genaue Untersuchung der Feld-Definition in der Schema.xml der zugrundeliegenden Liste brachte die Ursache ans Licht.
Im Field-Element des Auswahlfelds war das optionale Attribut BaseType mit dem Wert  „Integer“ enthalten, mit welchem man explizit angeben kann, ob der Wert als Integer oder als Text persistiert werden soll.

In der Beschreibung des Attributs im Artikel der MSDN ist ersichtlich, dass die Verwendung des BaseTypes in Zusammenhang mit Choice- bzw. Auswahlfeldern nicht möglich ist:

BaseType | Optional. The BaseType attribute can be set to Integer, which stores values as integers, or to Text (default), which stores values as text. You cannot create integer base-type choice fields.

Dennoch spannend, dass sich ein dementsprechend definiertes Feld in einer Liste überhaupt anlegen und ein Listenelement damit erstellen lässt sowie dass dazu noch die eher spektakuläre, wenig sagende Fehlermeldung präsentiert wird.
Falls irgendjemand mal Lust hat herauszubekommen, warum ausgerechnet für Auswahlfelder die Option Integer nicht zulässig ist – ich würde mich über eine Antwort freuen.

SharePoint Bulk-Delete via PowerShell

1.000+ ListItems in einer SharePoint-Liste und die müssen alle weg – und zwar fix. Manchmal sind es Demo- oder Test-Daten und mal soll schlicht nur aufgeräumt werden. Was tun? Eine Art „TRUNCATE TABLE“ wäre schön. Wieder hilft hier die PowerShell mit wenigen Zeilen und geladenen SharePoint-Commandlets weiter.

DELETE ALL ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$lst.Items | % { $lst.GetItemById($_.ID).Delete(); }

Zwar muss man dediziert für jedes ListItem die Delete-Methode rufen doch dafür verschwinden so zügig und unkompliziert die nicht länger benötigten Elemente aus SharePoint-Listen oder Bibliotheken.

Noch etwas interessanter wird der auf den ersten Blick nicht übermäßig elegant anmutende Ansatz für ein selektives Massen-Löschen…

DELETE SOME ListItems

$web = Get-SPWeb <URL zum Web>
$lst = $web.Lists[„<Name der Liste>“]
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = „<Where><Eq><FieldRef Name=’Project‘ LookupId=’TRUE‘ /><Value Type=’Lookup‘>23</Value></Eq></Where>“
$lst.GetItems($query) | % { $lst.GetItemById($_.ID).Delete(); }

Mit Hilfe einer CAML-Abfrage holt man sich nur die ListItems, die man löschen möchte. Auf dem SPList-Objekt findet man die Methode GetItems(), welches als Parameter ein SPQuery-Objekt entgegennimmt. Im Beispiel oben sind ListItems zu löschen, die mit einem Projekt-Datensatz in einer zweiten Liste verknüpft sind, welcher auf die ID 23 hört.

Wer nun Freude am Löschen per PowerShell findet, für den habe ich hier noch ein paar CAML-Query Beispiele zusammengetragen, welche vielleicht die ein oder andere Idee zur eigenen Adaption bringt…

# ** Query-Beispiel: ListItems, deren ID kleiner als 250 ist
$query.Query = „<Where><Lt><FieldRef Name=’ID‘ /><Value Type=’Counter‘>250</Value></Lt></Where>“

# ** Query-Beispiel: ListItems, die am oder nach dem 01.01.2016 angelegt wurden
$query.Query = „<Where><Geq><FieldRef Name=’Created‘ /><Value IncludeTimeValue=’FALSE‘ Type=’DateTime‘>2016-01-01</Value></Geq></Where>“

# ** Query-Beispiel: ListItems, die im Titelfeld mit ‚A‘ beginnen
$query.Query = „<Where><BeginsWith><FieldRef Name=’Title‘ /><Value Type=’Text‘>A</Value></BeginsWith></Where>“

# ** Query-Beispiel: ListItems, deren Beschreibungsfeld (‚Description‘) das Wort ‚Prozess‘ enthält
$query.Query = „<Where><Contains><FieldRef Name=’Description‘ /><Value Type=’Note‘>Prozess</Value></Contains></Where>“

# ** Query-Beispiel: ListItems, deren Aktiv-Flag auf FALSE gesetzt ist
$query.Query = „<Where><Eq><FieldRef Name=’Active‘ /><Value Type=’Boolean‘>0</Value></Eq></Where>“

Und wem das nicht weit genug geht – man kann nicht nur die Delete-Methode auf dem Objekt rufen…

LED Strip Connector mit eigenem Kabel anschließen

Heute mal thematisch etwas ganz anderes aus der Kategorie „Basteln“. Niedervolt LED-Strips haben hervorragende Eigenschaften, um mit minimalem Aufwand als Hintergrundbeleuchtung verbaut zu werden. Die Installation ist denkbar einfach und das Anschließen der Stromversorgung ist selbst für Hobby-Handwerker keine echte Herausforderung, wenn die Strips nicht gerade im Sichtfeld montiert werden sollen und man die passenden Verbinder zur Hand hat.

Kürzlich hatte ich das Problem, dass ich LED-Strips anschließen wollte, bei denen aus ästhetischen Gründen der Anschluss direkt in ein weißes Kabel übergehen sollte, welches ich sichtbar aber dezent am Türrahmen verlegen wollte. Im Lieferumfang fanden sich ein dickes, schwarzes Kabel mit vergossener Sockel-Buchse, eine etwas dünnere und angelötete Doppellitze in Rot und Schwarz sowie zwei Schnellverbinder, mit denen man hätte zwei Strips verbinden können. Grundsätzlich ausreichend – in meinem Fall allerdings keine brauchbaren Optionen, wenn nicht von den Türrahmen schwarze Kabelpeitschen mit Steckern baumeln sollten.

So fiel meine Wahl auf die Schnellverbinder, die eigentlich nicht zum Anschluss der Stromversorgung gedacht waren. Bleibt die Frage: Wie die Litze so einklemmen, dass sie auch nach dem Schließen des Schnellverbinders noch ausreichend Kontakt gibt, keinen Kurzschluss macht und nicht verrutscht?

LED-con_before

Nach einigen erfolglosen Versuchen, war ich bereits fast willens die Anschlüsse direkt auf die LED-Strips zu löten. Da kam mir die Idee, direkt aus den Kabelenden einen Verbinder zu formen, der unter die beiden Kontakte passt und nicht verrutscht.

LED-con_prep1

Die von der Isolierung befreiten Enden zog ich etwas auseinander, so dass die Litze ein flaches und breites Bündel bildete (1). Anschließend verzinnte ich die Bündel mit ausreichend Flussmittel (2). Trotz des vorherigen Auseinanderziehens waren die Enden noch viel zu dick, um unter die Kontakte zu passen.

LED-con_prep2

Um die Enden nun entsprechend flach zu formen, presste ich die Enden mit Hilfe eines Feinmechaniker-Schraubstocks auf die benötigte Stärke, in etwa einen viertel Millimeter und schnitt anschließend überschüssiges Material ab, um die Kontaktflächen zu bilden (3). Wer keinen Schraubstock zur Hand hat, könnte auf eine ausreichend starke Zange, Schraubzwingen oder im Notfall auch auf einen Hammer zurückgreifen. Um nun unter den Kontakten nicht zu verrutschen, hilft noch eine leichte Körnung in der Mitte der entstandenen Kontaktfläche (4).

Das Ergebnis erfüllt seinen Zweck und ist in jedem Fall eine Alternative, wenn man gerade kein passendes Anschlussmaterial sondern nur den Schnellverbinder bei der Hand hat.

LED-con_after

Sicherheitshalber noch der Hinweis, dass sich diese Art des Anschlusses lediglich für feste, nicht bewegte Installationen sowie für die 2-Pin-Variante sinnvoll anbietet, da nur der zweipolige Schnellverbinder (10mm) über ausreichend Platz zur Aufnahme der gelöteten Kontaktflächen bietet.
Obwohl auf Grund der geringen Spannung die Luftstrecke vernachlässigbar ist, sollte ein Abstand von mindestens einem Millimeter zwischen den Kontakten eingehalten werden, um Fehler zu vermeiden. Und zu guter Letzt: Jeder bastelt auf eigene Verantwortung. Gewissenhaftes Arbeiten bei der Herstellung und Klemmung der Kontakte ist dementsprechend wichtig – wer sich unsicher ist, sollte auf Anschlussmaterial der Hersteller zurückgreifen.

RSSharePointList-CAML-Hacks

Möchte man mit wenig Aufwand auf SharePoint-Listen mit Hilfe der SQL Server Reporting Services zugreifen, so kommt man am Datenquellen-Verbindungstyp für SharePoint-Listen nicht vorbei.
Dieser Verbindungstyp, auch bekannt als RSSharePointList bzw. SharePoint List Connection Type (Data Extension/Data Provider), ermöglicht einen einfachen Zugriff auf einzelne SharePoint-Listen eines SharePoint-Webs.

rssplist_smpl1

Konkret wird dabei ein SharePoint-Web bzw. eine SiteCollection mit einer SSRS-DataSource abgebildet, wohingegen ein SSRS-DataSet eine SharePoint-Liste repräsentiert.

rssplist_smpl2

Mittel eines Abfrageassistenten, der alle Listen/Bibliotheken eines Webs auflistet und darin enthaltene Spalten für das zu erstellende DataSet zur Auswahl anbietet, ist eine Definition der Reportdatenquelle schnell zusammengeklickt.

rssplist_smpl3

Heraus kommt eine XML-Struktur, eingeleitet mit dem Tag <RSSharePointList>, welches dem Entwickler mit SharePoint-Erfahrung bereits vertraut vorkommen könnte. Spätestens dann, wenn man noch eine Abfragebedingung im Assistenten hinzufügt, sind die Parallelen zu CAML, der in der SharePoint-Welt gängigen Collaborative Application Markup Language, nicht zu leugnen.

So weit, so gut. Solange man mit dem auskommt, was der Abfragedesigner zu leisten vermag, ist der BI-Analyst zufrieden. Letztendlich ist das oben Beschriebene ein alter Hut und die Nachfolgetechnologien stehen lange in den Startlöchern. Dennoch – SSRS und SharePoint sind auch 2016 noch ein Thema und es gibt Situationen, in denen man schneller als erwartet an Grenzen stößt. Ganz besonders dann, wenn man an den Komfort von der Flexibilität von SQL-Statements gewohnt war, um die Daten in eine für den Report sinnvolle Form zu bringen.

Hier wird es eng…

  • Sortieren von DataSets bereits zur Abfrage (Äquivalent zum SQL ORDER BY)
  • Arbeiten mit Referenzen auf andere SharePoint-Listen bzw. Listenelemente
  • Arbeiten mit Referenzen aus MultiValue-Lookups

Das grundlegende Problem wird bereits im Abfragedesigner deutlich. Eine Abfrage, ein DataSet. Sobald eine zweite Liste ausgewählt wird, erinnert eine Messagebox daran, dass die bisherige Auswahl verworfen wird. In nativem CAML wären JOINs möglich – nicht so mit RSSharePointList. Benötigt man nun Daten des referenzierten Datensatzes aus einer zweiten Liste, ist man darauf angewiesen, die zweite Liste ebenfalls als DataSet einzubinden und mittels Lookup-Funktion der Reporting Services dort einzelne Spalten abzuholen. Dies wird zudem noch erheblich erschwert, dass man mit dem Anzeigenamen des referenzierten Datensatzes und nicht mit der ID arbeiten muss, dass die ID hinter dem SharePoint Lookup-Feld nicht im DataSet erscheint.

Hier kommt man weiter…

Sortieren

Glücklicherweise ist im Rahmen von Berichtselementen wie Diagrammen oder Tabellen bzw. Tabellengruppen das Sortieren vorgesehen, so dass man selten die Notwendigkeit hat, dies bereits zur Abfragezeit zu berücksichtigen. Bei Parametern allerdings, deren Daten auf einer Abfrage basieren, ist dies der einzige Weg, da das DataSet selbst keine Sortierung kennt.
Da uns die Ähnlichkeit zu CAML aufgefallen ist, ist es naheliegend das Sortier-Konstrukt aus eben dieser Notation im SSRS Data Provider zu testen. Unterhalb des Query-Elements kann man das OrderBy-Element verwenden…

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>SortTest</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="Category" />
    <FieldRef Name="DueDate" />
    <FieldRef Name="ID" />
  </ViewFields>
  <Query>
    <OrderBy>
      <FieldRef Name="Category" />
      <FieldRef Name="DueDate" Ascending="FALSE" />
    </OrderBy>
  </Query>
</RSSharePointList>

Referenzen

Hat man innerhalb von SharePoint seine Datenstrukturen rein relational und vollständig 1:n aufgebaut, sprich ohne die Verwendung von Multi-Lookup-Spalten, so will man häufig nur eine Liste anhand einer ID filtern, die aus z.B. einem Report-Parameter stammt oder einem Übergabeparameter für einen Sub-Report dient.
Im Standard kommt man mit der allerdings nicht besonders weit, denn das Where-Element enthält nur einen einfachen, String-basierten Vergleich, der lediglich das Filtern auf Anzeigenamen ermöglicht. Sicherlich ist dies eine Alternative, solange der Titel sich nie ändert und über die gesamte Zeit eindeutig ist. Von diesen idealen Bedingungen kann man aber nicht immer ausgehen.
Ein einfacher Trick aus der CAML-Welt hilft hier weiter: Das Setzen des Attributs LookupId auf TRUE am FieldRef-Element im Query ermöglicht das Nachschlagen per ID.

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>Task</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="ProjectName" />
    <FieldRef Name="ScheduledDate" />
    <FieldRef Name="ActualDate" />
    <FieldRef Name="ID" />
  </ViewFields>
  <Query>
    <Where>
      <Eq>
        <FieldRef Name="ProjectName" LookupId="TRUE" />
        <Value Type="Lookup">
          <Parameter Name="ProjectId" />
        </Value>
      </Eq>
    </Where>
  </Query>
</RSSharePointList>

Innerhalb von Listen mit Referenzen auf andere Listen steht man vor einem ähnlichen Problem. Möchte man hier die ID zum referenzierten Datensatz erhalten, hat man nur den zum Nachschlagefeld definierten DisplayName. Dieser hilft ebenfalls nur unter idealen Bedingungen weiter und dürfte sich nie ändern. Und auch hier: Entgegen der CAML-Dokumentation führt das LookupId-Attribut am FieldRef-Element im ViewFields-Element zum Erfolg.

<RSSharePointList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ListName>Task</ListName>
  <ViewFields>
    <FieldRef Name="Title" />
    <FieldRef Name="ProjectName" LookupId="TRUE" />
    <FieldRef Name="ScheduledDate" />
    <FieldRef Name="ActualDate" />
    <FieldRef Name="ID" />
  </ViewFields>
</RSSharePointList>

…leider mit der Einschränkung, dass man sich für ID oder DisplayName des Lookups entscheiden muss.

…und hier hört es auf

  • CAML-Join
  • CAML-Group
  • CAML-RowLimit
  • Multi-Lookup Columns

rssplist_failed

Frohes Reporten weiterhin!