PI Services

Le blog des collaborateurs de PI Services

SCOM et alertes WMI: Script de redémarrage du service wmi et de ses dépendances

 

Le script suivant récupère les alertes ouvertes pour une machine, qui correspondent a des erreurs de requetage wmi. Si il en trouve au moins une dont le repeatcount est supérieur a une valeur donnée en variable, il redémarre le service wmi et ses dépendances et clos les alertes correspondantes.

   1:  
   2: $scomms="scom2k12sp1srv1"
   3: $targetcomputer="scom2k12sp1dc1"
   4: $repeatcountthreshold="1"
   5: $wmi="WinMgmt"
   6:  
   7: $scomcred=Get-Credential -Credential "scom2k12sp1maq1\administrator"
   8: $arrwmialerts=@(“Operations Manager failed to run a WMI query","Workflow Initialization: Failed to start a workflow that queries WMI for performance data","Workflow Initialization: Failed to start a workflow that queries WMI for WMI events","Operations Manager failed to run a WMI query for WMI events",
   9: "Operations Manager failed to run a performance data WMI query","Workflow Initialization: Failed to start a workflow that queries WMI","Script Based Test Failed to Complete")
  10:  
  11: Import-Module operationsmanager
  12:  
  13: New-SCOMManagementGroupConnection -ComputerName $scomms -Credential $scomcred
  14:  
  15: $arrcomputernewalertnames=Get-SCOMAlert | Where-Object {$_.Resolutionstate -eq "0" -and $_.NetbiosComputerName -eq $targetcomputer -and $_.RepeatCount -gt $repeatcountthreshold -and $_.IsMonitorAlert -eq $false } | Select-Object -Property name -ExpandProperty name
  16: $arrcomputernewalerts=Get-SCOMAlert | Where-Object {$_.Resolutionstate -eq "0" -and $_.NetbiosComputerName -eq $targetcomputer -and $_.RepeatCount -gt $repeatcountthreshold -and $_.IsMonitorAlert -eq $false }
  17:  
  18:  
  19:  
  20: $matchingalerts=0
  21: foreach ($wmialert in $arrwmialerts)
  22: {
  23:   if ($arrcomputernewalertnames -contains $wmialert)
  24:     {
  25:     Write-Host -ForegroundColor Red -BackgroundColor White "L'alerte "$wmialert.ToUpper()" a été répétée plus de $repeatcountthreshold fois sur $targetcomputer"
  26:     Write-Host -ForegroundColor Yellow "Fermeture de l'alerte "$wmialert.ToUpper()" avant redemarrage du service $wmi et de ses dependances"
  27:     $matchingalerts= ($matchingalerts + 1)
  28:     $arrcomputernewalerts | Where-Object {$_.Name -like "$wmialert*"} | foreach {Set-SCOMAlert -ResolutionState 255 -Alert $_ }
  29:     }
  30: }
  31:  
  32:  
  33: ###FUNCTIONS###
  34: Function Restart-Wmi ($targetcomputer)
  35: {
  36: Invoke-Command -ComputerName $targetcomputer -Credential $scomcred -ScriptBlock {
  37: $winmgmt=Get-Service -Name Winmgmt
  38: $winmgmtrundep=$winmgmt.DependentServices | Where-Object {$_.Status -eq "Running"}
  39: Stop-Service -Name Winmgmt -Force -ErrorAction SilentlyContinue
  40: Start-Sleep -Seconds 5
  41: Start-Service -Name Winmgmt -ErrorAction silentlycontinue
  42: Start-Sleep -Seconds 5
  43:  
  44: foreach ($dep in $winmgmtrundep) 
  45:     {
  46:     if (Get-WmiObject win32_service | Where-Object {$_.Name -eq $dep.Name -AND $_.state -ne "running" -AND $_.startmode -eq "Auto"}) 
  47:         {
  48:         write-host -ForegroundColor Green "demarrage de la dependance "$dep.Name.ToUpper()""
  49:         Start-Service -Name $dep.Name -erroraction SilentlyContinue -ErrorVariable ("start_"+$dep.Name+"_error").ToString()
  50:         }
  51:     }
  52:  
  53: }
  54: }
  55:  
  56:  
  57: Function NewEventSource
  58: {
  59:     if(!(Test-Path 'HKLM:\SYSTEM\CurrentControlSet\services\eventlog\Operations Manager\RestartWMIScript'))
  60:     {
  61:     New-EventLog -LogName "Operations Manager" -Source RestartWMIScript
  62:     }
  63: }
  64: ###FUNCTIONS###
  65:  
  66:  
  67:  
  68:  
  69:  
  70:  
  71: if ($matchingalerts -gt 0)
  72: {
  73: write-host -ForegroundColor Yellow "Redemarrage du service WinMgmt et de ses dependances"
  74: Restart-Wmi $targetcomputer
  75: }
  76: else
  77: {
  78: write-host -ForegroundColor Green "Pas d'alertes correspondantes trouvées"
  79: Write-Host -ForegroundColor Green "Pas de redemarrage du service WinMgmt et de ses dependances"
  80: exit
  81: }
  82:  
  83:  
  84:  
  85:  
  86:  
  87: ###VERIFICATION ET LOG D'ERREURS
  88:  
  89:  
  90: Invoke-Command -ComputerName $targetcomputer -Credential $scomcred -ScriptBlock {
  91: param($targetcomputer)
  92: $wmi=Get-Service -Name WinMgmt -ComputerName $targetcomputer
  93: if ($wmi.Status -ne "Running")
  94: {
  95: $function:NewEventSource
  96: Write-EventLog -LogName 'Operations Manager' -Source RestartWMIScript -EntryType Error -EventId 1002 -Message "erreur de demarrage du service winmgmt"
  97: }
  98:  
  99: } -Argumentlist $targetcomputer
 100:  
 101: ###VERIFICATION ET LOG D'ERREURS
 102:  
 103:  
 104:  

Desired State Configuration (Partie 1) : Introduction et syntaxe

Introduction

Powershell 4.0 (introduit avec Windows 2012 R2) apporte son lot de nouveautés. La plus importante est : Desired State Configuration.

En entreprise, il existe deux problématiques récurrentes au sein d’un système d’informations :

  • L’augmentation du nombre de serveurs
  • Le changement

Desired State Configuration apporte une solution à ces questions en proposant une solution pour l’automatisation des déploiements et la maintenance des serveurs (contrôle et retour en conformité).

Avec cette fonctionnalité, il sera possible de déployer rapidement et à grande échelle des améliorations à une infrastructure, tout en s’assurant que les systèmes ne varient pas au cours du temps.

Par exemple, on peut vouloir s’assurer qu’un groupe de serveurs web possède :

  • le rôle adéquat correctement configuré,
  • les services nécessaires démarrés
  • les sources valides d’un site web copiées dans le bon répertoire
  • la bonne adresse IP pour chaque serveur.

