Welcome to MSDN Blogs Sign in | Join | Help

Partner Day : Développer autour de CRM 4.0

Pour cette nouvelle année 2009, nous relançons les Partner Days, la première de cette série a été jouée ce Mardi 20 Janvier pour nos partenaires Gold et/ou ISV Certified & Registered dans le cadre de leurs heures de conseil (respectivement 40, 15 & 10 heures par an).

Nous avons pu accueillir 16 partenaires dans notre salle de formation composée désormais de machine Windows Server 2008 avec Hyper-V et 8 Go de RAM.

Manifestement, la journée a été encore une fois appréciée puisque nous avons obtenu les scores suivants :

Intervenants 8,57/9
Satisfaction Générale 8/9
Impact Métier 8/9

Nous remercierons donc les 1ers participants pour leurs retours encourageants ! Grâce à ces résultats probants, nous sommes déjà en train d'organiser une seconde session pour satisfaire les personnes qui étaient en liste d'attente.

Le thème était donc 'Développer autour de CRM 4.0'. Nous avions fait le choix de ce thème car la version pour CRM 3.0 avait été très appréciée et demandée. C'est aussi une demande récurrente de nos partenaires.

Les catégories de personnes visées sont :

  • Les chefs de projets ou directeurs technique cherchant à mieux comprendre les possibilités de développement autour du produit.
  • Les développeurs cherchant à connaître toutes les facettes du développement autour du CRM 4.0.

N’hésitez donc pas à revenir vers nous si vous souhaitez participer à la prochaine session qui devrait tomber à la fin du mois de Février. D'ailleurs, nous essaierons de rejouer cette journée autant de fois que possible.

