Comment créer son premier script PowerShell ?

I. Présentation

Le langage PowerShell est désormais incontournable pour l'administration des systèmes d'exploitation Windows, ainsi que pour l'automatisation de certaines tâches. Dans le même temps, Microsoft développe une version compatible Linux, ce côté multi-plateformes le rend, à mon sens, encore plus attractif et son apprentissage pertinent.

Au-delà du scripting, PowerShell est un véritable outil d'administration et d'automatisation.

Pour votre premier script PowerShell, difficile de deviner quel sujet il traitera, les options sont nombreuses... Mais il y a fort à parier que vous allez requêter l'annuaire Active Directory de votre entreprise assez rapidement. En tout cas, l'objectif principal de cet article est de vous donner les bases pour avoir une bonne approche dans la rédaction de votre premier script PowerShell.

II. Quel éditeur utiliser pour un script PowerShell ?

La première question qui va se poser, c'est de savoir quel éditeur vous allez utiliser pour rédiger votre script. Oubliez le Bloc-note, Notepad++ ou la console PowerShell directement. Ce n'est pas adapté.

Je vous recommande deux outils : PowerShell ISE, qui est l'éditeur intégré à Windows et qui est adapté au scripting PowerShell, il contient notamment l'aide intégré, l'auto-complétion ainsi qu'une console PowerShell. De base et sans configuration particulière, il vous permettra de bénéficier d'un environnement simple et préconfiguré pour débuter avec PowerShell.

Le second outil n'est autre que Visual Studio Code, VSCode pour les intimes, qui ne se limite pas qu'à PowerShell contrairement à l'ISE puisque l'on pourra installer différentes extensions, dont PowerShell. On pourra ensuite le configurer à souhait avec les nombreux paramètres disponibles, mais aussi l'interconnecter avec d'autres services comme GitHub et intégrer d'autres langages.

Remarque : Au même titre que PowerShell ISE, l'outil VSCode est disponible en version 32 bits et 64 bits.

En fait, et ça reste mon avis, je pense qu'il vaut mieux commencer avec PowerShell ISE, car il est super simple d'utilisation et il s'agit de l'outil natif. Puis, par la suite, lorsque l'on souhaite personnaliser de manière plus avancée son éditeur PowerShell, il faudra basculer vers VSCode.

Aperçu de l'interface PowerShell ISE

Pour commencer, ces trois boutons classiques sont à connaître, car ils sont bien pratiques :

Je vous propose de consulter cet article qui détaille notamment les nouveautés de PowerShell ISE 5.0 par rapport aux versions précédentes : PowerShell ISE 5.0, les nouveautés - notamment l'excellente fonctionnalité IntelliSense disponible depuis la version 3.0 et qui permet l'auto-complétion des commandes et de vous aider dans la syntaxe de manière efficace.

Maintenant que l'on a identifié un éditeur de code, passons à quelques bases théoriques sur PowerShell.

III. Quelques bases

Afin de vous aiguiller dans la rédaction de vos premières lignes de code PowerShell et pour vous donner quelques bases bien utiles, voici ci-dessous quelques notions abordées, volontairement sans trop de détails pour une première approche.

A. Le nom des commandes / cmdlets

Vous verrez au fil du temps que vous pouvez deviner le nom d'une commande PowerShell, même si vous ne la connaissez pas, simplement parce qu'il y a une convention de nommage stricte pour le nom des cmdlets.

En fait, Microsoft fournit une liste de verbes approuvés et qui peuvent être utilisés pour le nom des commandes, que ce soit pour les commandes officielles ou celles des modules communautaires. Une commande PowerShell suit la convention de nommage suivante : Verbe-Nom.

Par exemple, le verbe "Get" ciblera les commandes qui permettent d'obtenir des informations. Pour obtenir la liste des services, ce sera "Get-Service". Pour arrêter un service, on utilisera le verbe "Stop" ce qui donnera "Stop-Service" et pour le démarrer "Start-Service". Simple, non ?

Plus d'informations sur les verbes approuvés : Approved Verbs for Windows PowerShell Commands

Astuce : le cmdlet "Get-Command" permet de lister les commandes disponibles sur votre machine, ce qui peut varier selon votre version de PowerShell et les modules disponibles sur l'hôte local. Ainsi, on peut rechercher facilement une commande en s'appuyant sur un mot clé.