DSC permet de configurer un serveur via un script au travers d’une syntaxe simple (similaire aux fonctions Powershell). Les possibilités de configuration sont infinies (rôles, groupes et utilisateurs locaux, registre…). Cette configuration peut se faire en local ou à distance. De plus, au delà de la première application de la configuration du serveur, il existe des mécanismes de contrôles. Avec Desired State Configuration, Windows peut automatiquement vérifier si sa configuration est correcte et la remettre à niveau s’il y a eu un changement anormal. Ainsi, les dérives de configuration sont évitées !

    Pour appliquer une configuration, il existe deux modes :

  • Push : La configuration est envoyé au serveur
  • Pull : La configuration est demandé par le serveur client vers un serveur centrale qui gère toutes les configurations possibles.

Grâce au scripting il va être possible d’appliquer des configuration à des groupes de serveurs.

DSC est basé sur les fichiers “.mof”. Il est possible de les générer de la façon que l’on souhaite (éditeur de texte par exemple). Powershell 4.0 permet de simplifier la génération de ses fichiers notamment grâce à l’auto complétion mais aussi avec syntaxe accessible. Via le module PSDesiredStateConfiguration, on peut créer ses fichiers et les utiliser pour appliquer une configuration.

Cet article fait partie d’une série de 5 billets sur Desired State Configuration :

Desired State Configuration est disponible comme Powershell 4.0 sur Windows 2012 R2/8.1, Winsows 2012/8 et Windows 2008 R2/7.

Les ressources

Les éléments que l’on va pouvoir configurer sont appelés ressources.

Voici quelques exemples de ressources disponibles nativement : l’exécution de services, de clés de registre, de scripts ou de variables d’environnement. Les groupes et utilisateurs locaux ainsi que la copie de fichiers sur un serveur est aussi gérable. Les possibilités sont infinies.

Il est aussi possible de créer ses propres ressources, en définissant la façon de réaliser la configuration sur le serveur et de tester la conformité. Ainsi on peut imaginer une ressource qui s’occupera de la gestion du fichier “hosts”, un autre peut gérer la configuration IP ou même la présence et l’activation de règle firewall.

La liste des ressources disponibles nativement est listé dans le lien suivant : http://technet.microsoft.com/en-us/library/dn249921.aspx

La syntaxe

La syntaxe Powershell implémentée se base sur le mot clé Configuration. Voici un exemple :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
Configuration TestDSC 
{ 

  Node WEBSRV01 #Nom du serveur
  { 
    WindowsFeature IIS 
    { 
      Ensure = “Present” #Vérifie que le rôle est présent
      Name = “Web-Server” #Nom du rôle ou de la fonctionnalité à vérifier
    } 

    File DirectoryCopy
    {
        Ensure = "Present" #Vérifie que les fichiers/dossiers sont présents
        Type = "Directory" #Type d'objet à vérifier
        Recurse = $true #Inclus les fichiers/dossiers enfants
        SourcePath = "\\FILESRV01\MyWebSite" #Chemin des sources
        DestinationPath = "C:\inetpub\wwwroot\MyWebsite" #Destination où doivent se trouver les données
    }
   
    Group ViewerGroup
    {
        Ensure = "Present" #Vérifie qu'un groupe est présent
        GroupName = "Viewer" #Nom du groupe
    }
  } 
}

La déclaration se fait donc via des blocs entre accolades. Dans un bloc de type Configuration, on a un ou plusieurs blocs Node. Pour chaque bloc Node, un fichier MOF sera généré. A côté de ce mot clé, on inscrit le nom du serveur qui possédera cette configuration. A l’intérieur de chacun de ses blocs se trouvent les ressources que l’on souhaitent configurer. Dans l’exemple précédent, on retrouve dans l’ordre les 3 ressources suivantes :

  • WindowsFeature : S’assure que le rôle IIS est installée.
  • File : Vérifie que les fichiers sont bien présents sur le répertoire de destination.
  • Group : Constate que le groupe local Viewer existe.

Dans le cas où l’une des ressources retournerait un résultat incorrect alors l’opération serait réalisée afin de mettre l’ordinateur en conformité. Par exemple, pour les sources du site web (Ressource WebsiteDirectory), le fichier de configuration possède le chemin source et la destination.

Pour générer le fichier MOF, il faut appeler notre configuration comme une fonction Powershell :

001
TestDSC -OutputPath c:\DSCConfig

Le paramètre OutputPath (facultatif) définie le dossier où vont être stockés les fichiers de configuration. Le fichier créé portera le nom de la machine portant cette configuration (ici WEBSRV01).

A l’instar des fonctions, on peut utiliser des paramètres. Voici, un exemple similaire au précédent où l’on spécifie la source et la destination des fichiers du site web ainsi qu’une liste de nom d’ordinateur auxquels appliquer cette configuration.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
Configuration TestDSC 
{ 
 
  param(
    [Parameter(Mandatory=$true)]
    [String[]]$Computers,
    [Parameter(Mandatory=$true)]
    [String]$SourceWeb,
    [Parameter(Mandatory=$true)]
    [String]$DestinationWeb 
  )

  Node $Computers 
  { 
    WindowsFeature IIS 
    { 
      Ensure = “Present” 
      Name = “IIS-Server” 
    } 

    File DirectoryCopy
    {
        Ensure = "Present"
        Type = "Directory"
        Recurse = $true 
        SourcePath = $SourceWeb
        DestinationPath = $DestinationWeb 
    }

  } 
}

Il y aura autant de fichiers MOF générés que de noms dans le paramètre Computers. Voici la commande pour créer les fichiers MOF :

001
002
003
TestDSC -Computers @("WEBSRV01","WEBSRV02","WEBSRV03") `
-SourceWeb "\\FILESRV01\MyWebSite" -DestinationWeb "C:\inetpub\wwwroot\MyWebsite"`
-OutputPath c:\DSCConfig

Application d’une configuration

Ici, nous allons aborder brièvement l’application d’une configuration en local via le mode Push. Le détail de ce mode est expliqué dans la partie 2 de l’article sur Desired State Configuration. On utilise la commande Start-DscConfiguration. Voici l’explication des paramètres utilisées dans la commande ci-dessous :

  • Wait : Ne rend pas la main à l’utilisateur tant que la commande est en cours d’exécution (Par défaut l’exécution de DSC se fait en arrière plan).
  • Verbose : Affiche les opérations effectuées.
  • Path : Le dossier où se toruve le fichier MOF (DSC choisi le fichier portant le nom de l’ordinateur).
001
Start-DscConfiguration -Wait -Verbose -Path C:\DSCConfig

Il ne peut y avoir qu’une configuration active par machine. Si une seconde configuration est appliquée, il n’y aura plus de contrôle de conformité sur les ressources non présentes dans la nouvelle configuration.

Powershell : Gestion à distance

Introduction

L’une des forces de Powershell est la gestion à distance de serveurs, de postes clients et d’applications (comme Exchange, Sharepoint,…). Communément appelée Remote Powershell, elle est apparue avec Powershell 2.0 et donc disponible à partir de Windows Server 2003 (R2) SP2. Cette fonctionnalité n’est pas activée par défaut sur les systèmes d’exploitation Windows hors Windows 2012 (R2). Pour réaliser cette opération il faut lancer la commande suivante en mode administrateur :