Enfin, je remercie sincèrement Kelvin Lonfat, notre stagiaire ‘développement nouvelles technologies’(vous trouverez une partie de son travail sur http://blogs.msdn.com/paf), et Rémi Boigey sans qui la journée n’aurait pas pu se faire J

clip_image001clip_image002clip_image003

Pierre-Adrien                                    Rémi                                Kelvin - songeur

Nous allons bientôt vous annoncer les dates des prochaines journées qui seront SilverLight et Windows Communication Foundation - WCF.

Je vous propose de regarder l’agenda de cette Partner Day :

01 - Présentation du SDK – 180 min

Nous voulions commencer par le SDK car c’est la base d’un bon développement autour de CRM 4.0.  Nous commençons par l’architecture, puis nous nous attardons sur l’environnement et les outils de développement. Ensuite, nous détaillons les Web Services CRM.

clip_image004 clip_image005

Enfin, nous présentons longuement le JavaScript dans CRM – « le supporté comme le non supporté ». 

Pour terminer sur la partie dédiée aux ISV et à la mobilité.

02 – Plugins – 75 min

C’est une part importante de la personnalisation de votre CRM. Rémi explique en profondeur le fonctionnement et l’utilisation en mode offline. C’est l’occasion pour nos participants de faire un plugin à travers un lab expliquant les manipulations pas à pas.

clip_image006 clip_image007

03 - Workflows – 75 min

Les Workflows sont souvent suffisants via l’interface CRM mais parfois il est très utile de savoir créer une activité de Workflow personnalisée. Après une explication de Rémi sur les Workflows dans CRM 4.0, les participants ont fait un exercice pratique sur les machines mises à disposition.

clip_image008 clip_image009

04 - Présentation des accélérateurs CRM – 60 min

Suite à la sortie des accélérateurs pour CRM 4.0 en décembre, nous avons trouvé logique de leurs dédier une place durant la journée. Nous avons effectué une série de démonstrations fonctionnelles et techniques afin de montrer les éléments de développement mis à disposition par Microsoft.

clip_image010 clip_image011

05 – SQL Reporting Services – 90 min

Les rapports Reporting Services sont une part importante d’un CRM. Nous présentons donc ici les différentes solutions pour créer simplement des rapports complexes.

Report Builder 2.0 est présenté avec la série des nouvelles fonctionnalités SQL Reporting Services 2008.

Nous évoquons aussi le passage de paramètre entre CRM 4 .0 et SRS 2008. Nous commentons aussi des rapports que nous avons développés pour vous.

clip_image012 clip_image013

Nous avons essayé de préparer l’ensemble pour que le contenu fourni en fin de journée vous permette une réutilisation maximum au sein de vos propres environnements de développement. Si vous ne pouvez pas assister à cette journée et qu’une partie du contenu vous intéresse, n’hésitez pas à nous contacter.

 

Pierre-Adrien FORESTIER aka PAF
http://blogs.msdn.com/paf

Posted by pafore | 1 Comments

Lancement de mon blog perso

Bonjour à tous,

  Je vais bientôt changer de fonction, je vais donc laisser le relais à mes collègues pour continuer de faire vivre ce blog. J'espère que certains posts vous auront été utiles! :)

  Vous pourrez désormais me rendre visite sur http://blogs.msdn.com/davrous pour la suite des aventures.

A bientôt, 

David

Posted by davrous | 0 Comments

Exemple de code permettant une extraction des permissions MAPI & AD d'une OU complète vers un fichier .CSV pour Exchange 2003

Je me permets de partager avec vous un exemple de code qui peut se révéler pratique dans certains cas.

 

Cet exemple de code devrait vous permettre d’extraire l’ensemble des permissions MAPI mises en place sur les dossiers d’une BAL (Calendrier, Inbox, etc.) ainsi que l’ensemble des permissions de l’AD qui nous intéresse en général dans une optique Exchange (‘Send As’, ‘Receive As’, etc.). Le tout est donc synthétisé dans un fichier .CSV facilement exploitable dans Excel. L’idée est ainsi de pouvoir vérifier rapidement les différentes délégations mises en place par les utilisateurs. Ce code vise plutôt une architecture basée sur du Exchange 2003. Il existe quelque chose de similaire pour Exchange 2007 ici : http://gsexdev.blogspot.com/2008/04/exchange-permission-and-reverse.html en Powershell.

 

La pièce jointe ExtractMAPIPermissionsAndActiveDirectoryPermissions.zip contient les éléments suivants:

 

-          La version script VBS du code à utiliser : ExtractMAPIPermissionsAndActiveDirectoryPermissions.vbs

-          Le projet VB6 ayant servi de base pour la réalisation du script (pour rappel VB6 n’est plus supporté depuis Avril 2008)

-          La DLL acl.dll à enregistrer sur la machine cible (via regsvr32.exe)

-          Un exemple de résultat en .csv puis en .xlsx de la sortie générée par le code.

 

Je tiens à vous préciser que ce code ne constitue qu'un exemple et n'est pas supporté en tant que tel. Vous devez notamment être en mesure de lire, comprendre & modifier ce code avant toute mise en production.

 

Pour fonctionner, ce code a besoin des pré-requis suivant :

 

1 - CDO 1.21 (CDO.DLL) disponible avec Outlook 2003/Exchange 2003 sinon à télécharger ici:  http://www.microsoft.com/downloads/details.aspx?familyid=2714320d-c997-4de1-986f-24f081725d36&displaylang=en pour les postes Outlook 2007/Exchange 2007.

 

2 - ACL.DLL : à enregistrer sur la machine via la commande "regsvr32.exe acl.dll"

 

3 - Le code doit tourner sous l'autorité d'un compte ayant les droits d'ouverture de session MAPI sur l'ensemble des BALs visées (pour l'extraction des permissions sur les différents dossiers MAPI)

 

Utilisation du script :

 

cscript ExtractMAPIPermissionsAndActiveDirectoryPermissions.Vbs CHEMIN_LDAP_VERS_OU CHEMIN_VERS_LE_FICHIER_CSV

 

Exemples:

 

- cscript ExtractMAPIPermissionsAndActiveDirectoryPermissions.Vbs * c:\ExchangeRights.csv

                               --> Extrait l'ensemble des permissions MAPI & AD sur l'ensemble des utilisateurs de l'organisation (RootDSE)

                --> dans le fichier 'c:\ExchangeRights.csv'

 

- cscript ExtractMAPIPermissionsAndActiveDirectoryPermissions.Vbs LDAP://DAVROUS2k3.COM/OU=BatchClient,DC=davrous2k3,DC=com c:\temp\test.csv

 --> Extrait l'ensemble des permissions MAPI & AD des utilisateurs du chemin LDAP suivant:

                --> 'LDAP://DAVROUS2k3.COM/OU=BatchClient,DC=davrous2k3,DC=com' dans le fichier 'c:\temp\test.csv'

 

Vous retrouverez cette description en lançant le script sans paramètre ou avec le mauvais nombre de paramètres.

 

Vous avez donc 2 possibilités :

 

1 – Lancer le code sur l’ensemble de votre organisation (via l’opérateur * pour le 1er paramètre)

2 – Lancer le code que sur une OU particulière en précisant le chemin LDAP complet vers celle-ci en 1er paramètre.

               

Une fois le code lancé, voici un exemple de résultat :

 

1 – Sortie dans la commande :

 

 

On voit ici la logique du code. Pour chacun des utilisateurs de l’OU visée par le code :

 

-          On commence par effectuer une ouverture de session MAPI vers la boîte aux lettres de l’utilisateur pour en extraire les permissions « Outlook » au niveau de chacun des dossiers (Boîte de réception, Calendrier, etc.) à utilisation de CDO 1.21 & ACL.DLL sur cette partie. Ce sera la partie la plus couteuse en terme de performance.

-          On enchaîne en tentant de récupérer une liste de délégués pour le droit « Envoyer de la part de » (issue de l’attribut publicDelegates de l’AD). Ce droit "Send On Behalf" est stocké dans l'onglet "Exchange General" --> "Delivery Options"

-          Ensuite, on regarde si des utilisateurs disposent des droits « Send-As », « Receive-As » ou de droits personnalisés. Ces droits sont stockés dans l’attribut ntSecurityDescriptor.

-          Pour terminer, on vérifie si des utilisateurs disposent du droit « Full Mailbox Access ».  Ce droit est stocké dans l’attribut msExchMailboxSecurityDescriptor.

 

2 – Ouverture du fichier .CSV dans Excel 2007 et exemple de possibilités de filtrage sur le résultat. Ici on filtre pour l’afficher que ceux qui ont un droit de type « Full Mailbox Access » :

               

 

Note: je récupère les délégués depuis l’AD à travers l’attribut "publicDelegates". Attention la liste n’est pas forcément complète. Quand l’utilisateur n’a pas accès en écriture, Outlook ne met rien dans l’attribut et ne lève pas forcément de message d’erreur ni n’empêche le delegate wizard de se terminer. Il faudrait donc éventuellement envisager de récupèrer la liste à partir du message LocalFreebusy dans le dossier FreebusyData de la boite.

 

Voici les propriétés MAPI à considérer:

 

#define PR_DELEGATE_NAMES                            PROP_TAG(PT_MV_STRING8,0x6844) //Outlook 2003

#define PR_DELEGATE_NAMES2                           PROP_TAG(PT_MV_STRING8,0x684A) //Outlook 2007

 

Enjoy !

 

-= David =-

Partner Day: initiation au développement sous SharePoint

Le 19 juin, nous avons organisé une nouvelle journée « Partner Day » pour nos partenaires Gold et nos partenaires ISV Certified & Registered dans le cadre de leurs heures de consulting (respectivement 40, 15 & 10 heures par an). Nous avons donc pu accueillir 16 partenaires, taille limite de notre salle de formation. Manifestement, la journée a été appréciée puisque nous avons obtenu un score moyen de 8.2/9 comme note générale lors des évaluations et 8.3 sur la partie « impact sur votre business ». Nous remercierons donc les 1ers participants pour leurs retours encourageants ! J

Je tiens à remercier également mon ami et ancien collègue de Microsoft Julien Bakmezdjian pour nous avoir grandement aidé à la réalisation de cette journée et à sa participation active. Retrouvez le sur le site de sa propre entreprise : http://www.baktek.fr

Le thème de cette nouvelle journée fut l’initiation au développement sous SharePoint. C’est en effet un besoin récurrent et important au près de notre population de développeurs. Cette initiation vise plusieurs catégories de personnes :

-          Les chefs de projets ou directeurs technique cherchant à mieux comprendre les possibilités de développement autour du produit WSS

-          Les développeurs cherchant à débuter le développement sur cette même technologie

Nous avons planifié de faire une autre journée le 1er juillet mais cette dernière est déjà remplie. Nous sommes donc en train de planifier une 3ème journée ! N’hésitez donc pas à revenir vers nous si le concept vous intéresse. Nous essaierons de rejouer cette journée au tant de fois que possible.

Rémi

David

La salle de formation avec 16 machines disponibles

Julien

Pierre-Adrien surveille l’ensemble ! J

 


Je vous propose de regarder l’agenda de cette Partner Day :

01 - Présentation Générale (30 min)

Nous commençons par passer en revue les différences fonctionnelles, techniques et de licences entre Microsoft Office Sharepoint Server (MOSS) 2007 et Windows SharePoint Services (WSS) 3.0.

On y découvre également une vue d’ensemble des différentes possibilités de personnalisations graphiques et de développement autour des 2 produits.

02 – WebService (30 min)

Nous découvrons ici comment consommer les WebServices exposés par WSS 3.0. Une démo est effectuée et un lab complet est remis pour que vous puissiez rejouer l’ensemble chez vous plus tard.

03 - Object Model (90 min)

Ici, nous regardons comment :

1 – Utiliser le modèle objet depuis une application de type Winform C#
2 – Utiliser le modèle objet depuis ASP.NET avec les particularités du concept du répertoire « /_layouts » de SharePoint.
3 – Utiliser le modèle objet depuis une CmdLet PowerShell.

Vous aurez à votre disposition l’ensemble du code source associé et vous implémenterez vous-même la page ASP.NET sur les machines virtuelles.

      Application d’un thème ‘vintage’ via un script

PowerShell PS1

 


04 – Feature (15 min)

Comme vous le découvrirez, tout est « feature » dans SharePoint. Nous voyons ici comment installer un nouvel élément dans le menu « Settings » pointant sur un projet réalisé en 03.

05 – WebPart (90 min)

Ensemble, nous allons créer un WebPart avec Visual Studio 2005 et les extensions WSS. Ce WebPart utilisera le modèle objet pour créer une nouvelle tâche via un bouton et affichera le résultat de la création dans un label. Ensuite, nous modifierons ce même WebPart pour configurer la couleur d’affichage du résultat à travers le panneau de configuration de droite pour les WebPart.

Nous verrons alors comment débugger ce WebPart en nous attachant au bon process w3wp.exe et nous vous expliquerons comment éviter le piège du « double saut ».

Vous trouverez également un beau Lab de 1 heure à faire chez vous où vous pourrez :

1 – Créer un WebPart avec action pane comme dans la démo
2 – Créer un WebPart basé sur un User Control (plus pratique à « designer »)
3 – Créer un WebPart filtrant les données en étant connecté à un autre WebPart affichant une liste importée depuis un fichier Excel 2007.

Ce lab étant disponible à la fois en C# et VB.NET

Pour terminer, nous verrons comment intégrer un WebPart utilisant la technologie Silverlight 2.

              Utilisation d’un WebPart Silverlight 2 connecté à une « Picture Librairies » de WSS

06 - Event Receiver (30 min)

Comme le dit souvent Julien, les « Event Receiver » sont à considérer avant d’envisager un Worflow bien plus complexes à mettre en œuvre. Ici nous verrons comment mettre en place un gestionnaire d’évènements sur une librairie de documents. Cet « Event Receiver » s’occupera alors, de manière asynchrone, de renommer les documents postés selon une nomenclature prédéfinie. C’est un besoin récurrent soumis au près de Microsoft.

07 – Workflow (180 min)

La plus grosse partie de cette journée. C’est également ici que vous aurez le plus de contenus pour vous aider à rejouer tout cela chez vous.

Nous vous proposons tout d’abord un Lab de 30 min à faire chez vous permettant de créer un petit Workflow sous SharePoint Designer.

Un Worflow à état réalisé par Julien simulant une candidature au près de la RH vous sera présenté en détails. Le Lab étant décrit dans un document Word et le code source vous sera fourni.

 Par ailleurs, un dernier Lab réalisé par Rémi vous propose de mettre en place un Worflow séquentiel sous Visual Studio 2008. Vous le réaliserez vous-même sur la machine virtuelle pendant 1 heure.

Pour terminer, Rémi vous présentera une extension du Worflow séquentiel mis en place à travers le Lab 03 pour y ajouter une personnalisation des formulaires d’initiation et d’association du Worflow. Vous y trouverez également une tâche personnalisée d’un Worflow accompagné d’un formulaire personnalisé d’édition.  Tout cela pour simuler une application de demande de congés au sein de WSS.


Nous avons essayé de préparer l’ensemble pour que le contenu fourni en fin de journée vous permette une réutilisation maximum au sein de vos propres environnements de développement. Si vous ne pouvez pas assister à cette journée et qu’une partie du contenu vous intéresse, n’hésitez pas à nous contacter pour que l’on puisse vous le fournir en échange d’une partie de vos heures de consulting.

-= David =-

Procédure pour installer le Webpart Silverlight 2 HelloWord pour Sharepoint

Vous connaissez peut-être déjà les superbes démos proposées par le site suivant : « Microsoft Silverlight BluePrint for SharePoint » : http://www.ssblueprints.net/sharepoint/ . L’idée est d’intégrer la puissance et les possibilités graphiques de Silverlight (sous ensemble de WPF) dans MOSS ou WSS. Une bonne idée de ce que cela pourrait donner est par exemple le WebPart « Colleague Viewer » proposé sur le même site en vidéo. Cela ressemble furieusement à l’exemple que je vous ai présenté à travers ActiveDirectory.Show mais utilisant les Webservices (comme le UserProfileService() de MOSS 2007) pour récupérer les informations sur vos collègues. Cela donne ce genre de chose :

Avant d’en arriver là, il serait peut-être bon de déjà réussir à faire fonctionner le bon vieux HelloWorld dans le monde WebPart/Silverlight non ? Et bah, ce n’est pas forcément si facile à mettre en place. Aussi je vous propose de vous indiquer les marches que j’ai du suivre pour y arriver de mon coté. Logiquement, cela devrait vous aider si vous rencontrez l’erreur suivante en tentant ajouter le WebPart à votre site : « Silverlight BluePrint for SharePoint: Hello Silverlight 2 Web Part: Could not load file or assembly ‘System.Web.Silverlight, Version = 2.0.5.0, Culture=neutral, PublicKeyToken=blabla’ or one of its dependencies. The system cannot find the file specified »


Etape 1 : les briques de base de votre maquette

Personnellement, j’ai travaillé avec une machine virtuelle Windows 2003 R2 SP2. Pour bien commencer, il faut que votre machine dispose des composants suivants :

-          MOSS 2007 ou WSS 3.0 avec le SP1

-          Visual Studio 2008 RTM


Etape 2 : les couches nécessaires à Silverlight 2 beta 1

Avant toute chose, il faut impérativement que vous n’ayez pas installé le SDK de Silverlight 2 ou la runtime en elle-même sur la machine Sharepoint. Si c’est déjà le cas, commencez par désinstaller ces 2 composants. Ensuite, installez l’extension à VS 2008 suivante : « Microsoft Silverlight Tools Beta 1 for Visual Studio 2008 » : http://www.microsoft.com/downloads/details.aspx?FamilyId=E0BAE58E-9C0B-4090-A1DB-F134D9F095FD&displaylang=en qui s’occupera alors d’installer gentiment le SDK et la Runtime de Silverlight 2 Beta 1.


Etape 3 : créez un projet de type Silverlight application

Créez un projet de type Silverlight application (projet qui sera disponible grâce à l’étape précédente) par défaut. L’idée sera alors de récupérer les sections du web.config généré pour les insérer dans le web.config de votre site WSS.

Toutes les sections à récupérer se trouvent ici : http://www.zimmergren.net/archive/2008/03/19/how-to-get-up-and-running-with-the-silverlight-2-0-blueprints-for-sharepoint-2007.aspx

Par ailleurs, cette charmante personne a eu la bonne idée de montrer les étapes complètes en vidéo : http://www.u2u.info/Blogs/Patrick/Lists/Categories/Category.aspx?Name=Silverlight%20BluePrint

C’est long à suivre mais cela marche au moins !


Etape 4 : installez System.Web.Silverlight.dll dans le GAC

Cette procédure m’a bien aidé : http://grumpywookie.wordpress.com/2008/03/26/getting-started-with-silverlight-blueprint/

Voici ce qu’il faut donc faire :

Inscrire dans le GAC le fichier System.Web.Silverlight.dll depuis « C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server » vers « C:\windows\assembly » avec l’explorateur Windows.


Etape 5 : Enregistrez le type MIME « .Xap » dans IIS

Dans la console d’administration d’IIS (inetmgr.exe), naviguez au niveau de votre site WSS. Dans les propriétés du site, rendez-vous dans l’onglet « HTTP headers ». Ensuite : « MIME Types… ». Ajoutez une nouvelle extension de type « .xap » associée à « application/x-silverlight-2-b1 ».


Etape 6 : lancez le setup du WebPart HelloWorld

Next à Next à Next…


Etape 7 : Copiez le fichier Silverlight.js dans ClientBin

Au passage, si vous voulez faire fonctionner l’autre WebPart HelloWorld qui utilise un container pour des applications Silverlight 1.0 ou 2, vérifiez également le répertoire « /ClientBin » de votre site SharePoint. Si le fichier « Silverlight.js » n’y est pas, copiez-le depuis « C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Tools. »


Etape 8 : Recompilez le projet du WebPart

Vous êtes pressé de voir le résultat hein ? J Allez, encore un dernier petit effort pour y arriver.

Après avoir récupéré le package complet du Sample 1 appelé « Hello Silverlight Web Parts ans the SilverlightPart » depuis le site http://www.ssblueprints.net/sharepoint/ , rendez-vous dans le répertoire : « HelloSilverlightSampleFullPackage\HelloSilverlightSampleSource\Sources_HelloSilverlight2\SL.XAML.HelloSilverlight2 » et ouvrez le projet « .csproj » dans Visual Studio 2008.

Recompilez et récupérez le résultat de la compilation pour le copier/coller dans le répertoire « \ClientBin\SL.HelloSilverlight2 » de votre site. Chez moi, il se trouve ici : «  C:\Inetpub\wwwroot\wss\VirtualDirectories\80\ ».


Etape 9 : Activez la feature et ajoutez (enfin !) le WebPart à votre site

Pour cela, il suffit de suivre la vidéo du site BluePrint montrant en détail les étapes à suivre. Et enfin, je peux cliquer sur mon bouton vectoriel Silverlight 2 !!!

 


Enjoy !

-= David =-

Transformez l’application Family.Show afin d’afficher l’organigramme d’une entreprise issu de l’Active Directory

Pendant mon auto-formation sur WPF, je me suis amusé à modifier le code de Family.Show de Vertigo disponible sur Codeplex pour le rendre exploitable sur un annuaire d'entreprise Active Directory. L'idée était de faire quelque chose de joli (merci WPF ! :)) ET pratique dans le monde de l'entreprise.

Voici un exemple de résultat:

Je vous propose de découvrir tout cela sur l'article MSDN expliquant la démarche que j'ai suivi : http://msdn.microsoft.com/fr-fr/netframework/cc563816.aspx Vous y retrouverez également une vidéo de démonstration.

Je prépare un workshop autour de la technologie WPF utilisée dans cette démo pour les partenaires Gold & Certified ISVs. Nous y découvrirons alors ensemble comment réaliser ce type d'applications.

Stay tuned!

-= David =-

Code C# utilisant WebDAV pour calculer la taille d'une boîte aux lettres Exchange 2000/2003

Voici un code en C# qui vous permettra d'obtenir la taille d'une boîte aux lettres Exchange. Le résultat retourné est identique à celui que vous retrouvez dans l'ESM (Exchange System Manager).

Ce code reprend simplement le code proposé dans cet article technique : http://support.microsoft.com/default.aspx?scid=kb;en-us;320071

Sous Visual Studio, créez une solution de type "Console Application" appélée RecursiveLoopFolders, ajoutez une classe que vous nommerez WebDAVSize.cs. Copier/coller dans cette classe le code suivant:

using System;

using System.Net;

using System.IO;

using System.Text;

using System.Xml;

 

namespace RecursiveLoopPublicFolders

{

      public class WebDAVSize

      {

            static public long FolderSize(string URL, string userName, string userPassword, string userDomain)

            {

                  System.Net.HttpWebRequest Request;

                  System.Net.WebResponse Response;

                  System.Net.CredentialCache MyCredentialCache;

                  string strQuery ="";

                  byte[] bytes = null;

                  System.IO.Stream RequestStream = null;

                  System.IO.Stream ResponseStream = null;

                  XmlDocument ResponseXmlDoc = null;

                 

                  XmlNodeList oXMLSizeNodes = null;

                  XmlNodeList oXMLHREFNodes = null;

                  XmlNodeList oXMLHasSubsNodes = null;

                  long totalSize=0;

 

                  try

                  {

                        strQuery = @"<?xml version=""1.0""?>";

                        strQuery += @"<g:searchrequest xmlns:g=""DAV:"">";

                        strQuery += @"<g:sql>SELECT ""http://schemas.microsoft.com/";

                        strQuery += @"mapi/proptag/x0e080003"", ""DAV:hassubs"" FROM SCOPE ";

                        strQuery += "('SHALLOW TRAVERSAL OF \"" + URL + "\"') ";

                        strQuery += @"WHERE ""DAV:isfolder"" = true";

                        strQuery += @"</g:sql>";

                        strQuery += @"</g:searchrequest>";

 

                        MyCredentialCache = new System.Net.CredentialCache();

                        MyCredentialCache.Add( new System.Uri(URL),

                             "NTLM",

                             new System.Net.NetworkCredential(userName, userPassword, userDomain)

                             );

 

                        Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(URL);

                        Request.Credentials = MyCredentialCache;

                        Request.Method = "SEARCH";

                        bytes = Encoding.UTF8.GetBytes((string)strQuery);

                        Request.ContentLength = bytes.Length;

                        RequestStream = Request.GetRequestStream();

                        RequestStream.Write(bytes, 0, bytes.Length);

                        RequestStream.Close();

                        Request.ContentType = "text/xml";

                        Request.Headers.Add("Translate", "f");

                        Request.Headers.Add("Depth", "0");

                        Response = (HttpWebResponse)Request.GetResponse();

                        ResponseStream = Response.GetResponseStream();

                        ResponseXmlDoc = new XmlDocument();

                        ResponseXmlDoc.Load(ResponseStream);

 

                        // Get the XML nodes that contain the individual sizes.

                        oXMLSizeNodes = ResponseXmlDoc.GetElementsByTagName("d:x0e080003");

 

                        oXMLHREFNodes = ResponseXmlDoc.GetElementsByTagName("a:href");

                        oXMLHasSubsNodes = ResponseXmlDoc.GetElementsByTagName("a:hassubs");

     

                        // Loop through the nodes, and then add all of the sizes.

                        for (int i=0; i < oXMLSizeNodes.Count; i++)

                        {

                             totalSize += long.Parse(oXMLSizeNodes.Item(i).InnerText);

                            

                             if (oXMLHasSubsNodes.Item(i).InnerText == "1")

                             {

                                   totalSize += FolderSize(oXMLHREFNodes.Item(i).InnerText, userName, userPassword, userDomain);

                             }

                        }

 

                        ResponseStream.Close();

                        Response.Close();

                       

                        return totalSize;

                  }

                  catch(Exception ex)

                  {

                        Console.WriteLine(ex.Message);

                        return 0;

                  }

            }

      }

}


Ensuite, voici le code de l'appelant:

[STAThread]

static void Main(string[] args)

{

      long totalSizeO;

      double totalSizeKO;

 

      string userName = "exchangesuperuser";

 

      totalSizeO = WebDAVSize.FolderSize("http://davrous2005/exchange/" + userName + "/NON_IPM_SUBTREE", "exchangesuperuser", "password!1", "DAVROUS2K3");

      Console.WriteLine ("******************************************");

      Console.WriteLine ("* TOTAL FINAL SIZE : " + totalSizeO + " Octets");

      totalSizeKO = totalSizeO/(double)1024;

      totalSizeKO = Math.Ceiling(totalSizeKO);

      Console.WriteLine ("* TOTAL FINAL SIZE : " + totalSizeKO + " KO");

      Console.WriteLine ("******************************************");

      Console.ReadLine();

}

Pour terminer, voici le résultalt sur le serveur Exchange 2003 vu plus haut:

Le résultat est bien identique.

-= David =-

 

Posted by davrous | 0 Comments
Filed under: , ,

Les "Store Event Sinks" d'Exchange 2003: introduction et guide de résolution des problèmes

Avant toute chose,  je vous invite à télécharger le SDK d’Exchange 2003 & 2007 :

 

-          Exchange 2003 : http://www.microsoft.com/Downloads/details.aspx?FamilyID=5ca18d40-5a37-4a20-94ae-6a6cf6cb846d&displaylang=en

-          Exchange 2007 : http://www.microsoft.com/downloads/details.aspx?FamilyId=190F71A4-7B5F-4A4C-99BA-9BD032E16E15&displaylang=en

 

Vous trouverez alors des exemples de code autour des store event sinks dans: \Exchange SDK\SDK\Samples\Events\VBEvents

 

Présentation générale des Store Event Sinks

 

Sous Exchange 2000/2003, un système de notification peut être géré via la technologie des « Store Event Sinks ». Ces derniers se modélisent sous la forme de composants tournant dans COM+ et capables de surveiller les opérations de sauvegarde ou de suppression dans le store Exchange sur une boîte aux lettres ou l’ensemble des boîtes aux lettres. Ces notions sont assez complexes pour quelqu’un qui débute et pourrait justifier un transfert d’expertise. Un point d’entrée intéressant dans le SDK est ici : http://msdn2.microsoft.com/en-us/library/ms879478.aspx & Exchange Store Event Sinks : http://msdn2.microsoft.com/en-us/library/aa142643.aspx

 

                Voici quelques exemples précis :

 

-          Implementing an OnSave Event Sink : http://msdn2.microsoft.com/en-us/library/ms992721.aspx

-          La documentation des exemples se trouve ici: http://msdn2.microsoft.com/en-us/library/ms878012.aspx

-          Pour terminer, voici les références complètes: http://msdn2.microsoft.com/en-us/library/ms992652.aspx

 

Scénario : utilisation d’un Store Event Sink Synchrone dit « Store Wide »

 

Si vous souhaitez surveiller l’ensemble des boîtes aux lettres d’un seul coup. Il faut alors utiliser les Event Sinks synchrones et dit « Store Wide ». Ces derniers sont un peu spéciaux et sont alors capable de surveiller l’ensemble du store Exchange d’un seul coup. Il faut alors faire très attention à son écriture car la moindre opération de sauvegarde/suppression générera son appel. Ce type de sink doit alors être particulièrement succins et rapide.

 

Voici les inconvénients :

 

-       Il faut impérativement que son traitement soit rapide car il bloque un des thread d’Exchange et peut impacter la performance globale du serveur de messagerie

-       Il faudra faire attention à ne pas rentrer dans une boucle infinie : un event sink « store wide » écoute toutes les opérations potentielles d’écriture. Donc le sink risque potentiellement de « s’auto-appeler » en boucle. Mais ce n’est finalement qu’un problème de logique d’implémentation

 

Son implémentation est envisageable en VB 6.0 avec une performance accrue en C++. Dans la mesure du possible, évitez .NET qui ajoute une couche d’interopabilité avec COM rendant l’ensemble moins performant qu’avec un langage COM pur comme C++ ou VB. Evitez ensuite comme la peste de le faire en VBScript. Malheureusement, comme vous le savez sans doute déjà, VB 6.0 n’est plus supporté à partir d’Avril 2008. Cela limitera donc les possibilités de développement autour d’Exchange à C++ et .NET .

 

Informations détaillées et exemples de code

 

-          Store Event Sink synchrone : http://msdn2.microsoft.com/en-us/library/ms877938.aspx

-          Méthode OnSyncSave pour les sinks Synchrones : http://msdn2.microsoft.com/en-us/library/ms992702.aspx

-          Registering for Store-Wide Events : http://msdn2.microsoft.com/en-us/library/ms878488.aspx  

-          Vous trouverez également des exemples de code en VB 6.0 et C++ dans le répertoire « Program Files\Exchange SDK\SDK\Samples\Events\ » suite à l’installation du SDK

 

Sur Exchange 2007, c’est une toute autre histoire. Les solutions de développement autour d’Exchange 2007 sont vraiment adaptées à notre plateforme .NET.  Les opérations effectuées jadis via CDO 1.21, MAPI, CDOEX, WebDAV & store event sinks sont remplacées par l’utilisation des WebServices. Les opérations d’administration (création de boîte aux lettres, gestion des stores, etc.) gérées avant via CDOEXM sont remplacées par des commandes PowerShell facilement appelable depuis un code .NET.

 

Voici 2 points d’entrée intéressants expliquant une solution basée sur l’utilisation des WebServices d’Exchange 2007 pour remplacer le concept de store event sinks d’Exchange 2003 :

 

-          Using Pull Notifications : http://msdn2.microsoft.com/en-us/library/aa579617.aspx

-          Push Notification Sample Application (Exchange Web Services) : http://msdn2.microsoft.com/en-us/library/bb204063.aspx

 

Pour terminer, pour vous aider, je vous ai également attaché un document qui se présente sur la forme d’un « guide » pour analyser les problèmes les plus classiques autour des Store Event Sinks (enregistrement dans COM+, problème d’exécution, méthode de débogage). Ce guide, en Anglais, s’appuie sur mes années d’expérience au support européen Microsoft en tant que développeur sur les solutions de messagerie Exchange & Outlook. J’espère qu’il vous sera utile !

-= David =-

Video du workshop ".NET Framework 3.0 Windows Communication Foundation (WCF)" disponible

Nous avons eu également de bons retours sur le workshop intitulé « .NET Framework 3.0 Windows Communication Foundation (WCF) ».

Nous avons eu malheureusement quelques soucis techniques sur l’enregistrement de la vidéo effectuée lors de la 1ère présentation. Je l’ai donc récemment enregistré à nouveau. Vous pouvez donc revenir vers moi pour me demander le lien vers celle-ci, l’accès  à la présentation au format pptx et aux exemples de code (projets VS 2008). Pour cela, envoyez moi un email à davrous@microsoft.com  .

Voici quel fut l’agenda :

-          Pourquoi WCF?

o   Historique, unification, pré-requis pour développer avec WCF

-          Introduction: SOA, principe ABC

o   Démo1: implémentation du service WCF

o   Démo2: implémentation du host & binding

o   Démo3 : implémentation du client

-          Notions avancées : Hosting, Sessions & Fiabilité

o   Démo 4 & 5: gestion des sessions, hosting dans un service Windows puis dans IIS

-          Nouveautés Visual Studio 2008

o   Revue rapide

Ainsi qu’une démo rapide, graphique, illustrant la mise en place de manière simple du support de la fiabilité (reliable) en modifiant simplement le fichier de configuration app.config.

L’ensemble des démos a été effectué sous Visual Studio 2008.

<-- Un extrait de la présentation -->

<-- Démonstration d’un hosting WCF dans un service Windows NT -->

Pour terminer, j’ai eu des remarques, à juste titre, comme quoi je n’avais pas couvert les notions de sécurité autour de WCF. Mon ami Pascal Belaud a justement écrit récemment un très bon article sur le sujet que je vous recommande chaudement. Vous devriez bientôt le retrouver sur son blog : http://blogs.msdn.com/pascal/

UPDATE: Voici l'article de Pascal dont je vous parlais : "Deux exemples de mise en œuvre de contrôles de sécurité dans nos services WCF" : http://msdn2.microsoft.com/fr-fr/security/cc451914.aspx

-= David =-

Posted by davrous | 2 Comments
Filed under: , ,

Les projets SQL 2005 (SSIS, RS, ...) avec Visual Studio 2008?

Cela fait plusieurs fois que je suis confronté la même question. Vous vous demandez, suite à une migration de vos projets vers Visual Studio 2008, comment récupérer vos projets SQL 2005 de type package SSIS, Reporting Server, etc. ?

Tentons de comprendre, le positionnement de chacun des 2 outils.

SQL 2005 arrive avec une sorte de Visual Studio 2005 « light » (SQL Server Business Intelligence Development Studio (SQL BIDS)) proposant, entre autre, un projet pour faire du Reporting coté server avec Reporting Server, des packages SSIS, etc. Visual Studio 2005 permet alors d’éditer les rapports pour RS 2005. Si vous installez par-dessus une version plus complète de Visual Studio 2005 (comme une Pro par exemple), le Visual Studio 2005 de SQL 2005 sera alors enrichi avec les projets classiques de type C#, VB.NET, etc. Par contre, si vous installez Visual Studio 2005 seul, sans une installation de SQL 2005 sur la même machine, on voit bien alors qu’il ne propose pas de projet de type Report Server mais uniquement des projets pour du RDLC pour « designer » des rapports clients.

C’est la même chose pour Visual Studio 2008 à l’heure actuelle. Par exemple pour le reporting, il ne permet uniquement, pour l’instant, d’éditer des rapports client via le format .rdlc. Lorsque SQL 2008 arrivera, ce dernier enrichira alors VS 2008 d’un nouveau type de projet pour du Report Server et pour SSIS.

En conclusion, voici le scénario le plus simple pour utiliser Visual Studio 2008 pour la plupart des projets et pour malgré tout avoir le support des projets de type SQL 2005:

-              Installation d’un SQL 2005 sur un poste pour disposer du SQL BIDS livré avec
-              Installation de VS 2008 pour tous les autres types de projets.

A noter, que Visual Studio 2005 peut tout à fait cohabiter avec Visual Studio 2008. Ce scénario est supporté et parfaitement fonctionnel.

Lorsque SQL 2008 sera disponible, vous pourrez ensuite migrer vos projets SSIS vers ce dernier pour pouvoir les éditer directement sous Visual Studio 2008.

-= David =-

Posted by davrous | 0 Comments

Video du workshop Hyper-V "Windows 2008 - Solutions de Virtualisation Microsoft" disponible

Nous avons eu de bons retours sur le workshop Hyper-V que nous avons joué avec Hervé Mestrude (PTC infra) le 31/01/2008.

Ce workshop était consacré à la découverte de la plateforme Hyper-V, Système de Virtualisation Windows Server 2008.

Les sujets suivants furent présentés :

- Solutions de Virtualisation
- Windows Server 2008 Hyper-V (Introduction – Définition – Architecture…)
- Composants clés de la technologie Hyper-V
- Interopérabilité (Novell – Sun et XenSource)
- Introduction à SCVMM
- Feuille de route à la Virtualisation

Vous retrouverez donc ces thèmes abordés dans la vidéo de notre enregistrement ainsi qu’une démo du produit malgré quelques petits soucis techniques avec les snapshots. ;-)



