Importer des rendez vous dans Outlook 2007
Par Guillaume MAISON le jeudi, février 2010, 13:43 - Développement - Lien permanent
Lors de l'installation d'un serveur Exchange 2007 chez un client, ce dernier m'a demandé de reprendre dans les calendriers de chacun des utilisateurs tous les événements d'une application d'agenda au format web.
Cette application web s'appelle Ovidentia. C'est une application fonctionnant sous Apache/PHP/MySQL. Ma première idée était de trouver un moyen d'exporter ces événements au format csv (format universellement connu et facilement manipulable par la suite pour automatiser d'une manière ou d'une autre un import). Fonctionnant sous MySQL, je pouvais utiliser un connecteur ODBC pour faire une requête dans Excel pour générer ce csv.
Toutefois, cela ne réglait pas mon souci pour importer les événements dans Outlook, lié à l'Exchange. Surtout, étant donné que j'avais plus de 50 utilisateurs à traiter, comment l'automatiser, sachant que je devais récupérer tous les événements depuis début 2009...
Enfin, j'ai réussi à trouver le script qui allait bien, qui plus est en PowerShell ! En fait, je me suis basé sur ce script Create Calendar Appointments Automatically Based on Existing Calendar Appointments.
Puis, je l'ai modifié, pour intégrer la requête ODBC qui va bien et les traitements qui vont bien pour la création des événements.
Pour cet exemple, les prérequis sont :
- pilote ODBC MySQL
- Powershell 2.0
J'ai donc créé 3 fichiers pour me permettre tout ça :
requete.sql :
SELECT bab_users.id, bab_users.nickname, bab_users.email, bab_cal_events.id, bab_cal_events.title, bab_cal_events.description, bab_cal_events.location, bab_cal_events.start_date, bab_cal_events.end_date, bab_cal_events.bprivate FROM bab_users, bab_cal_events, bab_cal_events_owners, bab_calendar WHERE bab_calendar.owner=bab_users.id AND bab_cal_events_owners.id_cal = bab_calendar.id AND bab_cal_events.id = bab_cal_events_owners.id_event AND bab_cal_events.start_date >= '#startdate#' AND bab_users.nickname ='#username#' GROUP BY bab_users.id, bab_users.nickname, bab_users.email, bab_cal_events.id, bab_cal_events.title, bab_cal_events.description, bab_cal_events.location, bab_cal_events.start_date, bab_cal_events.end_date, bab_cal_events.bprivate ORDER BY bab_cal_events.start_date
agenda.ps1 (LE script d'importation) Il est important d'exécuter ce script sur le poste de l'utilisateur et connecté avec sa session :
param($username, $action="synchro", $reel=$false) function HelpCommand($value) { $howto = @" agenda.ps1 username action [reel ($false|$true)] "username" : le nom de l'utilisateur dans Ovidentia "action" : quelle action doit-on effectuer : import : il s'agit d'une première synchronisation, complète, depuis le 01/01/2009 synchro (par défaut) : il s'agit d'une synchronisation Ovidentia->Outlook pour tous les nouveaux événements (ou événements modifiés) de la date du jour jusqu'à .... "reel" : doit-on réellement mettre à jour ou non (presque équivalent à -Whatif) $false (par défaut) : juste pour tester $true : mettre réellement à jour Exemple 1 : agenda.ps1 gmaison import $false Cet exemple permet de simuler l'import de l'agenda de gmaison depuis le 01/01/2009 Exemple 2 : agenda.ps1 gmaison synchro $true Cet exemple permet de synchroniser l'agenda de gmaison pour tous les événements à venir depuis la date d'exécution du script "@ $howto } trap [Exception] { Write-error "Une erreur est arrivée. Veuillez vérifier vos paramètres" HelpCommand break; } if ($username.tolower() -eq "-help") { HelpCommand break } #si on a oublié de préciser le username if ($username -eq $null) { [string]$username = read-host -prompt "veuillez saisir le nom réseau de l'utilisateur " } #ici, on récupère la requête pour l'utilisateur $filepath = "requete.sql" # ou bien si les noms utilisateurs sont identiques au login réseau #[string]$nomutilisateur = [environment]::username [string]$requete = get-content $filepath $requete = $requete.replace("#username#",$username).tolower() if ($action -eq "import") { $startdate = "2009-01-01" } else { $startdate = (Get-Date -Format "yyyy-MM-dd").toString() } $requete = $requete.replace("#startdate#",$startdate).tolower() #ici, on crée la connexion pour pouvoir récupérer tous ses rendez vous $commande = $null $connexion = $null $commande = new-object system.data.odbc.odbccommand $connexion = new-object system.data.odbc.odbcconnection $commande.connection = $connexion # attention : il faut créer l'entrée odbc pour ovidentia $dsn = "driver=mysql odbc 5.1 driver;uid=exchange;pwd=exchange;port=3306;database=ovidentia;server=serveur" $connexion.connectionstring = $dsn $connexion.open() #ici, on exécute la requête et on récupère les données $commande.commandtext = $requete $dataadapter = new-object system.data.odbc.odbcdataadapter($commande) $dataset = new-object system.data.dataset $nombre= $dataadapter.fill($dataset) # on démarre outlook if ($reel) { $outlookapp = new-object -comobject outlook.application $allcalitems = $outlookapp.getnamespace("MAPI").getdefaultfolder(9).items } #puis on insère les données dans le calendrier foreach ($table in $dataset.tables) { $max_lignes = $table.rows.count $i=0 foreach ($row in $table.rows) { $iduser = $row.id $nickname = $row.nickname $email = $row.email $eveid = $row.id1 $titre = $row.title $desc = $row.description $lieu = $row.location $datedeb = $row.start_date $datefin = $row.end_date $prive = $row.bprivate #write-host $nickname" - "$eveid" -> "$datedeb # on a récupéré toutes les données liées à l'événement # maintenant, on crée l'événement if ($reel) { if ($action -eq "synchro") { # ici, on va rechercher si l'événement utilisateur existe $event = $allcalitems | where-object{$_.userproperties.find("OvidentiaID", $true).value -eq $eveid -and $_.start -ge [datetime]$startdate} } else { $event = $null } # s'il n'existe pas, on le crée if ($event -eq $null) { $event = $outlookapp.createitem(1) $prop = $event.userproperties.add("OvidentiaID", 20) }else{ $prop = $event.userproperties.find("OvidentiaID", $true) } # quoiqu'il arrive, on le met à jour $event.subject = "$titre" $event.location = $lieu $event.body = $desc $event.start = [datetime]$datedeb $event.end = [datetime]$datefin if ($prive -eq "y") { $event.sensitivity = 2 } else { $event.sensitivity = 0 } $maintenant = get-date if ($datedeb -ge $maintenant) { $event.reminderset = $true } else { $event.reminderset = $false } $prop.Value = $eveid; $event.close(0) } else { write-host @" $iduser $nickname $email $eveid $titre $desc $lieu $datedeb $datefin $prive "@ $todisplay } [int]$pourcent = $i++ / $max_lignes *100 write-progress "importation des événements du calendrier" "en cours" -percentcomplete $pourcent -id 1 } }
J'ai également créé un script qui me permet, sur un poste d'un utilisateur, d'automatiser l'exécution du script ci-dessus par l'intermédiaire du planificateur de tâche. exec_task.ps1 la tâche doit être configurée pour être exécutée avec le compte de l'utilisateur :
param($username, $action, $reel) #Récupération de la date du jour $dt = Get-Date -format "yyyyMMdd_hhmm" # construction du chemin où se trouve ce script et celui d'import de l'agenda # mais également le chemin du fichier de log $MyPath = (split-path $myinvocation.Mycommand.Definition) $file = $MyPath +"\"+[Environment]::UserName+"_"+$dt + ".log" #Démarrage de la récupération de la console (pour le log) start-transcript $file #en cas d'erreur on arrête la récupération du log trap { stop-transcript; break} Set-Location $MyPath .\agenda.ps1 $username $action $reel stop-transcript