Reprenons le terme "Service" et recherchons toutes les commandes qui contiennent ce terme :

Get-Command *Service

Ce qui nous permet d'obtenir la liste des commandes :

CommandType Name             Version  Source
----------- ----             -------  ------
Cmdlet      Get-Service      3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      New-Service      3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Restart-Service  3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Resume-Service   3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Set-Service      3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Start-Service    3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Stop-Service     3.1.0.0  Microsoft.PowerShell.Management
Cmdlet      Suspend-Service  3.1.0.0  Microsoft.PowerShell.Management

En ajoutant un astérisque également après le terme "Service" vous obtiendrez des résultats supplémentaires, car ce sont des cmdlets qui auront un autre terme avec "Service" dans le nom. Je vous laisse essayer pour voir.

Un autre moyen de trouver le nom d'une commande, je pense, moins efficace, mais qui peut s'avérer utile rien que pour parcourir les commandes par curiosité, c'est d'utiliser l'auto-complétion. Vous commencez à saisir un nom de commande, par exemple "Get-" et vous appuyez ensuite sur "Tab" afin de faire défiler les choix.

Note : l'utilisation de l'auto-complétion est indispensable pour être plus efficace dans la saisie du code, mais aussi pour éviter les erreurs de frappe.

 

B. Obtenir de l'aide

Maintenant que l'on sait comment rechercher une commande, comment faire pour l'utiliser ? De l'aide peut être obtenue, directement dans la console PowerShell, en ligne sur Microsoft Docs voire même au sein de PowerShell ISE.

On s'appuiera sur le commandlet "Get-Help", mais pour ma part j'utilise surtout la documentation en ligne accessible depuis votre navigateur à l'adresse suivante : Aide PowerShell - Microsoft Docs

Note : L'aide peut être actualisée avec la commande "Update-Help" afin d'avoir une aide hors ligne et actualisée. En entreprise, sachez qu'il est possible d'héberger l'aide sur un partage réseau afin de la distribuer via le réseau local, plutôt que d'effectuer le téléchargement X fois.

Pour obtenir de l'aide sur le cmdlet "Get-Service" afin de savoir comment il s'utilise, on exécute :

Get-Help Get-Service

Ce qui nous donne de l'aide directement dans la console :

Aperçu de la commande "Get-Help"

Si l'on souhaite en savoir un peu plus et visualiser des exemples d'utilisation, on ajoutera le paramètre "examples" comme ceci :

Get-Help Get-Service -examples

Pour finir sur l'aide, vous pouvez ajouter le paramètre "online" à la fin de la commande pour que votre navigateur s'ouvre directement sur la page de l'aide de ce cmdlet. Ce qui est bien pratique.

Get-Help Get-Service -online

 

C. Les alias

En plus de rencontrer des cmdlets classiques avec les noms approuvés par Microsoft, vous allez surement rencontrer des noms de commandes basés sur des alias. L'exemple le plus concret c'est les commandes DOS. En fait, la plupart des commandes DOS fonctionnent dans la console PowerShell, comment ça se fait ?

Microsoft a intégré des alias pour faire une correspondance entre un nom utilisé historiquement en DOS et renvoyé vers son équivalent en PowerShell. Par exemple, si vous exécutez la commande "dir" qui permet de lister le contenu d'un répertoire, vous n'allez pas exécuter la commande DOS, mais directement "Get-ChildItem" qui est le cmdlet PowerShell qui assure désormais cette fonction.

Remarque : Microsoft a intégré également des alias correspondants à des commandes Unix, comme "ls" et "wget".

Il est possible de créer vos propres alias, mais ce n'est pas l'objet de cet article, en attendant vous pouvez lister les alias existants avec "Get-Alias".

Aperçu de la liste d'alias obtenue avec Get-Alias

D. L'exécution des scripts

Lors de la première exécution d'un script sur une machine, vous pourriez être déçu de constater que le script ne veut pas s'exécuter. Rassurez-vous, il s'agit d'un comportement normal.