001
Enable-PSRemoting

Cette commande permet de démarrer le service WinRM et d’ouvrir les règles de firewall adéquates si celui-ci est activé (port 5985).

Dans cet article, nous verrons comment se connecter à une machine (qu’elle soit dans le même domaine ou dans un workgroup) ou à une application comme Exchange, comment donner la possibilité à un utilisateur de se connecter via Remote Powershell et enfin l’accès WMI distant.

Entre deux ordinateurs du domaine

Il s’agit du cas le plus simple. Pour se connecter à une machine du même domaine, il suffit d’utiliser la commande suivante :

001
Enter-PSSession -ComputerName SERVER01

Il est possible de spécifier l’utilisateur avec lequel on souhaite se connecter via le paramètre Credential :

001
Enter-PSSession -ComputerName SERVER01 -Credential SERVER01\Administrator

Ainsi, un prompt demandant le mot de passe apparaîtra.

Depuis un ordinateur d’un workgroup vers un ordinateur en domaine (et vice versa)

Pour se connecter à une machine appartenant à un domaine différent ou à un workgroup, il est nécessaire que le poste source contienne l’ordinateur distant dans sa liste de client de confiance. Pour ajouter une nouvelle machine, il faut utiliser la commande suivante en mode administrateur :

001
002
003
Set-Item WSMan:\localhost\Client\TrustedHosts -Value *
#OU
Set-Item WSMan:\localhost\Client\TrustedHosts -Value SERVER02

Le paramètre Value peut prendre les valeurs suivantes :

  • un nom explicit d’une machine (SERV01)
  • * : pour accepter toutes les machines (Ceci n’est pas recommandé)
  • *.myenterprise.com : pour accepter toutes les machines possédant le suffixe DNS myenterprise.com

Connexion à distance à une application (Exchange)

Via le couple de commande New-PSSession / Import-PSSession, il est possible de se connecter à une infrastructure Exchange et importer les commandes relatives à la messagerie de Microsoft sur son poste sans avoir à installer le snapin. De plus, seul les commandes accessibles à l’utilisateur seront chargées sur le poste utilisateur (grâce aux mécanismes de RBAC).