<-- Un extrait de la présentation -->

<-- Démonstration Hyper-V et exemple d'utilisation des 'snapshots' -->

J’attire votre attention sur le fait qu’il faille absolument installer Windows 2008 en version 64 bits pour disposer du rôle Hyper-V. Par ailleurs, il faut que le processeur supporte également les instructions 64 bits (x86-64) ainsi que les instructions de virtualisation Intel VT ou AMDV. Pour terminer, n’oubliez pas d’activer le support de la virtualisation dans le BIOS et d’installer le serveur en EN-US de bout en bout. Vous pourrez ensuite changer en Français une fois l’installation terminée du rôle Hyper-V. Si vous n’installez pas de prime abord tout en EN-US, vous risquez de voir le service Hyper-V non disponible après coup.

En effet, Hyper-V est encore à l’état de Beta (actuellement RC). Nous avions annoncé une disponibilité RTM de Hyper-V 180 jours après la RTM de Windows 2008.

Pour ma part, je l’utilise déjà quotidiennement avec bonheur. En tant que développeur, la fonctionnalité appelée « Snapshot » est en effet super pratique. Cela me permet de facilement passer d’un type de machine (avec telle ou telle version du Framework, IIS installé ou non) pour analyser le comportement de mon code.

N’hésitez donc pas à revenir vers nous par email (davrous@microsoft.com & hmestrud@microsoft.com) si vous souhaitez obtenir l’accès complet à ce workshop. La vidéo exposant la présentation PowerPoint ainsi que les démos d’Hyper-V dure 1h30 et sera donc fournie en l’échange de 90 minutes sur votre contrat horaire Gold (40h/an), ISV Certified (15h/an) ou ISV registered (10h/an). Vous pouvez ensuite revoir cette vidéo autant de fois que vous le souhaitez avec l’ensemble des collaborateurs de votre entreprise.