En effet, Windows intègre une politique de sécurité qui contrôle l'exécution des scripts PowerShell. Pour des raisons de sécurité, elle est configurée par défaut sur un mode restreint (Restricted) qui empêche l'exécution des scripts PowerShell. Il y a plusieurs niveaux de protection, allant du niveau le plus ouvert (Bypass) au niveau plus sécurisé où l'on exige qu'un script soit signé (AllSigned) peu importe d'où ils proviennent (local ou internet).

Pour obtenir la stratégie actuellement appliquée sur votre machine, exécutez la commande suivante :

Get-ExecutionPolicy

Pour pouvoir exécuter votre script, basculer la politique sur la valeur "Unrestricted" comme ceci :

Set-ExecutionPolicy Unrestricted

Modification de la stratégie d'exécution
La stratégie d’exécution permet de vous prémunir contre les scripts que vous jugez non fiables. En modifiant la
stratégie d’exécution, vous vous exposez aux risques de sécurité décrits dans la rubrique d’aide
about_Execution_Policies à l’adresse http://go.microsoft.com/fwlink/?LinkID=135170. Voulez-vous modifier la stratégie
d’exécution ?
[O] Oui [T] Oui pour tout [N] Non [U] Non pour tout [S] Suspendre [?] Aide (la valeur par défaut est « N ») : o

Vous êtes désormais en mesure d'exécuter des scripts PowerShell sur votre machine.

Plus d'informations :

E. Une panoplie de modules

PowerShell est livré avec un ensemble de cmdlets, eux-mêmes associés à un module c'est-à-dire à un ensemble de cmdlets. En parallèle, Microsoft propose de nombreux modules officiels, comme par exemple un module Active Directory qui contient un ensemble de cmdlets pour administrer un annuaire Active Directory. On pourrait aussi citer des modules pour Office 365, la gestion du firewall ou encore Hyper-V. En supplément, on trouvera également des modules issus de la communauté PowerShell, généralement disponibles sur GitHub directement.

Pour la gestion des modules, il y a quelques commandes à connaître :

  • Get-Module -ListAvailable : Vous permet de lister les modules disponibles en local sur votre machine
  • Find-Module : Vous permet de rechercher un module parmi ceux référencés auprès de Microsoft - Exemple : Find-Module *ActiveDirectory*
  • Install-Module <nom du module> : Vous permet d'installer un module sur votre machine

En fait, installer un module revient à télécharger les fichiers sources et à les positionner dans le bon dossier sur votre machine. Mais alors ces modules, où sont-ils stockés ?

La variable d'environnement "PSModulePath" contient la liste des dossiers qui sont scannés pour rechercher les modules PowerShell sur votre machine. Par défaut, cette variable contient un répertoire personnel propre au profil de l'utilisateur, ainsi qu'un répertoire dans "Program Files" et un autre dans le répertoire Windows.

Vous pouvez consulter la valeur de cette variable avec la commande suivante :

$env:psmodulepath

Ce qui retourne par exemple :

C:\Users\Florian\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules

Puisque je parlais justement de variables, on va s'y atteler dans la partie suivante.

F. Jouer avec les variables

Les variables en PowerShell comme dans beaucoup d'autres langages se déclarent en préfixant un mot du signe dollars "$". Pour déclarer une variable "MaVariable" on indiquera simplement "$MaVariable". Chaque variable dispose d'un type, comme "string" pour les chaînes de caractères, "int" pour les nombres ou encore "boolean" pour un booléen.

Bien qu'il soit possible de forcer le type d'une variable, par défaut le type sera attribué automatiquement en fonction de la forme des valeurs envoyées à la variable. Par exemple, si l'on affecte une chaîne de caractères à une nouvelle variable, elle prendra directement le type "string".

Exécutez le bout de code ci-dessous et vous obtiendrez le type de la variable $MaVariable :

$MaVariable = "Hello World"
$MaVariable.GetType()

Ce qui retourne ceci :

IsPublic    IsSerial   Name      BaseType 
--------    --------   ----      -------- 
True        True       String    System.Object

On remarque la valeur "String" pour le nom du type de cette variable.

Remarque : Nous avons utilisé GetType() qui est une méthode c'est-à-dire une action à effectuer sur la variable.

Comment concaténer la valeur de plusieurs variables ?