001
002
$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri ` http://MYSERVER/powershell -Credential MYENTERPRISE\User_1
Import-PSSession $Session -AllowClobber | Out-Null

La première ligne de commande crée une session qui se connecte à l’infrastructure Exchange (Attention il faut modifier la valeur MYSERVER et le nom d’utilisateur avec vos valeurs) tandis que la seconde importe les commandes sur l’ordinateur initialisant la connexion.

Sessions distantes et permissions

Afin de se connecter à distance, il est nécessaire de faire partie du groupe Administrators (ou Remote Management Users pour Windows 2012 et supérieur) soit en étant connecté directement avec le bon compte (par exemple via un utilisateur administrateur du domaine) soit en s’authentifiant en tant qu’administrateur via le paramètre Credential vu précédemment. Il est aussi possible de donner l’accès à d’autres utilisateurs via la commande suivante :

001
002
003
Set-PSSessionConfiguration Microsoft.Powershell -ShowSecurityDescriptorUI -Force
#Si l'on est sur un système 64 bits.
Set-PSSessionConfiguration Microsoft.Powershell32 -ShowSecurityDescriptorUI -Force

Une fenêtre s’affiche et il est possible d’ajouter un utilisateur ou un groupe (via le bouton Add) ainsi que des permissions associées. La permission Execute est suffisante  pour se connecter à distance.

image

NB : Sur Windows 2012 et supérieur, il est nécessaire d’ajouter une clé de registre sur l’ordinateur distant pour que les groupes Administrators et Remote Management Users aient le droit de se connecter via Remote Powershell :

Dans le noeud : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system

Il faut ajouter la clé DWord : LocalAccountTokenFilterPolicy avec la valeur 1.

Cette clé de registre s’applique aussi au chapitre suivant.

Gestion WMI à distance

Pour gérer le WMI à distance (via la commande Set-WmiInstance par exemple). Il faut réunir les 3 conditions suivantes sur le serveur auquel on souhaite se connecter :

  • Faire partie du groupe Administrators ou Remote Management Users ou WinRMRemoteWMIUsers__.
  • Avoir les permissions suffisantes sur la classe WMI.
  • Autoriser l’utilisateur dans la configuration DCOM du serveur.

Les deux dernières conditions sont seulement utiles dans le cas d’un utilisateur qui ne fait pas partie du groupe Administrators (ce dernier possède déjà toutes les permissions nécessaires).

    Gestion des permissions via WMI Control :
Pour cette opération il faut lancer une console MMC et ajouter le composant WMI Control. Effectuer un clic droit et choissisez Properties puis naviguer dans l’onglet Security. Dans la MMC, on sélectionne l’espace de noms qui nous intéresse et on clique sur le bouton Security. Cliquez sur Advanced (cette option plus complète, permet éventuellement d’étendre les permissions au classes enfantes).

image image

On ajoute l’utilisateur ou le groupe avec au minimum les permissions Enable Account et Remote Enable. Il sera surement nécessaire d’ajouter d’autres droits suivants l’action que l’on souhaite réaliser.

image

Autorisation de l’utilisateur dans la configuration DCOM :

En lançant la console dcomcnfg, aller dans Component Services, Computers, My Computer et effectuer un clic droit et choisir Properties.

Dans l’onglet COM Security, choisir Edit Limits dans la section Launch and Activation Permissions. Ajoutez l’utilisateur ou le groupe souhaité et activez l’ensemble des permissions pour avoir accès en local et à distance en WMI via Powershell.

image image

Quelques astuces Powershell

Introduction

Lorsque l'on développe des scripts Powershell, il y a un certain nombres de commandes génériques que l'on réutilise très souvent. Nous verrons aussi quelques astuces qui peuvent être utiles dans de nombreux scripts.

Astuces

Retrouver le dossier d'exécution du script :

Souvent, il arrive que l'on crée une bibliothèque de scripts. Un script peut en appeler un autre parce qu'il contient des fonctions. On peut aussi vouloir faire appel à un fichier de configuration. Beaucoup de scripts contiennent alors le chemin d'exécution via une variable qu'il convient de changer manuellement dès que le répertoire est modifié. Cela n'est cependant pas très portatif. Il est nettement plus intéressant de retrouver ce chemin dynamiquement.

La commande ci-dessous permet de retourner le dossier où se situe le script qui est en train de s'exécuter.

001
002
$RootFolder = Split-Path -Path $MyInvocation.MyCommand.Path 

On peut ensuite retrouver nos fichiers additionnels via des chemins relatifs calculés depuis celui que l'on vient de récupérer.

"$MyInvocation.MyCommand.Path" retourne le chemin du fichier.
A partir de ce dernier la commande "Split-Path" nous retourne uniquement le dossier dans lequel est contenu le script.

Connaître le contexte d'exécution (32 ou 64 bits) :

Il peut arriver que l'on souhaite lancer un exécutable spécifiquement depuis une instance Powershell x86 ou x64 car celui-ci n'existe pas dans un autre contexte.

Pour cela, il existe une astuce permettant de savoir quelle édition de Powershell (x86 ou x64) est lancée :

001
002
[System.IntPtr]::Size 

Cette commande nous donne la taille d'un pointeur sous la forme d'un entier. Lorsque l'invite de commande Powershell est en x64, cette valeur vaut 8. Dans le cas contraire il s'agit de 4. On peut facilement imaginer une structure conditionnel permettant de relancer un script automatiquement en Powershell x86 qui intègre un exécutable ne tournant que sur cette version.

001
002
003
004
005
006
if( [System.IntPtr]::Size -ne 4) { 
    #Chemin du script
    $Path = $myInvocation.InvocationName 
    #Invocation de Powershell x86 avec le même script à exécuter comme paramètre
    $Return = &"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe" $Path 
}

Le script est-il exécuté en mode administrateur :

Dans le même esprit, il est possible de savoir si un script a été lancé en mode administrateur. En effet, certaines opérations peuvent exiger ce mode de fonctionnement :

001
002
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")

Bien évidemment il n'existe pas de commande pour relancer le script dans ce mode. On peut cependant inviter l'utilisateur à le faire.

Tester son script pour une autre version de Powershell :

Il peut arriver que l'on développe son script Powershell sur son poste client qui est en version 3 alors que le serveur qui le lance est lui en version 2. Afin d'être certain que ce script est compatible, il est possible d'indiquer la version de Powershell à utiliser. En voici un exemple ci-dessous :

test version

En version 3 il n'est plus nécessaire de faire d'Import-Module pour utiliser les cmdlets Active Directory, ce qui n'est pas le cas en Powershell 2. Nous voyons donc clairement la différence entre les 2 exécutions.

Appeler une librairie .NET :

Il existe de nombreuses méthodes pour charger une librairie .NET (sous forme de dll ou directement de code C# par exemple). Ici, nous en verrons une qui utilise la commande Powershell Add-Type :

Pour utiliser les Windows forms pour les interfaces graphiques.

001
002
Add-Type -AssemblyName "System.Windows.Forms"

Pour administrer IIS, on charge une dll depuis son emplacement sur le disque

001
002
Add-Type -Path "c:\windows\system32\inetsrv\microsoft.web.administration.dll"

Intégrer directement du code C# (il est aussi possible de le faire avec du code VBScript)

001
002
003
004
005
006
007
008
009
010
011
012
Main; Add-Type -TypeDefinition @"
public class Test
{
    public string Name {get;set;}
    public int Size {get;set;}
    public Test(string Name, int Size){
        this.Name = Name;
        this.Size = Size;
    }
}
"@

Toutefois lorsque la commande Add-Type sera exécutée il n'est pas possible de recharger une librairie qui aurait été modifiée (Cela est dû à .NET). En effet une librairie ne peut être déchargée. Il faut alors changer de session Powershell (c'est à dire lancer une nouvelle instance de Powershell).

Interaction Powershell - Exchange Web Services

Introduction

Avec Exchange 2010, pour certains besoins bien spécifiques, il se peut que les cmdlets Powershell soit limitées. Cependant, il existe aussi les Exchanges Web Services. Bien entendu, quand on parle des Exchange Web Services, on pense au C# et à un développement complexe. Cependant, on n'oublie souvent que Powershell permet d'exécuter du C#.
Il sera donc question d'accéder aux EWS via Powershell. Il s'agit surtout d'une introduction car les possibilités de scripting sont infinies. L'exemple mis en œuvre dans cet article montrera comment accéder à un dossier bien spécifique pour le purger suivant les dates de réception des emails. Cela permettra entre autres de voir le langage AQS permettant la recherche d'objets dans une boîte aux lettres Exchange.

Prérequis

Avant toute chose, pour manipuler l'API Exchange Web Services, il est nécessaire d'installer le package correspondant sur le poste qui exécutera le script. Il est trouvable en suivant ce lien : http://www.microsoft.com/en-us/download/details.aspx?id=28952

Attention si vous utilisez, Exchange 2013, il faut prendre cette version :
http://www.microsoft.com/en-us/download/details.aspx?id=35371

Il sera ensuite nécessaire d'ajouter dans chacun des scripts qui sera réalisé la dll permettant d'interagir avec les Web Services. Pour rappel, cela se réalise via la commande Powershell Add-Type :

001
002
003
Add-Type -path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"


AQS ou Advanced Query Syntax:

Le langage AQS permet de réaliser des recherches dans les objets d'une boîte aux lettres Exchange. Il est très simple à prendre en main.

Pour comprendre toutes les possibilités de ce langage voici le lien MSDN dédié :
http://msdn.microsoft.com/en-us/library/ee693615.aspx

Grâce à ce langage il va être possible de rechercher des éléments :
- par type (emails, réunions, notes, contacts, ...)
- par date (réception ou envoi)
- par propriété d'un email (champ from, to, cc, subject, body, ...)

L'exemple suivant permet de rechercher des emails ayant été reçu le 3 Septembre 2013 :
"Kind:email AND Received:03/09/2013"

On remarque l'opérateur AND qui permet de prendre en compte 2 propositions. Il en existe d'autres comme le OU (l'une ou l'autre des propositions) et le NOT (l'inverse d'une proposition).

Script commenté

Il s'agit ici d'un script où l'utilisateur se connecte à une boîte aux lettres sur laquelle il possède des droits et dont les messages du dossier nommé Personnel seront supprimées s'ils datent de plus de 30 jours. Aussi, pour chaque dossier, il affiche la taille de celui-ci en Ko. Cette dernière opération est aussi faisable via la commande EMS Get-MailboxFolderStatistics mais avec cette exemple nous n'aurons pas besoin d'installer ces outils mais seulement l'API EWS beaucoup plus légère.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
#Mailbox à traiter
$MailboxName = 'j.dupont@myenterprise.fr'

# A installer avant : www.microsoft.com/en-us/download/details.aspx?id=28952
try{
    Add-Type -path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
}catch{

}

#On spécifie la version des web services
$Version = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($version)

#On utilise les credentials avec lesquels on est connecté
$Service.UseDefaultCredentials = $true

#On récupère la configuration Autodiscover pour se connecter à la BAL
$Service.AutodiscoverUrl($MailboxName,{$true})

#On récupère l'ID du dossier
$RootFolderID = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)

#On se connecte au dossier via la connexion que l'on a initialisé
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,$RootFolderID)

#On limite le nombre de dossier à analyser à 1000 (sinon problème de throttling)
$FolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)

#On définit un ensemble de propriété à récupérer en même temps que nos dossiers
$PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
#On crée une propriété de type taille de dossier
$SizeObject = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(3592,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Long)
#On l'ajouter à notre vue de dossier afin que la taille soit aussi récupérée.
$PropertySet.Add($SizeObject); 
$FolderView.PropertySet = $PropertySet;

#On spécifie qu'on analyse l'intégralité de la hiérarchie
$FolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep

#On calcule la date d'il y a 30 jours et on la met au format dd/MM/yyyy
$DateOld = ((Get-Date).AddDays(-30)).ToString("dd/MM/yyyy")

#On récupère tous les dossiers
$Response = $RootFolder.FindFolders($FolderView)
#Pour chaque dossier
ForEach ($Folder in $Response.Folders) {
   
    $FolderSize = $null
    #Si la taille est disponible alors on l'export dans la variable $FolderSize
    if($Folder.TryGetProperty($SizeObject,[ref] $FolderSize)){
        $FolderSizeValue = ([Int64]$FolderSize)/1000 
        #On affiche la taille du dossier
        $Message = "Le dossier " + $Folder.DisplayName + " a une taille de $FolderSizeValue Ko"
        Write-Host $Message
    }else{
        $Message = "Taille du dossier " + $Folder.DisplayName +" introuvable."
        Write-host $Message
    }

    #On compare le display name avec la valeur recherchée
    if($Folder.DisplayName -eq "Personnel"){
        #Si le dossier est bien Personnel alors on récupère tous les mails selon les critères de date définies
        $Items = $Folder.FindItems("Kind:email AND Received:<$DateOld",$ItemView) 
        #Pour chaque email trouvée
        ForEach($Item in $Items){
            #On le supprime définitivement (à décommenter pour que ce soit effectif)
            #$Item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
    }
}

 

On remarque l’opérateur “<” (inférieur à) dans la requête AQS qui permet de spécifier tout ce qui se trouve avant cette date.

On peut accéder aux dossiers publics, modifier, supprimer, créer, tout type d'objet y compris des dossiers. Il est aussi possible de récupérer différentes informations comme la taille d'un dossier. Il est aussi possible d'analyser les pièces jointes pour supprimer celle dont l'extension est d'un certain type. Il est donc possible d'imaginer plein de scripts comme des tâches planifiées effectuant des traitement sur des boîtes aux lettres.

Manipuler les enregistrements DNS en Powershell 2

Problème rencontré

Lors d'un changement complet du plan d'adressage des serveurs d’un datacenter, il était nécessaire de changer les enregistrements DNS. Au delà des enregistrements NS des serveurs DNS, il fallait aussi mettre à jour l'intégralité des enregistrements statiques A et PTR. Il était nécessaire de proposer une solution qui soit simple à mettre en œuvre (peu d’intervention utilisateur), puisque près de 600 enregistrements était à modifier. Il n'était pas faisable de faire cela manuellement.

Solution proposée

Comme indiqué dans l'intitulé, il a été choisi que cette opération serait réalisée par un script Powershell. Actuellement, il y a encore peu de parcs informatique utilisant Powershell 3 avec le module DNS pour Windows 8/2012. Le module DNS fournit par Powershell 3 peut donc seulement être utilisé dans des cas très limités. La solution proposée utilisait les classes WMI. Il s'agissait ensuite de loguer un maximum d'informations pour avoir un maximum de contrôle sur les modifications apportées.

Les classes WMI

Voici un listing des classes WMI pour les enregistrements DNS les plus courants :
- Enregistrements PTR : MicrosoftDNS_PTRType
- Enregistrements A : MicrosoftDNS_AType
- Enregistrements CNAME : MicrosoftDNS_CNAMEType
- Enregistrements MX : MicrosoftDNS_MXType
- Enregistrements NS : MicrosoftDNS_NSType

Récupération d'enregistrements DNS

Voici un exemple de récupération d'un enregistrement A.

On déclare la zone dans laquelle on veut effectuer la recherche.

001
002
$DNSZone = "myenterprise.lan"

 

On définit le serveur DNS sur lequel on effectue la recherche.

001
002
$DNSServer = "SRVDNS01" 

 

On cherche l'enregistrement via l'attribut OwnerName qui est le nom DNS complet.

001
002
$OwnerName = "SRV01.$DNSZone" 

 

On utilise une requête WMI sur le serveur DNS avec un filtre sur la zone et l'enregistrement à chercher.

001
002
003
004
$Record = Get-WMIObject -Computer $DNSServer `
-Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType" `
-Filter "ContainerName='$DNSZone' AND OwnerName='$OwnerName'" 