-= David =-

Posted by davrous | 0 Comments

Quel est l'impact de l'installation du .NET Framework 3.0/3.5 pour les applications .NET 1.1 & 2.0?

Comme je vois souvent passer cette question, je vous propose de la couvrir rapidement. Tout d'abord, jetez un œil à cette image qui résume les dépendances entre les briques .NET successives:

 netfx versions

Pour faire simple, .NET 1.0 fut remplacé intégralement par .NET 1.1 au niveau fonctionnel qui fut lui-même remplacé intégralement par .NET 2.0.

 

Conséquence : une application écrite en 1.1 est par défaut impactée par l’installation du Framework 2.0. En effet, par défaut à nouveau, une application .NET va tenter d’utiliser la dernière version du Framework. Logiquement, tout est censé bien se passer. En cas de problème de compatibilité, on peut forcer son application 1.1 à n’utiliser que le .NETFx 1.1 via un fichier app.config. Mais c’est une opération manuelle, application par application.

 

Cette histoire était vraie jusqu’au .NETFx 2.0. A partir du .NETFx 2.0, nous avons figé la brique de base à ce niveau de fonctionnalités. Les nouveaux Framework « se contenteront » alors d’enrichir la brique de base avec des nouveaux services. .NETFx 3.0 apportant principalement WPF (graphique), WCF (communication) et Worflow Foundation. .NETFx 3.5 apporte principalement LINQ.

 