Imaginons deux variables qui contiennent une chaîne de caractères, que l'on souhaite concaténer dans une seule et même variable. C'est tout simple, on additionnera les deux variables comme on le ferait avec 2 nombres.

Voici un exemple :

$MaVariable1 = "Hello"
$MaVariable2 = "World"
$MaVariable3 = $MaVariable1 + $MaVariable2
$MaVariable3

La variable $MaVariable3 sera égale aux valeurs de $MaVariable1 et $MaVariable2.

Maintenant, si l'on veut ajouter du texte en supplément, ou par exemple un espace entre les deux mots, voici la syntaxe :

$MaVariable3 = $MaVariable1 + " " + $MaVariable2
$MaVariable3

Le fait d'indiquer $MaVariable3 permet tout simplement d'afficher le contenu de la variable dans la console PowerShell.

Comment stocker le résultat d'une commande dans une variable ?

Rappelez-vous, le cmdlet "Get-Service" permet d'afficher la liste des services avec l'état de chaque service. Si l'on souhaite stocker le résultat de cette commande dans une variable, c'est simple !

$ServiceState = Get-Service

Ceci vous permet de stocker l'état des services à un instant t, on pourrait imaginer comparer l'état des services à deux moments différents grâce à cette méthode d'affectation dans une variable.

G. Le pipeline

Le pipeline est une notion indispensable que l'on utilise tellement souvent... Mais d'ailleurs c'est quoi le pipeline ? Il s'agit de la barre verticale disponible sur la touche "6" d'un clavier AZERTY : "|".

En PowerShell, le pipeline permet d'interconnecter différentes commandes puisque la sortie d'une commande sera l'entrée de la suivante.

Imaginons que l'on récupère la liste des services (Get-Service), mais que l'on souhaite uniquement les services démarrés. Comment faire si la commande Get-Service n'offre pas cette possibilité nativement ? On va faire un piping d'objet pour filtrer le résultat dans une seconde commande.

Le cmdlet "Where-Object" permet de filtrer les données renvoyées par un autre cmdlet. On va l'utiliser pour filtrer le résultat de la commande Get-Service. On utilisera également $_ qui permet de cibler l'occurrence courante renvoyée par la commande Get-Service (ou une autre commande, selon celle qui est concernée par le pipeline).

Finalement, pour récupérer la liste des services en cours d'exécution, c'est-à-dire le statut "running", on exécutera la commande suivante :

Get-Service | Where-Object{ $_.Status -eq "Running" }

Ci-dessus, "Status" correspond à une propriété de l'objet renvoyé par Get-Service, le fait d'indiquer "$_.Status" permet de lire directement la valeur de cette propriété, et ensuite on utilise l'opérateur de comparaison "eq" ("equal" -> "égal") pour filtrer sur le statut "running".

Remarque : On utilise souvent des abréviations pour Where-Object : "Where" ou même plus récemment "?"

 

IV. A la conquête de notre premier script

Maintenant que l'on a survolé différents points du scripting PowerShell, on va pouvoir continuer l'apprentissage avec un premier script. En fait, il reste énormément à apprendre, mais c'est sans fin ou presque... Il va falloir apprendre au fur et à mesure.

Je vous propose de créer un script qui va surveiller les changements d'état de services Windows. Dans le cadre de cet exemple, on va forcer un peu les choses pour simuler des changements d'état sur deux services.

On a vu précédemment que la commande "Get-Service | Where-Object{ $_.Status -eq "Running" }" permet d'obtenir la liste des services en cours d'exécution, on va donc stocker cet état dans une variable : $ServiceStateBefore.

$ServiceStateBefore = Get-Service | Where-Object{ $_.Status -eq "Running" }

Ensuite, on va simuler deux changements d'état : Stopper le service Windows Update (wuauserv) et démarrer le service de temps (w32time) :

# On stoppe le service Windows Update
Stop-Service -Name wuauserv
# On démarre le service de temps
Start-Service -Name W32Time

Puis on va de nouveau stocker l'état des services dans une seconde variable $ServiceStateAfter :

$ServiceStateAfter = Get-Service | Where-Object{ $_.Status -eq "Running" }

A cet instant, on dispose de deux variables qui stockent l'état des services à deux instants différents. On va comparer ces deux objets afin de détecter les changements.

