PI Services

Le blog des collaborateurs de PI Services

Powershell : Générer des fichiers Excel

Introduction

En Powershell, lorsque l'on souhaite exporter des données, le format de fichier le plus couramment prisé et le CSV (comma separated value). Cependant, il arrive souvent que ce fichier soit retravaillé avec de la mise en forme notamment. A ce moment là, il faut donc utiliser Excel et faire quelques clics... Heureusement, Microsoft fournit des classes C# accessibles en Powershell pour toute la suite Office. Il va donc être question de réaliser ces exports de façon automatisée avec la mise en page que l'on souhaite.

Utilisation d'Excel via Interop

Nous verrons ici les principales fonctions pour généré un fichier Excel et le mettre en forme. La totalité des fonctionnalités proposées étant disponible ici : 
http://msdn.microsoft.com/fr-fr/library/microsoft.office.interop.excel(v=office.11).aspx

Tout d'abord il faut appeler Excel en créant un nouvel.
$objExcel = new-object -comobject excel.application
On remarque que cette commande crée un processus Excel.
Pour accéder à un classeur il suffit d'utiliser cette commande (pour un fichier existant) :
$finalWorkBook = $objExcel.WorkBooks.Open($ExcelFilePath)
"$ExcelFilePath" représente le chemin du fichier que l'on souhaite ouvrir
S'il s'agit d'un nouveau fichier :
$finalWorkBook = $objExcel.Workbooks.Add()

Ensuite il est possible d'accéder à chaque onglet en précisant l'index dans la commande ci-dessous :
$finalWorkSheet = $finalWorkBook.Worksheets.Item(1)
Mais on peut aussi le renommer :
$finalWorkBook.Worksheets.Item(1).Name = "MyPSTab"

On peut ensuite accéder aux cellules de l'onglet :
$finalWorkSheet.Cells.Item(4,5) = "MyCell01"
Le premier chiffre est le numéro de la ligne et le second le numéro de la colonne (ci-dessus, ligne 4 - colonne 5). On peut donc facilement réaliser des boucles sur ces index pour changer de cellule.

Pour récupérer la valeur d'une cellule dans le cas où on se sert d'un fichier Excel en entrée d'un script :
myValue = $finalWorkSheet.Cells.Item(1,1).Text

Voici quelques commandes de mise en forme :
Pour mettre un texte en gras :
$finalWorkSheet.Cells.Item(1,4).Font.Bold
Pour surligner une cellule :
$finalWorkSheet.Cells.Item(3,2).Interior.ColorIndex = 42
Le nombre passé en paramètre correpond à une couleur.
Enfin pour ajuster la taille des colonnes automatiquement :
Pour une colonne spécifique (1 est l'index de la colonne):
$finalWorkSheet.Columns.Item(1).Autofit()
Pour l'intégralité du tableau :
$UR = $finalWorkSheet.UsedRange
$UR.EntireColumn.AutoFit()

Lorsque l'on souhaite sauvegarder un classeur Excel il existe deux méthodes. Dans le cas où le fichier existe :
$finalWorkBook.Save()
Si ce n'est pas le cas alors on utilise la méthode SaveAs avec le chemin du fichier :
$finalWorkBook.SaveAs(C:\TestExcelPS.xlsx)

Enfin, on n'oublie pas de fermer le processus ouvert par la création de l'objet COM :
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel)

Astuce : Si l'on souhaite voir le résultat pendant que le script s'exécute il suffit de rendre l'objet Excel visible en changeant la valeur de l'attribut éponyme :
$objExcel.Visible =$true

Script d'exemple

Ci-dessous un script réalisant un export des comptes désactivés d'un annuaire Active Directory. Ensuite, les comptes sont triés par unité d'organisation puis exporté dans un fichier Excel. A l'affichage chaque utilisateur est surligné d'une couleur différente en fonction de son unité d'organisation.

##################################################################

# Help                                                                                                        #

##################################################################

<#

    .SYNOPSIS

    Get Disabled Accounts      

    .DESCRIPTION

    Get Disabled Accounts, sort them by OU and Export by Excel or CSV

    .EXAMPLE

    01-Get-DisabledAccounts.ps1

    Description

    -----------

    Get Disabled Accounts, sort them by OU and Export by Excel or CSV

#>

##################################################################

# Main                                                                                                       #

##################################################################

# Récupération du chemin du fichier du script

$RootFolder = Split-Path -Path $MyInvocation.MyCommand.Definition

# Test de la présence du module Active Directory

if((Get-Module ActiveDirectory) -eq $null){

    try{

        Import-Module ActiveDirectory

    }catch{

        Write-Host "The execution computer doesn't have ActiveDirectory Powershell Module. The script can't continue." -ForegroundColor Red

        return

    }

}

# Création de l'objet application Excel sinon on réalise un export au format CSV

try{

    $objExcel = new-object -comobject excel.application

    Write-Host "Excel is installed on this Computer, disabled Users will be export in a fashioned excel file."

    $ExcelTest = $true

}catch{

    Write-Host "Excel is not installed on this Computer, disabled Users will be export in a plain old CSV file."

    $ExcelTest = $false

}

# Génération de la date du jour pour le nom du fichier d'export

$Date = Get-Date -Format ddMMyyyy

# Si Excel est disponible

if($ExcelTest){

    # Génération du chemin du fichier d'export

    Write-Host "Create Excel file"

    $ExcelPath = "$RootFolder\DisabledAccounts_$Date.xlsx"

   # Si le fichier Existe on l'ouvre

    if (Test-Path $ExcelPath) {

        $finalWorkBook = $objExcel.WorkBooks.Open($ExcelPath)

       # On choisi l'onglet sur lequel on travaille

        $finalWorkSheet = $finalWorkBook.Worksheets.Item(1)

        # Donne un nom au à l'onglet

        $finalWorkBook.Worksheets.Item(1).Name = "DisabledAccounts"

    }else{

        # Création d'un nouveau fichier

        $finalWorkBook = $objExcel.Workbooks.Add()

        $finalWorkSheet = $finalWorkBook.Worksheets.Item(1)

        $finalWorkBook.Worksheets.Item(1).Name = "DisabledAccounts"

    }

    #$objExcel.Visible =$true

    Write-Host "Create header"

   # Rempli la première ligne

    $finalWorkSheet.Cells.Item(1,1) = "SamAccountName"

    # Met le texte en gras

    $finalWorkSheet.Cells.Item(1,1).Font.Bold = $True

    $finalWorkSheet.Cells.Item(1,2) = "FirstName";

    $finalWorkSheet.Cells.Item(1,2).Font.Bold = $True

    $finalWorkSheet.Cells.Item(1,3) = "LastName"

    $finalWorkSheet.Cells.Item(1,3).Font.Bold = $True

    $finalWorkSheet.Cells.Item(1,4) = "LastLogonDate"

    $finalWorkSheet.Cells.Item(1,4).Font.Bold = $True

    $finalWorkSheet.Cells.Item(1,5) = "DistinguishedName"

    $finalWorkSheet.Cells.Item(1,5).Font.Bold = $True

}else{

    # Création du chemin du fichier CSV

    $CSVPath = "$RootFolder\DisabledAccounts_$Date.csv"

    # Création du header du fichier CSV

    $Header = "SamAccountName;FirstName;LastName;LastLogonDate;DistinguishedName"

    # Ecriture du header

    $Header | Out-File -FilePath $CSVPath

}

Write-Host "Rrieving data..." -ForegroundColor Green

# Récupération des utilisateurs désactivées

$ListUser = Get-ADUser -Filter {Enabled -eq $false} -Properties * | Select CanonicalName, CN, DistinguishedName, SamAccountName, GivenName, SurName, LastLogonDate, `

@{Name="OU";Expression={(($_.CanonicalName).Substring($_.CanonicalName.IndexOf("/")+1)).replace("/$($_.CN)","")}} `

| Sort-Object OU

Write-Host "Writing data..." -ForegroundColor Green

# On commence à la seconde ligne (la 1ère est consacrée au Header)

$FinalExcelRow = 2

# Choix d'une couleur pour surligner la ligne

$ColorIndex = 41

# Récupéraiton de l'OU du premier utilisateur

if($ListUser.Count -gt 0){

    $OU = $ListUser[0].OU

}

$i = 0

#On boucle sur chaque utilisateur

ForEach($User in $ListUser){

    #On affiche une barre de progression montrant le nombre d'utilisateur déjà traités

    $PercentComplete = [System.Math]::Round($($i*100/($ListUser.Count)),2)

    Write-Progress -Activity "Exporting data to Excel" -status "Effectué : $PercentComplete %" -percentcomplete $($i*100/($ListUser.Count))

    $i++

    if($ExcelTest){

        # Si l'OU est à changé on change aussi l'index de la couleur

        if($OU -ne $User.OU){

            $ColorIndex++

            if($ColorIndex -ge 56){

                $ColorIndex = 3

            }

        }

       # Récupéraiton de l'OU de l'utilisateur en cours

        $OU = $User.OU

        #On stocke les différentes valeurs

        $finalWorkSheet.Cells.Item($FinalExcelRow,1) = $User.SamAccountName

        #On attribut la couleur définit plus haut pour la case concerné

        $finalWorkSheet.Cells.Item($FinalExcelRow,1).Interior.ColorIndex = $ColorIndex

        $finalWorkSheet.Cells.Item($FinalExcelRow,2) = $User.GivenName

        $finalWorkSheet.Cells.Item($FinalExcelRow,2).Interior.ColorIndex = $ColorIndex

        $finalWorkSheet.Cells.Item($FinalExcelRow,3) = $User.SurName

        $finalWorkSheet.Cells.Item($FinalExcelRow,3).Interior.ColorIndex = $ColorIndex

        $finalWorkSheet.Cells.Item($FinalExcelRow,4) = $User.LastLogonDate

        $finalWorkSheet.Cells.Item($FinalExcelRow,4).Interior.ColorIndex = $ColorIndex

        $finalWorkSheet.Cells.Item($FinalExcelRow,5) = $User.DistinguishedName

        $finalWorkSheet.Cells.Item($FinalExcelRow,5).Interior.ColorIndex = $ColorIndex

        # On incrémente le numéro de la ligne en cours d'écriture

       $FinalExcelRow++

    }else{

        $Result = $User.SamAccountName+";"+$User.GivenName+";"+ `                            $User.SurName+ ";"+$User.LastLogonDate+";"+$User.DistinguishedName

        $Result | Out-File -FilePath $CSVPath -Append 

    } 

}

Write-Host "Saving data and closing Excel." -ForegroundColor Green

if($ExcelTest){

    # Sélectionne les cellules utilisées

    $UR = $finalWorkSheet.UsedRange

   # Auto ajustement de la taille de la colonne    

    $null = $UR.EntireColumn.AutoFit()

    if (Test-Path $ExcelPath) {

        # Si le fichier existe déjà, on le sauvegarde

        $finalWorkBook.Save()

    }else{

        # Sinon on lui donne un nom de fichier au moment de la sauvegarde

        $finalWorkBook.SaveAs($ExcelPath)

    }

    # On ferme le fichier

    $finalWorkBook.Close()

}

# Le processus Excel utilisé pour traiter l'opération est arrêté

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel)

MDT 2012 – Powershell : Intégrer des drivers non extractibles dans un master.

Lors de la création d’un master dans MDT, l’une des des étapes est l’intégration des pilotes. En principes ceux-ci sont généralement extractibles et il est possible de retrouver le .inf permettant l’installation du périphérique. Cependant dans quelques cas, cela n’est pas possible.

Pour pallier à ce problème, l’une des solutions est d’ajouter l’exécution d’un script Powershell dans la séquence de tâches.

Récupération des valeurs sur les postes cibles :

Tout d’abord il est nécessaire de récupérer certaines valeurs sur le modèle d’ordinateur concerné :

# Récupération du model via une requête WMI

$ModelName = wmic csproduct get name

# Récupération de la marque via une requête WMI

$VendorName = wmic csproduct get vendor

Celles-ci vont nous permettre de détecter au moment du déploiement le modèle.

Script à intégrer dans la séquence de tâches :

Le script suivant est celui qui est intégré à la séquence de tâches (ici, le déploiement a été effectué sur un Elitebook 8440p de Hewlett-Packard) :

# Récupération du model via une requête WMI

$ModelName = wmic csproduct get name

# Récupération de la marque via une requête WMI

$VendorName = wmic csproduct get vendor

$ModelName = $ModelName[2].replace(" ", "")

$VendorName = $VendorName[2].replace(" ", "")

if(($ModelName -eq "HPEliteBook8440p") -and ($VendorName -eq "Hewlett-Packard") ){

    Invoke-Expression "ligne_de_commande"

}

On récupère les mêmes valeurs que précédemment et ci ces dernières correspondent aux valeurs récupérées alors on exécute une commande permettant l’installation silencieuse du pilote.

Powershell – Script de MailFlow Externe

 

Le script suivant:

- envoi un mail a un responder (ping@oleane.net)

- attends et récupère la réponse du responder dans Outlook

- retourne un état en cas d’echec

- retourne un état et le message en cas de succes, et supprime le message.

Prerequis: client outlook installé avec le composant “Visual Basic for application” et présence de l’assembly .net Microsoft.Office.Interop.Outlook (cette assembly est présente dans le dossier C:\Windows\assembly).

Dans le menu Outil/Macro/Sécurité , cochez l’option ci-dessous

image image

Paramètre de script a modifier:

$smtpServer: le nom du serveur smtp

$From: l’emeteur du mail

$ReplyTo: l’adresse de réponse

$Dest: le destinataire du mail

$Subject: le sujet du mail

$Body: le corp du mail

$SecondToWait: le temps d’attente de la réponse du responder

[System.Reflection.Assembly]::Load("Microsoft.Office.Interop.Outlook, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c")

    [string]$smtpServer=”mon_serveur_smtp@home.fr”

    [string]$From="test@home.fr"

    [string]$ReplyTo="test@home.fr"

    [string]$Dest="ping@oleane.net"

    [string]$Subject="Test envoi mail"

    [string]$Body="Test envoi mail"

    [string]$SecondToWait =90

 

function sendMail

{

     Write-Host "Sending Email"

     #Creating a Mail object

     $msg = new-object Net.Mail.MailMessage

     #Creating SMTP server object

     $smtp = new-object Net.Mail.SmtpClient($smtpServer)

     #Email structure

     $msg.From = "$From"

     $msg.ReplyTo = "$ReplyTo"

     $msg.To.Add("$Dest")

     $msg.subject = "$Subject"

     $msg.body = "$Body"

     #Sending email

     $smtp.Send($msg)

}

Function Get-MessageInBox

{

Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null

$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]

$outlook = new-object -comobject outlook.application

$namespace = $outlook.GetNameSpace("MAPI")

write-host "waiting for the response from Oleane..."

$namespace.SendAndReceive($false)

sleep -Seconds $SecondToWait

$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)

$folder.items |

Select-Object -Property * -Last 1 | where-object {$_.subject -eq "[echo] Votre message a $Dest"}

}

 

Function Delete-mail

{

Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null

$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]

$outlook = new-object -comobject outlook.application

$namespace = $outlook.GetNameSpace("MAPI")

$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)

$folder.items | Select-Object -Property * -Last 1 | where-object {$_.subject -eq "[echo] Votre message a $Dest"} | tee-object -Variable MessageToDelete

$folder.Items.Remove(1)

}

#Calling function sendmail

sendMail

#Retrieve message to oleane in inbox

Get-MessageInBox | Tee-Object -Variable Message | out-null

if ($Message -eq $null)

{

write-host -ForegroundColor Darkred "---PAS ENCORE DE REPONSE DE $Dest---"

}

else

{

write-host -ForegroundColor Darkgreen "---REPONSE OK DE $Dest---"

Write-Host -ForegroundColor Darkgreen "----MESSAGE----:"

Write-Host "SUJET:" $Message.Subject

Write-Host "ENVOYE LE:" $Message.SentOn

Write-Host "RECU LE:" $Message.ReceivedTime

Write-Host "CORP DU MESSAGE:" $Message.Body

Clear-Variable -Name Message

Write-Host -ForegroundColor Yellow "SUPPRESSION DU MESSAGE..."

Delete-mail | Out-Null

}

SCOM – Powershell: Script de resolution d’alertes avec Regex et Switch.

 

Voici un script de resolution d’alertes indésirables qui utilise:

1- une expression reguliere pour filtrer certains champs d’alertes

2 – une declaration switch pour prendre en charge des filtres de maniere plus pratique qu’avec if…else.

 

#Fermeture de certaines alertes#>

<#modifiez et/ou Incrementez les variables alertes pour prendre en charge d’autres noms d’alertes#>

$Alert1="The previous system shutdown (le dernier arret systeme n'etait pas prévu)"

$Alert2="Redemarrage Propre du serveur"

$Alert3="Database Backup Failed To Complete"

$Alert4="Network interface failed."

<#modifier $MachinePattern avec une autre expression reguliere. Ici par defaut

on recherche les alertes générées par une machine dont le nom contiens la chaine “TEST”#>

$MachinePattern="^.*(TEST).*$" 

#Initialisation du provider SCOM

add-pssnapin "Microsoft.EnterpriseManagement.OperationsManager.Client" -ErrorVariable errSnapin -erroraction silentlycontinue;

set-location "OperationsManagerMonitoring::" -ErrorVariable errSnapin;

new-managementGroupConnection -ConnectionString:monserveurscom.home -ErrorVariable errSnapin;

set-location monserveurscom.home -ErrorVariable errSnapin;

#Verification du  chargement du provider SCOM

if ($errSnapin.count -eq 0){

Write-host "`nOpsMgr 2007 PSSnapin initialized!`n";

}

else{

Write-host "`nOpsMgr 2007 PSSnapin failed initialize!`nPlease verify you are running this script on a OpsMgr 2007 Management Server";

}

$AllOpenAlert=get-alert | where-object {$_.ResolutionState -eq "0"}

Foreach ($alert in $AllOpenAlert)

{

    switch($alert)

    {

        {$_.Name -eq $Alert1 -OR $_.Name -eq $Alert2 -AND $_.MonitoringObjectName -match $MachinePattern -AND $_.LastModified -lt [DateTime]::Now.Adddays(-1)}  {resolve-alert -Alert $_ ; write-host -NoNewline $_.Name "SUR" $_.MonitoringObjectName " -- "}

       

        {$_.Name -eq $Alert3 -OR $_.Name -eq $Alert4 -AND $_.MonitoringObjectPath -match $MachinePattern -AND $_.LastModified -lt [DateTime]::Now.Adddays(-1)}  {resolve-alert -Alert $_ ; write-host -NoNewline $_.Name "SUR" $_.MonitoringObjectPath " -- "}

       

       default {break}

    }   

}

Powershell: Acces aux variables entre Session locale et session distante.

Independemment de la portabilité des variable dans un script, un problème se pose lorsque vous souhaitez, dans un script, accéder des variable locales depuis des commandes executées sur une machine distante.

Exemple:

 

$vmmserver="monserveurvmm.home.com"
$VmToStop="c:\BackupAdmin\VMToStop.txt"

if (!(test-path $VmToStop))
{
write-host "le fichier des VM $VmToStop a eteindre introuvable. le script va s'arreter"
Exit
}
else
{
$VmToStop= Get-Content $VmToStop
foreach ($vm in $VmToStop)
{

        Invoke-Command -ComputerName $vmmserver -ScriptBlock {
        param($vm,$vmmserver)

        Add-PSSnapin microsoft.systemcenter.virtualmachinemanager
        $vmstatus= (get-vm -Name $vm -VMMServer $vmmserver | Select-Object -Property status)
        if ($vmstatus.status -eq "running")
            {
            write-host "La VM $vm est démarré et va etre arretée"
            Shutdown-VM -VM $vm
            }
            elseif ($vmstatus.status -eq "PowerOff")
            {
            write-host "La VM  $vm est déja arrétée"
            Exit
            }
        } -Argumentlist $vm,$vmmserver
}
}       

##################################

 

Dans ce script qui recherche dans un fichier “VMToStop.txt” une liste de machine virtuelles a arrêter, un bloc de commande est executé a distance (Invoke-Command -ComputerName $vmmserver -ScriptBlock { } ) sur un serveur scvmm. Comment faire en sorte que les commandes executées a distance connaissent les variables locales $vm et $vmmserver ?

param($vm,$vmmserver) va permettre de declarer une liste de variable dans le ScriptBlock

-Argumentlist $vm,$vmmserver va permettre de faire la liaison entre le contenu de param et les variables locales.

A noter que le nom des variables déclarées par param est arbitraire, mais il est nécéssaire que ces variables soit dans le meme ordre que celles de –Argumentlist .

Script Powershell – Desinstallation d’application

 

Le script suivant prends en paramètre un nom de machine et un nom d’application (apparaissant dans Ajout-suppression de programme), desinstalle l’application si elle est trouvée, affiche les resultats et les inscris dans un fichier de log.

 

 

Param(
[Parameter(Mandatory = $true)][string]$computername=(read-host -Prompt "entrez le nom de la machine"),
[Parameter(Mandatory = $true)][string]$application=(read-host -Prompt "entrez le nom exact de l'application"),
[string]$credential="administrator"
)

$logfile="c:\result.txt"
$now=(get-date).ToString()

$appuninstall=Get-WmiObject -ComputerName $computername -Class win32_product -Credential $credential | where-object {$_.name -eq $application}

if ($appuninstall -eq $null)
{
write-host "Application $application non trouvée" -ForegroundColor yellow -BackgroundColor black
write-host "Resultat inscris dans $logfile" -ForegroundColor yellow -BackgroundColor black
Out-file $logfile -Append -InputObject "$now -- Application $application non trouvée sur $computername"
exit
}

foreach ($app in $appuninstall)
{
  write-host "...debut desinstallation..." -ForegroundColor yellow -BackgroundColor black
  $app.uninstall()| Tee-Object -Variable uninstallresult
if ($uninstallresult.ReturnValue -eq 0)
    {
    write-host "Desinstallation OK pour $computername" -ForegroundColor green -BackgroundColor black
    write-host "Resultat inscris dans $logfile" -ForegroundColor green -BackgroundColor black
    Out-file $logfile -Append -InputObject "$now -- Desinstallation OK pour $computername"
    }
    else
    {
    write-host "Desinstallation KO pour $computername" -ForegroundColor red -BackgroundColor black
    Out-file $logfile -Append -InputObject "$now -- Desinstallation KO pour $computername"
    write-host "Resultat inscris dans $logfile" -ForegroundColor red -BackgroundColor black
    }
}

Exchange 2010 sp1 – Statistiques ActiveSync avec IPhone

Dans le système de messagerie Microsoft Exchange (depuis Exchange 2007 SP1 jusqu’à aujourd’hui), il est possible de lancer des commandes Powershell permettant d’obtenir des statistiques sur les synchronisations avec des appareils mobiles (Windows Mobiles, Iphone, Etc. …), avec la commande “Get-ActiveSyncDeviceStatistics”.

Aujourd’hui, la liste de téléphones, PDAs Phone, Smartphones, Tablettes graphiques, et autres permettant de synchroniser sa ou ses boite(s) aux lettres ne cesse d’augmenter.

Une des particularités des appareils apple-logo_thumb3 concerne les différents modèles et le fameux IOS avec ses mises à jour successives. Du coup, lors de l’exécution de cette fameuse commande, les résultats peuvent apparaitre avec une liste non exhaustive d’appareils alors que l’utilisateur final n’en possède qu’un seul, le tout lié à ses différentes mises à jour successives.

image_thumb8

Dans cet exemple, on peut voir que cet utilisateur possède :

  • 1 IPhone 3GS
  • 3 IPhones de base, donc version 2
  • 1 HTC

 Triste Alors qu’il utilise un IPhone 3GS….. Triste 

Il est alors possible coder un script Powershell avec un tableau de comparaison prenant en compte les modèles d’appareils ainsi que les différentes versions de Firmwares.

Exemple :

image

Dans ce script, la commande “$devices = Get-ActiveSyncDeviceStatistics -Mailbox $mailbox.samaccountname | Select-Object DeviceType,DevicePolicyApplied, LastSuccessSync,DeviceUserAgent” va être complémentée par le tableau suivant :

switch ($device.DeviceUserAgent)
    {
    "Apple-iPhone/701.341" {$DeviceUserAgent = "iPhone"}
    "Apple-iPhone/703.144" {$DeviceUserAgent = "iPhone"}
    "Apple-iPad/702.367" {$DeviceUserAgent = "iPad"}
    "Apple-iPod2C1/801.293" {$DeviceUserAgent = "iPod"}
    "Apple-iPod3C1/801.293" {$DeviceUserAgent = "iPod"}
    "Apple-iPhone1C2/801.293" {$DeviceUserAgent = "iPhone 3G"}
    "Apple-iPhone2C1/801.293" {$DeviceUserAgent = "iPhone 3GS"}
    "Apple-iPhone3C1/801.293" {$DeviceUserAgent = "iPhone 4"}
    "Apple-iPhone/508.11" {$DeviceUserAgent = "iPhone"}
    "Apple-iPhone/701.400" {$DeviceUserAgent = "iPhone"}
    "Apple-iPhone/704.11" {$DeviceUserAgent = "iPhone"}
    "Apple-iPhone/705.18" {$DeviceUserAgent = "iPhone"}
    "Apple-iPod2C1/801.306" {$DeviceUserAgent = "iPod"}
    "Apple-iPod3C1/801.306" {$DeviceUserAgent = "iPod"}
    "Apple-iPhone1C2/801.306" {$DeviceUserAgent = "iPhone 3G"}
    "Apple-iPhone2C1/801.306" {$DeviceUserAgent = "iPhone 3GS"}
    "Apple-iPhone2C1/801.400" {$DeviceUserAgent = "iPhone 3GS"}
    "Apple-iPhone3C1/801.306" {$DeviceUserAgent = "iPhone 4"}
    default {$DeviceUserAgent = $device.DeviceUserAgent}
    }

où les différents modèles sont accompagnés des différentes versions d’IOS. En parallèle, ce tableau sert aussi d’extracteur de modèle en fonction des différentes versions d’agent qui ne sont pas vraiment lisibles. Par contre, ce tableau demandera d’être complémenté au fil de l’eau selon les différentes évolutions publiées par Apple.

De même, un IPhone “Jailbreaké” (la signification littérale vient de l'anglais et veut dire "Sortir de Prison", cela consiste simplement à modifier le système de l'iPhone afin de le rendre plus accessible et d'en retirer certaines limitations...) vous remontera de fausse informations… ici un IPhone 3G “ouvert” interprété comme un IPhone2… Triste

image_thumb7

Du coup, on peut rapidement s’y perdre !!!

Dans le script en exemple, des restrictions dans les dates de synchronisation ont été implémentées afin de ne prendre en compte que le dernier mois ou les 30 derniers jours. Ce qui permettra de filtrer les retours et d’être un peu plus pertinent sur ces statistiques ! Sourire

 

N'hésitez pas à laisser un commentaire si ce tips vous a été utile ou bien si vous avez des éléments à ajouter !…

Exchange 2010 : Activation en masse

Contexte:


Lors de la mise en œuvre d’une infrastructure exchange 2010 pour un grand compte, il m’est arrivé de devoir activer plus de 20 licences Exchange 2010. L’activation de ces nombreux serveurs est fastidieuse et peut engendrée des erreur de saisie.

Solutions possibles:

Tous vos serveurs sont en version Standard ou en version Enterprise:

         

Get-ExchangeServer | Set-ExchangeServer -ProductKey ‘Clef produit’

Les versions sont différentes en fonction du rôle:


Get-ClientAccessServer | Set-ExchangeServer -ProductKey ‘Clef produit’

Get-TransportServer | Set-ExchangeServer –ProductKey ‘Clef produit’

Get-MailboxServer | Set-ExchangeServer -ProductKey ‘Clef produit’

Get-UMserver | Set-ExchangeServer –ProductKey ‘Clef produit’

Conclusion:

L’activation des serveurs est simplifié avec cette commande et permet un gain de temps lors du déploiement de nombreux serveurs de messagerie Exchange 2010.

A noté que cette commande est fonctionnelle avec Exchange 2007.

Exchange 2010 – Erreur “the execution of scripts is disabled on this system” lors du lancement d’un script powershell

Lors de l’exécution d’un script powershell (.PS1) sur un serveur Exchange 2010, alors que vous possédez des droits Administrateurs, vous rencontrez l’erreur suivante :

image

Par défaut, et pour des raisons évidentes de sécurité, l’exécution de script “Powershell for Exchange” est bridée. Afin de visualiser ce niveau de sécurité, il suffit de lancer la commande “Get-ExecutionPolicy” :

image

afin de se rendre compte que les droits sont positionnés à “Restricted” par défaut.

Les différents droits existants pour l’exécution de script sont les suivants :

  • Unrestricted
  • RemoteSigned
  • AllSigned
  • Restricted
  • Default
  • Bypass
  • Undefined

image

Il est alors possible d’autoriser l’exécution de script à l’aide de la commande “Set-ExecutionPolicy” et d’y ajouter la valeur désirée (nommée précédemment).

image

Mais comme l’indique alors le message lors du passage de la commande, le niveau de sécurité est dans ce cas abaissé. Ce qui peut poser problème. Si on désire autoriser momentanément l’exécution de script sans toucher au niveau de sécurité, il est possible de paramétrer l’environnement d’exécution juste pour ce lancement, avec un VBS par exemple, et qui servira de “lanceur” au script powershell.

1/ Le raccourci de lancement du Powershell for Exchange s’exécute comme suit :

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit –command            ".'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto"

  • Lancement de l’exécutable –Command “appel du script RemoteExchange.ps1 permettant d’alimenter le Powershell avec les commandes pour Exchange 2010”; Connexion au premier serveur Exchange disponible

2/ Il suffit alors de rajouter ce type de commande supplémentaire :

  • Set-ExecutionPolicy -ExecutionPolicy Bypass –Force

Ce qui pourrait donner :

  • C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit –command            ".'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto"; Set-ExecutionPolicy -ExecutionPolicy Bypass –Force
    3/ Une fois inclus dans un script VBS, cela peut donner :
  • Return = WshShell.run (“C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit –command            ".'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto"; Set-ExecutionPolicy -ExecutionPolicy Bypass –Force; MonScript.ps1; exit“)

    Le script “MonScript.ps1” sera alors exécuté avec les bonnes autorisations sans impacter les paramètres de sécurité du serveur de manière définitive.

    N.B.: il est possible de remplacer “-auto” par le nom d’un serveur Exchange spécifique permettant ainsi d’effectuer du “Remote Scripting” sur le serveur désiré.

N'hésitez pas à laisser un commentaire si ce tips vous a été utile ou bien si vous avez des éléments à ajouter !…

SCOM - Agents bloqués en “Pending”

Nous avons rencontrés aujourd’hui un souci avec les agents scom 2007 R2.

Sur un cluster RMS, la procédure de déploiement d’agents se déroulait bien mais les agents ne s’installaient pas. Ces derniers restaient bloqués en « pending » avec une « installation in progress », les event ID 21016 apparaissent dans le journal d’évènements.

La solution pour les approuver fut de passer par la commande powershell : get-agentpendingaction | approve-agentpendingaction