Du coup, l’installation du .NETFx 3.0 (basé sur .NETFx 2.0) n’aura aucune incidence sur une application conçue pour tourner en .NETFx 2.0. Cette application n’aura tout simplement aucune conscience de l’existence de ces nouveaux services. Cela sera donc totalement transparent pour elle.

 

Par contre, l'installation du .NETFx 3.0 entraine forcément l'installation dans la foulée du .NETFx 2.0 sur lequel il est basé. Ainsi, de manière indirecte, l'installation du .NETFx 3.0 peut avoir un effet sur les machines où uniquement le .NETFx 1.1 était installé. En effet, suite à l'installation du .NETFx 3.0, les applications écrites en 1.1 basculeront alors sur le 2.0.

 

Pour terminer, voici un lien vers les « breaking changes »  au runtime, c'est-à-dire les éventuels problèmes générés lorsque l’on fait tourner une application 1.1 sur le framework 2.0/3.x : http://msdn2.microsoft.com/en-us/netframework/aa497239.aspx avec plus de détails ici : http://msdn2.microsoft.com/en-us/netframework/aa570326.aspx

Les chances de tomber sur de tels problèmes sont minces, mais si c’est le cas, il est alors possible de forcer une application spécifique à utiliser le runtime de son choix via le fichier app.config.

-= David =-

Posted by davrous | 2 Comments
Filed under:

PowerShell : le nouvel environnement de scripting

Comme nous l’avons déjà dit ici, nos partenaires ont accès à des workshops dédiés sur certains sujets. En contrepartie, en général, 1h est décomptée sur votre contrat de 40h (si vous êtes Gold) quelque soit le nombre de participants.

Nous en avons déjà 3 en stock dont celui sur PowerShell.

PowerShell est un nouvel environnement de scripting qui, contrairement aux autres shells, ne retourne pas que du texte mais de véritables objets .NET du Framework. Cela nous offre alors de très intéressantes perspectives et une puissance disponible bien supérieure au shell Windows précédent.

Ce nouvel environnement sera disponible par défaut sous Windows 2008 mais peut-être téléchargé et installé pour Windows XP, Windows Vista & Windows 2003. Vous pouvez télécharger celui de Windows Vista ici : http://www.microsoft.com/downloads/details.aspx?FamilyId=C6EF4735-C7DE-46A2-997A-EA58FDFCBA63&displaylang=en

Voici l’agenda de notre workshop:

Agenda Powershell

  • Qu’est ce que PowerShell ?
    • Description rapide de ce nouveau Shell et de ses avantages par rapport aux anciens Shell Windows
  • Les bases
    • Qu’est-ce qu’une Command-Let (CmdLet) ?
    • Revenu de quelques commandes, utilisation du Pipe, interop .NET & WMI
  • Ecrire un script
    • Ecriture d’un script PS1 requêtant l’Active Directory en utilisant les objets du Framework .NET

Script Powershell Search 

 

  • Ecrire une CmdLet
    • Présentation du squelette de base d’une CmdLet en .NET (C#)
    • Ecriture d’une CmdLet gérant des utilisateurs dans une base de données
    • Utilisation d’un Snap-in pour intégrer la nouvelle CmdLet dans PowerShell
  • Utiliser une CmdLet depuis du code .NET
    • Intégration d’un appel d’une CmdLet PowerShell dans un projet de type Console.

En tant que développeurs, la revue de l’écriture d’un script ainsi que d’une CmdLet en .NET sera susceptible de vous intéresser.

Si c’est le cas, n’hésitez pas à nous contacter par email avec votre numéro de partenaire pour pouvoir rejouer ce workshop.  Nous vous enverrons alors un lien vers l’enregistrement LiveMeeting que nous avons fait de manière à vous laisser la possibilité de rejouer ce workshop ainsi que l’ensemble de la présentation au format PowerPoint, les scripts PowerShell et le projet solution Visual Studio 2005 de la CmdLet.

-= David =-

Posted by davrous | 0 Comments
Filed under: ,

Solution du « revert-to-self » pour les problèmes de « double-hop »

Dans un précédent post (voir cet article), nous évoquions différentes méthodes pour pallier le problème de double saut. Je vous porpose de détailler ici la méthode #3 :

Faire un revert-to-self (par code) pour forcer le thread à utiliser l’identité du process : toutes les connexions au back-end se feront alors sous cette même identité.

Cette méthode est applicable dans une application ASP.NET en mode impersonate=true. Le scénario est alors le suivant :

  1. L'utilisateur se connecte à l'application Web. Il s'authentifie en Windows auprès de IIS qui passe le jeton à ASP.NET. ASP.NET lance exécute alors le thread pour le traitement de la requête sous l'identité de l'utilisateur. C'est là quele porblème de double-hop peut survenir en cas de connexion à un système back-end : ASP.NET ne peut pas réutiliser l'identité de l'utilisateur initial.
  2. On fait donc un « revert-to-self » : le thread continue son excécution sous l'identité du process (ie de l'application pool)
  3. On exécute la requête vers le back-end
  4. On revient à l'identité initiale du thread (ie celle de l'utilisateur) pour la suite de l'exécution de la requête