Pour réaliser cette opération, nous allons utiliser le cmdlet Compare-Object qui permet de comparer des objets entre eux, ce qui peut être utile dans de multiple cas, notamment pour comparer deux fichiers.

Compare-Object $ServiceStateBefore $ServiceStateAfter -Property Name,Status

On va lui indiquer les deux objets en entrée, à savoir $ServiceStateBefore et $ServiceStateAfter. Puis, on indique les propriétés à comparer pour détecter les changements, on va utiliser le nom (Name) et le statut (Status).

Enfin, on terminera par l'ajout de deux commandes pour remettre à l'état initial les services :

# Retour à l'état initial
Start-Service -Name wuauserv
Stop-Service -Name W32Time

Ce qui nous donne le script suivant :

$ServiceStateBefore = Get-Service | Where-Object{ $_.Status -eq "Running" }

# On stoppe le service Windows Update

Stop-Service -Name wuauserv

# On démarre le service de temps

Start-Service -Name W32Time

$ServiceStateAfter = Get-Service | Where-Object{ $_.Status -eq "Running" }

Compare-Object $ServiceStateBefore $ServiceStateAfter -Property Name,Status

# Retour à l'état initial

Start-Service -Name wuauserv

Stop-Service -Name W32Time

Si vous exécutez le script sur votre machine, vous obtiendrez le retour suivant :

Pour interpréter ce résultat, c'est relativement simple. La propriété "SideIndicator" indique pour chaque ligne de quel côté une modification a été détectée. Le signe "=>" indique le service tournait dans $ServiceStateBefore, mais qu'il est introuvable dans $ServiceStateAfter, ce qui est logique, car W32Time s'est arrêté.

A l'inverse, le signe "<=" indique que le service tournait dans $ServiceStateAfter, mais pas dans $ServiceStateBefore, ce qui est logique, car on a démarré le service "wuauserv" entre temps.

Voilà pour ce qui est d'un premier script, qui pourrait être amélioré, mais n'oublions pas que l'objectif est de faire ses premiers pas avec PowerShell 🙂

 

V. Interroger l'annuaire Active Directory en PowerShell

Pour terminer cette initiation, on va interroger un annuaire Active Directory en PowerShell, car comme je le disais en introduction, c'est une utilisation très fréquente. L'objectif est de manipuler quelques cmdlets, notamment pour rechercher des objets dans l'annuaire.

On va commencer par importer le module Active Directory, d'ailleurs avec les versions récentes de PowerShell l'importation sera réalisée automatiquement si la ligne n'est pas spécifiée, mais que vous utilisez un cmdlet d'un module externe.

Import-Module ActiveDirectory

On peut rechercher un utilisateur avec le cmdlet "Get-ADUser". Pour lister l'ensemble des cmdlets du module Active Directory, vous pouvez utiliser la commande suivante :

Get-Command -Module ActiveDirectory

Pour la recherche d'un utilisateur, il suffira d'utiliser le paramètre "Filter" pour affiner la recherche. En s'appuyant sur la propriété SamAccountName c'est-à-dire le login, on va pouvoir rechercher l'utilisateur "florian.burnel" :

Get-ADUser -Filter "SamAccountName -eq 'florian.burnel'"

A la place de l'opérateur de comparaison "eq" on pourrait en utiliser d'autres, comme "like" pour trouver les utilisateurs qui contiennent le mot recherché.

Remarque : On aurait pu se passer du filtre pour ajouter un pipeline suivi de Where-Object pour rechercher notre utilisateur, mais ce sera plus gourmand en ressources et donc moins performant. C'est logique, car sans filtre, le cmdlet Get-ADUser va récupérer la liste de tous les utilisateurs et dans un second temps le Where-Object va filtrer les résultats, alors que via le paramètre Filter permet de filtrer directement.

Et comme PowerShell est un langage très flexible, il y a bien souvent plusieurs manières de parvenir à ses fins. Pour la recherche de notre utilisateur, on aurait pu utiliser le cmdlet "Search-ADAccount".

Ce cmdlet est très intéressant et contient plusieurs paramètres qui permettent d'effectuer des recherches rapides sur l'annuaire ; par exemple on peut rechercher les comptes utilisateurs désactivés facilement :