Si l'on souhaite obtenir toutes les propriétés de cet enregistrement et notamment voir les autres attributs sur lesquels on peut effectuer une recherche il suffit d'appeler la variable : $Record

Mis à jour d'enregistrements DNS :

En reprenant l'enregistrement précédent, on peut rapidement modifier son addresse IP (ou TTL) via la méthode Modify().

001
002
$NewRecord = $Record.Modify($Record.TTL, "10.0.1.1") 

 

Détecter si un enregistrement est dynamique :

Aussi, il peut être intéressant de ne mettre à jour que les enregistrements statiques. On peut détecter les enregistrements dynamiques via leur timestamp qui n'est pas nulle :

001
002
003
004
if($Record.Timestamp -ne 0){ 
    $NewRecord = $Record.Modify($Record.TTL, "$newRecordAddress") 
} 

Il suffit donc juste d'utiliser une structure conditionnelle si sinon sur l'attribut timestamp de notre enregistrement DNS.

Exemple avec un enregistrement PTR :

Pour réaliser cette opération on réutilise les variables $DNSServer, $DNSZone et $OwnerName déclarées plus haut et définir la zone où chercher l'enregistrement PTR.

001
002
$DNSZonePTR = "10.in-addr.arpa" 

 

La syntaxe pour rechercher un enregistrement PTR est similaire. Seuls la classe WMI et le champ de recherche (PTRDomainName au lieu de Ownername).

001
002
003
004
$PTRRecord = Get-WMIObject -Computer $DNSServer `
-Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_PTRType" `
-Filter "ContainerName='$ZonePTR' AND PTRDomainName='$OwnerName.'" 

 

Attention, il n'est pas possible de modifier l'IP d'un enregistrement PTR, il faut d'abord supprimer l'enregistrement puis le recréer.

Avant, on récupère la TTL pour la réutiliser afin qu'elle soit identique lors du nouvel enregistrement :

001
002
$TTL = $PTRRecord.TTL 

 

On supprime l'enregistrement DNS en supprimant l'objet WMI

001
002
$PTRRecord | Remove-WmiObject 

 

On déclare la nouvelle valeur de notre enregistrement. Si IP vaut 10.B.C.D dans la zone "10.in-addr.arpa" alors celui-ci vaudra D.C.B.10.in-addr.arpa

001
002
$PTROwnerName = "1.1.0.10.in-addr.arpa"

 

On déclare le type de notre enregistrement, ici PTR :

001
002
003
$PTRTypeClass = [WMIClass]"\\$DNSServer\root\MicrosoftDNS:MicrosoftDNS_PTRType" 

$PTRNewRecord = $PTRTypeClass.CreateInstanceFromPropertyData("$DNSServer.myenterprise.lan",$ZonePTR,$PTROwnerName,$null,$TTL,"$OwnerName.") 

 

Le 4ème attribut est dénommé record class : par défaut il s'agit de IN. La valeur à insérer est 1 ou $null.

Exemple sous Powershell v3 avec module DNS :

Pour terminer, voici comment réaliser les mêmes opérations (Récupération/Mis à jour d'enregistrements DNS) avec le module DNS Powershell v3. Il faut posséder un poste sous Windows 8/2012 pour exécuter ses commandes et avoir installé l'outil de gestion des serveurs DNS (via les outils d'administration).

On commence par déclarer la zone, le serveur DNS et le nom de l'enregistrement :

001
002
003
004
005
$DNSZone = "myenterprise.lan" 
$DNSServer = "DNS01" 
$RecordName = "SERV01" 
$NewRecordAddress = "10.0.1.1" 

 

Le type est renseigné dans le paramètre RRType. Attention, il est important de stocker l'objet dans une variable car nous allons le réutiliser pour le modifier.

001
002
003
$Record = Get-DnsServerResourceRecord -ZoneName "$DNSZone" -Name "$RecordName" `
-RRType "A" -ComputerName "$DNSServer" 

 

Pour valider les modifications nous aurons besoin de l'enregistrement DNS avant et après sa mise à jour. Il faut donc réaliser une deuxième récupération de l'enregistrement DNS dans une autre variable.

001
002
003
$NewRecord = Get-DnsServerResourceRecord -ZoneName "$DNSZone" -Name "$RecordName" `
-RRType "A" -ComputerName "$DNSServer" 

 

Ensuite, il faut modifier la propriété qui nous intéresse, ici l'adresse IP.

001
002
$NewRecord.RecordData.IPv4Address.IPAddressToString = "$NewRecordAddress" 

 

Enfin, on enregistre les modifications en passant les 2 objets (avant et après modification), la zone et le nom du serveur DNS :

001
002
003
Set-DnsServerResourceRecord -NewInputObject $NewRecord -OldInputObject $Record -ZoneName "$DNSZone" `
-ComputerName "$DNSServer" 

Powershell v3.0 : Les Workflows

Introduction

L'une des grandes nouveautés de Powershell 3.0 est l'intégration des Workflows. Pour généraliser ceux-ci représente une série d'action sur lesquels on va pouvoir effectuer des actions pendant l'exécution. Concrètement, grâce à ceux-ci nous pouvons désormais :
- Paralléliser l'exécution d'actions indépendantes les unes des autres. Cela était déjà faisable via les jobs mais la syntaxe des Workflow est orientée pour les traitements lourds.
- Interrompre puis reprendre des tâches.
- Placer des checkpoints permettant de reprendre des traitements à un endroit donné. Par exemple, si le workflow crashe, nous pouvons reprendre son exécution à partir du checkpoint et non dès le début.

Exemple d’utilisation

On peut imaginer toute sorte d'utilisation :
- Réaliser des pings en parallèle sur des ordinateurs (Traitement sur de multiples postes en même temps).
- Renommer un ordinateur puis reprendre l'exécution du workflow une fois le poste redémarré pour qu'il envoi un mail de confirmation à un administrateur (ou qu'il effectue un traitement).
- La création de machines virtuelles en parallèle.  Puis, on réalise un checkpoint, puisqu'elles n'auront plus à être recréées. Enfin on démarre les machines virtuelles en parallèle et on leurs fait rejoindre le domaine de l'entreprise.
- Créer parallèlement de nombreux ordres de déplacement de boîtes aux lettres dans le cas d'une migration Exchange.
- Créer un workflow contenant d'autres workflows tous exécuté en parallèle (Récupération en même temps, des comptes Active Directory désactivés, expiré, et verrouillé).

Tests et syntaxe

Ici, nous verrons comment implémentés les concepts que l'on a énoncé dans nos scripts. Les différents exemples se veulent simples afin de se focaliser sur la syntaxe.

La syntaxe est similaire au fonction. En effet, seul le mot clé diffère. Il s'agit de "workflow". L'appel au workflow se fait de la même façon que les fonctions.

Tout d'abord, nous allons comparer le temps d'exécution d'un workflow qui exécute 2 pauses d'une seconde en parallèle et une fonction qui réalise la même opération les unes à la suite des autres. Aussi au niveau de la syntaxe, on remarque que ce qui est parallélisé se trouve dans un block de code (entre accolades) précédé du mot clé "parallel".

03

Le résultat montre bien la différence entre les 2 modes d'exécution, puisque le workflow se réalise en un peu plus d'une seconde contre 2 pour la fonction.

04

A l'intérieur d'un bloc "parallel", il est possible d'insérer un bloc "sequence" pour être certain que les actions contenu dans celui-ci ne seront pas parallélisées. 

01

Le résultat obtenu permet de constater que les actions en parallèle s'exécute dans un ordre indéterminable (ici, le résultat de la ligne 9 s'affiche avant celui de la ligne 6 par exemple).

02

Il est aussi possible de gérer une boucle "ForEach" au travers de multiples exécution simultanées. Il suffit d'ajouter le paramètre "parallel".

09

Certaines commandes ne peuvent être traitées par le framework Workflow, il faut donc les inscrire dans un bloc "inlinescript". En voici un exemple avec "Get-ChildItem".

05

Pour qu'une variable déclaré dans un workflow soit accessible dans un bloc "inlinescript", il faut le préfixer par le mot clé "using:". Ci ce n'est pas le cas, alors Powershell est incapable de retrouver la valeur.

0607

Il en est de même si l'on souhaite modifier une valeur déclarer en dehors d'un bloc "parallel". Il faudra que celui-ci soit préfixé du mot "workflow:".

08

Enfin, le dernier thème abordé, sera celui de la sauvegarde, de la mise en pause et de la reprise d'un workflow.

Tout d'abord, la commande "Checkpoint-Workflow" permet de sauvegarder l'état d'un workflow. Ainsi, si celui-ci s'arrête à cause d'une erreur notamment, il pourra être repris à l'endroit où il s'est arrêté. Cela peut être intéressant pour éviter de ré exécuter des traitements lourds.

"Suspend Workflow" permet quant à elle de mettre en pause un traitement. Cette commande intègre automatiquement un checkpoint implicite afin de reprendre plus tard le workflow où il s'est arrêté.

Lorsqu'un workflow est suspendu via "Suspend-Workflow" ou une autre commande comme "Restart-Computer", il est possible de reprendre un traitement en cours via 2 méthodes. La première est manuelle.Lorsque l'on exécute le code ci-dessous, un job est créé. Grâce à l'un de ces attributs comme le nom ou l'ID , il est possible de redémarrer le workflow.

11

10

Pour l'exemple ci-dessous la commande à exécuter serait :

Get-Job -Name Job2 | Resume-Job -Wait

Afin de réaliser la même chose de façon automatisée, on crée un nouveau "job trigger". Celui-ci va nous permettre de gérer de l'évènementiel (lancer une tâche automatiquement à un moment donné).

L'exemple ci-dessous montre la création d'un "job trigger" qui lancera une tâche au démarrage. Cette dernière récupère le Workflow en suspend (ici "Myjob"), et le reprend. Contrairement à l'exemple précédent, on remarque qu'il est possible de définir le nom du job que prendre le workflow. En effet, lorsque l'on invoke un workflow, il existe le paramètre "JobName" qui permet de spécifier ce nom. Ce dernier est un paramètre qui existera pour n'importe quel workflow qui sera créé.

12

Powershell : Définir la liste d'adresse par défaut d'Outlook

Problème rencontré

Lors d'une migration Exchange inter organisation visant à la consolidation des infrastructure de messagerie des filiales d'une entreprise, il s'est présenté la problématique suivante. Il fallait que les utilisateurs aient accès dans leur client Outlook à une liste d'adresse correspondant à leur filiale. Cette dernière devait être la liste visible par défaut.

Solution proposée

Pour se faire, il est nécessaire de modifier une clé de registre sur les postes clients.
Dans la ruche : "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\", sont listés les profiles du client Outlook. Une ruche est présente dans chacun de ceux-ci : "9207f3e0a3b11019908b08002b2a56c2". Celle-ci contient la clé "01023d06" qui définit la liste d'adresse qui sera affiché par défaut à l'ouverture du carnet d'adresse. Attention la valeur est encodé au format Bytes HEX. Nous verrons comment la définir.

S'agissant d'appliquer une modification du registre à l'ensemble des postes clients d'une filiale, la solution la plus simple était d'implémenter cela dans le login script. Cela sera fait en Powershell. Il est bien entendu aussi possible de réaliser cette opération en VBS.
 
Il est à savoir que la vue par défaut du carnet d'adresse est la "Global Address List". De plus, si une valeur erronée est inscrite dans la clé de registre (ne correspondant à aucune liste d'adresse) alors Outlook repositionnera automatiquement le carnet d'adresse sur la liste d'adresse globale.

Récupération des paramètres

Afin de connaitre la valeur que nous devons positionner sur la clé "01023d06", il faut paramétrer manuellement Outlook afin de récupérer la valeur que l’on devra positionner. Pour cela, on définit la liste d’adresse sur laquelle on souhaite que nos utilisateurs se trouvent par défaut.

3

Ensuite, on peut ouvrir la clé de registre qui nous intéresse et observer sa valeur.

1

Si l'on modifie plusieurs fois cette valeur, on remarque le phénomène suivant. Elle se découpe en 3 parties :
- Une première qui est généré dynamiquement par utilisateur (avant le trait rouge)
- Une seconde qui est fixe qui va nous être utile pour récupérer la partie dynamique (entre le trait rouge et vert).
- Une troisième partie fixe (après le trait vert).

Ces trois éléments ont toujours une longueur fixe.

Il faut ensuite reformater les deux dernières parties sous forme de tableau de bytes. Il suffit devant chaque valeur en byte d’ajouter “0x” et de mettre une virgule entre toutes les bytes (syntaxe d'un tableau en Powershell).
Exemple :

01 00 00 00 00 01 00 00 2F devient 0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x2F. Dans le script cette valeur sera définit par la variable $GALSuffix.

67 75 69 64 3D 38 42 34 39 43 31 36 34 45 44 35 41 36 34 30 39 34 42 30 42 4236 35 43 34 45 38 46 39 42 39 00 devient 0x67,0x75,0x69,0x64,0x3D,0x34,0x38,0x42,0x34,0x39,0x43, 0x31,0x36,0x34,0x45,0x44,0x35,0x41,0x36,0x34,0x30,0x39,0x34,0x42,0x30,0x42,0x42, 0x36,0x35,0x43,0x34,0x45,0x38,0x46,0x39,0x42,0x39,0x00.

Dans le script cette valeur sera définit par la variable $GALDefaultValue.

Script

Ci-dessous, le script commenté, où l'on va appliquer les paramètres que l'on a récupéré précédemment. Ceux-ci seront comparés avec ceux que l'on retrouve dans la clé de registre "11023d05" qui contient une configuration de sauvegarde. Cela permet de récupérer la première partie qui est dynamique.

2

Entre la ligne 37 et 47 on compare un à un les bytes rencontrés dans la clé de registre "11023d05" afin de retrouver l’index ou se trouve le tableau de bytes contenu dans $GALSuffix. Une fois cette valeur obtenue, on sait que la partie dynamique à rechercher est définie dans les 20 bytes précédentes.

Contrôle à distance de Sharepoint via Powershell

Introduction

L'une des forces de Powershell est de pouvoir administrer des produits directement depuis un poste client sans avoir à installer des outils d'administration. Hormis dans certains cas particuliers comme Exchange Online, il n'est pas non plus nécessaire d'ajouter des modules ou snapin Powershell sur notre ordinateur. Ceux-ci sont déjà présents sur le serveur distant, il est donc possible de les réutiliser. Dans cet article nous verrons le cas de Sharepoint pour lequel j'ai rencontré une petite subtilité.

Connexion à distance

Tout d'abord nous allons initier une nouvelle PSSession. Pour rappel, ce sont elles qui nous permettent d'interagir avec un serveur à distance. Elles ont été introduites à partir de Powershell v2.0.

On commence par stocker les paramètres d'authentification dans une variable.

$Credential = Get-Credential

On crée une variable avec le serveur sur lequel on souhaite se connecter

$Server =  "XXXXXXXXXX"

On génère une nouvelle PSSession en spécifiant les deux paramètres précédents. Celle-ci est stocké dans une variable car nous allons la réutiliser.

$Session = New-PSSession –ComputerName $Server -Credential $Credential

Ensuite, nous allons utiliser, la Cmdlet Invoke-Command afin d'exécuter une commande dans la session distante que nous venons de créer.

Invoke-Command -ScriptBlock {$ver = $host | select version; if ($ver.Version.Major -gt 1) {$Host.Runspace.ThreadOptions = "ReuseThread"}; Add-PSSnapin Microsoft.SharePoint.PowerShell;} -Session $Session

Il est nécessaire de préciser la session sur lequel va être réalisé le bloc de commandes. Un scriptblock est exécuté. Si la version de Powershell est supérieur à 1 alors on positionne l'interpréteur pour réutilisé constamment le même thread. Ceci est une configuration obligatoire si l'on souhaite ajouter le snapin Sharepoint. Nous pouvons le retrouver dans le fichier “sharepoint.ps1” qui est lancé par le Sharepoint Management Shell.

Enfin nous pouvons importer la session. Avec cette méthode l'intégralité des commandes sera utilisable directement depuis le poste client.

Import-PSSession $Session -AllowClobber

Erreur rencontrée

Lorsque l'on effectue une connexion a distance il se peut que l'on obtienne l'erreur suivante :

Import-PSSession : L’exécution de la commande Get-Command dans la session à distance a signalé l’erreur suivante: Le traitement de données pour une commande distante
a échoué avec le message d'erreur suivant: <f:WSManFault xmlns:f="
http://schemas.microsoft.com/wbem/wsman/1/wsmanfault" Code="3762507597"
Machine="XXXXXXXXXXXXXXXXXXX"><f:Message><f:ProviderFault provider="microsoft.powershell"
path="C:\Windows\system32\pwrshplugin.dll"></f:ProviderFault></f:Message></f:WSManFault> Pour plus d'informations, voir la rubrique d'aide
about_Remote_Troubleshooting...

Cette dernière signifie qu'il n'y a pas assez de mémoire disponible pour charger les commandes. En effet, les commandes Sharepoint sont très consommatrice en mémoire. Bien entendu, il existe un paramétrage pour pallier à ce problème.

Paramétrage serveur

Afin de corriger cette erreur, il faut augmenter la quantité de mémoire maximum allouée pour un shell distant. Il est recommandé pour Sharepoint de définir cette valeur à 1000 MB.

Pour réaliser cette étape il suffit de modifier la valeur MaxMemoryPerShellMB via le provider WSMan permetant d'accéder à la configuration des connexions distantes. Par défaut la valeur est à 100 MB.

Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1000

Powershell : Modifier l'affichage d'un compte sous Outlook 2010

Introduction

Dans le cadre d'une migration inter-organization Exchange 2003 vers Exchange 2010, il fallait reconfigurer le profil pour que le nom de compte dans Outlook 2010 soit mis à jour avec la nouvelle adresse email (ainsi que le nom des arborescences des emails et de dossiers publics associées).

Blog1blog2

Afin de répondre à cette problématique en impactant le moins d'utilisateurs possibles, la solution proposée réalisait des modifications via un script déployer en GPO (logon script).
Ci-dessous vous trouverez les informations nécessaires à ce paramétrage via Powershell.

Récupération des informations de comptes

Afin d'effectuer ces modifications il faut aller les chercher dans le registre.
Ainsi, la ruche "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\" liste tout les profiles Outlook enregistré (par défaut le premier profil est appelé Outlook) pour l'utilisateur connecté.
Dans les ruches enfantes, si la clé de registre 001f6620 est présente c'est qu'il s'agit d'un compte Outlook. Cette dernière définit le nom du compte.

De plus, toujours dans les ruches sous-jacentes au nom d'un profile, si la clé 0003660a est positionné alors il s'agit d'une arborescence de emails ou de dossiers publics (ce sont celles qui nous intéressent dans le cas d'un changement de nom).
Si elle a la valeur "0x03,0x00,0x00,0x00" c'est qu'elle représente une arborescence de dossiers publics tandis que "0x01,0x00,0x00,0x00" représente la même chose pour des emails.
Le nom de l'arborescence est contenu dans la clé 001f3001.

Avec ces informations nous pouvons donc facilement retrouver le nom d'un compte et le profile associé pour le modifier. Pour modifier les noms des arborescences, nous avons les clés de registres à changer.

Modification du nom de compte

Pour modifier le nom du compte il n'existe actuellement qu'une seule méthode puisque la propriété du accessible via la librairie Interop (permettant d'interagir avec Outlook) n'est accessible qu'en lecture seule. Un module Powershell a été développé pour gérer les comptes Outlook : Outlook Account Manager. Il est disponible à cette adresse : http://psoutlookmanager.codeplex.com/

Il propose un jeu de commandes permettant de récupérer les profiles (Get-Profile), les comptes (Get-MAPIAccount) et de modifier ces derniers (Set-MAPIAccount).

Voici un exemple permettant le modification du nom d'un compte :

On récupère le compte Outlook que l'on souhaite renommer (Il faut spécifier le profil)
$Account = Get-MAPIAccount -ProfileName "Nom du profil" | Where-Object `   {$_.AccountName -eq "Mon compte à modifier"}
On change l'attribut AccountName avec le nouveau nom que l'on souhaite obtenir.
$Account.AccountName = "Nouveau nom"
On enregistre les changements sur le compte que l'on a mis à jour.
Set-MAPIAccount $Account

Il est à noter que le module Outlook Account Manager ne s'exécute qu'avec Powershell 32 bits. On peut donc lancer le script via la commande ci-dessous :
&"$env:windir\syswow64\windowspowershell\v1.0\powershell.exe" $Path
$Path représente ici le chemin du script.

Cette méthode peut être exécuter pendant qu'Outlook est lancé. Le résultat sera visible dès l'exécution du script (sans avoir à redémarrer Outlook).

Modification du nom d'affichage

Pour mettre à jour le nom d'affichage dans l'arborescence Outlook, il existe plusieurs méthodes.

La première, consiste à utiliser les classes Interop Outlook. Cela va lancer un processus Outlook en tâche de fond.
Tout d'abord on invoque une instance d'Outlook
$Outlook = New-Object -comObject Outlook.Application
$Namespace = $Outlook.GetNamespace("MAPI")

Permet d'obtenir tous les comptes.
$Accounts = $Namespace.Accounts

Cette méthode présente l'avantage d'obtenir un résultat visible même si Outlook est lancé (sans avoir à le redémarrer). Cependant, l'utilisateur sera prompté pour lui dire qu'un autre processus souhaite accéder à Outlook, et cela nécessitera donc une intervention manuelle. Il peut aussi être concevable de fermer toutes les instances d'Outlook avant d'exécuter ce script, ce qui peut être déroutant pour l'utilisateur.

Voici un exemple de code permettant la dernière proposition :
$OutlookProcesses = Get-Process | Where-Object {$_.Name -like "Outlook"}
ForEach($Outlook in $OutlookProcesses){
    Stop-Process $Outlook.Id
}

A la fin du script on n'oublie pas de fermer le processus ouvert par la création de l'objet COM :
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Outlook)

La seconde méthode consiste à modifier directement la clé de registre. Pour mettre en œuvre cette opération il faut changer la valeur de la clé "001f3001" que l'on a identifier au préalable. Attention, le type de cette clé est un tableau de bytes. Bien qu'il soit possible de donner une chaine de caractère classique (String), tout en impactant pas le fonctionnement d'Outlook, cela va modifier le type. Voici donc un exemple pour créer un tableau de bytes à partir d'une chaine de caractère :

Exemple de résultat à obtenir :
blog4

On encode une String  en tableau de bytes
$enc = [system.Text.Encoding]::UTF8
$mystring = "This is a string"
$data = $enc.GetBytes($mystring)

Chaque caractère est séparé par une valeur en byte équivalente à un zéro. Pour que notre tableau soit correct il faut ajouter ce zéro après chaque caractère.
On crée un tableau modifiable (ArrayList)
$ArrayBytes = New-Object System.Collections.ArrayList
Entre chaque byte on ajoute un zéro.
foreach($d in $data){
    $ArrayBytes.Add($d)
    $ArrayBytes.Add(0)
}

Enfin on peut modifier la valeur de la clé de registre :

Set-ItemProperty "$RegistryPath" -Name 001f3001 -Value $ArrayBytes
$RegistryPath représente le chemin vers la clé de registre.

L'avantage de cette méthode est de n'avoir pas à exécuter de processus Outlook et l'utilisateur ne se rend pas compte du changement (pas de prompt ni de fermetures intempestives d'Outlook). Cependant si Outlook est lancé, le résultat ne sera visible qu'au prochain démarrage de celui-ci.