Pour réaliser le « revert-to-self », on utilise un appel à la méthode suivante : 

      using System.Security.Principal;

      . . .

      WindowsIdentity
wi = null; // pour stocker l'identité afin d'y revenir plus tard

      // Stocke l'identité courante et revient à l'identité du process
      private void BackToProcessID()
      {
            wi =
WindowsIdentity.GetCurrent();
            WindowsIdentity.Impersonate(IntPtr.Zero);
      }
 

Pour revenir à l'identité de l'utilisateur, on appelera cette méthode :

      // Revient à l'identité stockée
      private void BackToUserID()
      {
            if(wi != null)
               wi.Impersonate();
      }

-= Julien Bakmezdjian =-

Comment cacher dynamiquement des contrôles dans InfoPath ?

Considérons un scénario où un formulaire InfoPath contient des champs dont l’affichage est contrôlé par le rôle de l’utilisateur. Lorsque le formulaire est présenté à l’utilisateur, certains champs ne sont pas visibles si l’utilisateur n’est pas dans rôle donné. Le problème semble trivial, mais InfoPath ne propose pas d’accès direct au jeu de contrôles d’un formulaire : le modèle objet d’InfoPath est « data-driven ». Voyons donc comment nous pouvons procéder pour parvenir à nos fins malgré tout.

 

Il faut tout d’abord considérer l’ajout de code managé en « code-behind » du formulaire. Cela peut se faire avec Visual Studio 2005 et les VSTO SE (http://www.microsoft.com/downloads/details.aspx?FamilyId=5E86CAB3-6FD6-4955-B979-E1676DB6B3CB&displaylang=en).

Comme dit, on ne peut pas manipuler directement les contrôles graphiques du formulaire. L’astuce est donc de créer un champ dans le jeu de données, champ qui contiendra la valeur du rôle de l’utilisateur :

 

UserRole Field

 

Ce champ est rempli dynamiquement par code lors du chargement du formulaire en fonction de l’utilisateur courant. Voici ce que l’on peut envisager par exemple :

 

        void FormEvents_Loading(object sender, Microsoft.Office.InfoPath.LoadingEventArgs e)

        {

            SetUserRole();

        }

 

        private void SetUserRole()

        {

            XPathNavigator navigator = Root.SelectSingleNode("my:UserRole", this.NamespaceManager);

            if (. . . )

                       navigator.SetValue("user");

            else

                       navigator.SetValue("approver");

        }

 

L’étape suivante est de configurer les contrôles ou les groupes de contrôles pour qu’ils s’affichent ou disparaissent en fonction de la valeur du champ :

 

Conditional Formatting

 

-= Julien Bakmezdjian =-

Posted by julienba | 0 Comments
Filed under: ,
More Posts Next page »
 
Page view tracker