Search-ADAccount -AccountDisabled -UsersOnly

Pour terminer, voici ce que je vous propose : réaliser un export au format CSV de la liste des utilisateurs avec les informations suivantes : login, SID (identifiant unique), date de création de l'utilisateur et le nombre de connexions.

Tout d'abord, il faut bien connaître les attributs Active Directory, correspondant à ces informations. La console historique "Utilisateurs et ordinateurs Active Directory" vous permettra d'obtenir facilement la liste des attributs.

Pour les champs que nous souhaitons, ça donne :

  • Login = SamAccountName
  • Identifiant unique = SID (ou ObjectSID)
  • Date de création = whenCreated
  • Nombre de connexions = logonCount

Par défaut, lorsque l'on exécute la commande Get-ADUser toutes les propriétés d'un objet ne sont pas sélectionnées pour des raisons de performances. Pour sélectionner des propriétés supplémentaires, on va utiliser le paramètre "Properties", ce qui nous donne :

Get-ADUser -Filter * -Properties SamAccountName, SID, whenCreated, logonCount

Vous remarquerez que l'on utilise * comme filtre, afin de prendre tous les utilisateurs. Le paramètre "Filter" est obligatoire. Maintenant, on va utiliser le pipeline pour affiner l'objet de sortie avec le cmdlet Select-Object qui va permettre de sélectionner uniquement les 4 propriétés qui nous intéressent pour l'export CSV, sinon on aurait beaucoup plus d'infos qu'on le souhaite.

Ce qui donne :

Get-ADUser -Filter * -Properties SamAccountName, SID, whenCreated, logonCount | Select-Object SamAccountName, SID, whenCreated, logonCount

La dernière étape consiste à exporter au format CSV les données, on va utiliser le cmdlet "Export-Csv". Nous allons utiliser trois paramètres : Path pour le chemin vers le fichier CSV de sortie, Encoding pour l'encodage des données en UTF-8 (pour gérer les accents) et le paramètre "NoTypeInformation" pour supprimer les infos sur le type dans le fichier.

Voici la commande complète :

Get-ADUser -Filter * -Properties SamAccountName, SID, whenCreated, logonCount | Select-Object SamAccountName, SID, whenCreated, logonCount | Export-Csv -Path "C:\export.csv" -NoTypeInformation -Encoding UTF8

Suite à l'export, vous allez obtenir un fichier CSV qui aura du contenu sous cette forme :

"SamAccountName","SID","whenCreated","logonCount"
"user01","S-1-5-21-2077788776-554437559-1112223334-11784","22/02/2016 11:35:14","27"
"user02","S-1-5-21-2077788776-554437559-1112223334-11778","22/02/2016 11:35:05","30"
"user03","S-1-5-21-2077788776-554437559-1112223334-11785","22/02/2016 11:35:16","10"

Maintenant que l'on a notre CSV en main, on peut exploiter ces données très facilement, avec Excel notamment.

Voilà, je vais m'arrêter là, car on pourrait en écrire des pages et des pages... Ça vous donne un aperçu de ce que l'on peut faire en PowerShell avec l'Active Directory, mais ce n'est vraiment qu'un aperçu. 🙂

VI. Et ensuite ?

Ce tutoriel touche à sa fin, j'espère qu'il vous sera utile pour vous initier au scripting Powershell, maintenant vous allez devoir vous familiariser avec ces nouvelles notions et ensuite poursuivre votre apprentissage. Pour cela, je vous propose quelques ressources :

Par ailleurs, vous pouvez lire du code afin de progresser en essayant de le comprendre et afin d'assimiler les syntaxes les plus courantes. Faire un tour sur Github est un excellent moyen de trouver du code. Par exemple, vous en trouverez quelques-uns sur mon Github ou sur celui de LazyWinAdmin.

Enfin, retrouvez sur Microsoft Virtual Academy un cours vidéo gratuit d'introduction à PowerShell, le tout en français.

Bon courage ! 🙂

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Florian Burnel

Co-Fondateur d’IT-Connect, je souhaite partager mes connaissances et expériences avec vous, et comme la veille techno’ est importante je partage aussi des actus.

florian a publié 1610 articles sur IT-Connect.See all posts by florian

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *