PI Services

Le blog des collaborateurs de PI Services

Préparation et déploiement d’un VHD contenant une image de référence dans Hyper-V3 en powershell

Dans ce blog, nous allons voir comment préparer un VHD étapes par étapes en appliquant notre image de référence Windows 8 pour un serveur sous Hyper-v.

Il est intéressant de connaitre les cmdlets sous Powershell étant donné que l’utilisation de Diskpart est maintenant dépréciée.

Notre serveur Hyper-v ne détient actuellement aucune machine.

clip_image002

Nous définissons dans une variable le nom qu’aura notre VM dans Hyper-v

$NameVm="Demo"

Nous définissons dans une variable l’emplacement et le nom qu’aura notre VHD créé

$PathVM="C:\VHD\$NameVM.vhdx"

Nous créons maintenant notre VHD à l’aide de la cmdlet " new-vm " qui créera directement la VM dans Hyper-v .

new-vm -Name $NameVm -MemoryStartupBytes 1024MB -NewVHDPath $PathVM -NewVHDSizeBytes 10000MB

Le résultat :

clip_image003

clip_image004

clip_image005

Il est maintenant nécessaire que nous montions notre VHD pour le préparer (partionnement, boot,..)

Mount-VHD $PathVM

En utilisant maintenant la cmdlet "Get-disk" nous pouvons vérifier que notre VHD à correctement été monté.

clip_image007

Notre VHD n’ayant pas encore été partitionné, il apparait sous le style de partition raw. Nous allons maintenant récupérer le numéro de partition de ce VHD grâce au « Friendly Name » et au « Partition Style »

$numero=(get-disk | Where-Object {$_.friendlyname -match "virtual" -and $_.partitionstyle -match "raw"}).number

Il faut maintenant initialisé le VHD afin de pouvoir formater celui-ci et y stocker des données.

Initialize-Disk $numero -PartitionStyle mbr

get-disk $numero

clip_image009

Le disque a bien été initialisé.

Nous allons maintenant partitionner ce VHD en NTFS

$Label="Demo"

New-Partition $numero -UseMaximumSize -AssignDriveLetter | Format-Volume -NewFileSystemLabel $label -FileSystem NTFS –asjob

Nous ne connaissons pas la lettre de volume qui lui a été alloué. Pour cela, on peut consulter tous les volumes à l’aide de la cmdlet :

Get-volume

clip_image011

Nous allons maintenant récupérer notre volume par l’identifiant de notre label précédemment définit.

$vol=(Get-Volume | Where-Object {$_.filesystemlabel -match $label}).driveletter

$vol1=$vol+":"

Et maintenant nous appliquons notre master de référence sous l’extension WIM avec DISM.

dism /apply-image /imagefile:C:\Users\administrateur\Desktop\Master_8.wim /index:1 /applydir:$vol1

clip_image012

On définit maintenant la partition comme étant active pour que celle-ci puisse booter depuis un OS.

Set-Partition -DriveLetter $vol -IsActive $true

Et maintenant nous allons configurer notre magasin BCD en lui ajoutant l’entrée de notre nouveau disque VHD.

$vol2=$vol1+"\Windows"

bcdboot $vol2 /s $vol1

clip_image013

Nous pouvons maintenant démonter notre VHD puis démarrer notre VM.

Dismount-VHD $PathVM

Start-VM $NameVm

Maintenant si nous revenons sur la console Hyper-v, nous pouvons constater que notre VM a bien démarrer et que notre master de référence Works !!

clip_image015

Il suffit maintenant d’imaginer un déploiement de master de référence à plus grande échelle pour une phase de recette par exemple.

Pour cela, il suffit d’effectuer une boucle dans un script avec toute les cmdlets et cela se déploiera au sein de Hyper-v de façon automatisé.

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 .

Manipulation des droits NTFS via Powershell

Il existe un module nommé NTFSSECURITY permettant une manipulation simplifié des droits NTFS sur des dossiers et/ou fichiers.

Ce module peut être trouvé sur la galerie Technet http://gallery.technet.microsoft.com/scriptcenter/1abd77a5-9c0b-4a2b-acef-90dbb2b84e85/file/48905/1/NTFSSecurity%201.3.zip

 

Une fois téléchargé, mettez le dossier du module NTFSSecurity ici C:\Windows\System32\WindowsPowerShell\v1.0\Modules

Maintenant, nous allons charger le module dans powershell

image

Une fois celui-ci chargé, de nouvelles cmdlets sont désormais disponible.

image                                   

Récupération du SID d’un utilisateur dans une variable.

Nous allons définir dans une variable $SamMember le nom de l’utilisateur que nous voulons récupérer.

Ensuite nous allons utiliser l’object System.Security.principal.NtAccount(« domaine »,utilisateur) qui va nous permettre de récupérer notre utilisateur dans un domaine spécifié.

image

image

Maintenant, récupérons le SID de notre utilisateur grâce à une méthode de notre variable $account.

image

Nous avons ainsi récupéré dans notre variable $accountsid le SID de notre utilisateur spécifié dans la variable $SamMember.

 

Modification du propriétaire d’un répertoire.

Avec le chargement du module NTFSSecurity, une cmdlet get-owner est apparue nous permettant de connaitre simplement le propriétaire d’un élément (fichier ou répertoire).

Exemple :

image

Nous allons maintenant changer le propriétaire de ce répertoire avec l’utilisateur contenu dans notre variable $accountsid

image

Voyons maintenant le résultat :

image

 

Le propriétaire à bien été changé.

 

Modification des ACE du répertoire.

Nous allons maintenant modifier les ACE du répertoire de façon à ne laisser que l’utilisateur de notre variable $accountsid en FullControl et aucune autre ACE.

Rajout de l’ACE :

image

Suppression des autres ACE :

image

(Ce lien permet de connaitre les SID connu dans les OS Windows http://support.microsoft.com/kb/243330)

 

Si on consulte maintenant nos ACE, on peut remarquer que notre ajout d’ACE s’est bien passé mais que la suppression des autres ACE ne s’est pas déroulée correctement.

 

image

Cela est normal, car ses ACE sont hérité du répertoire parent. Il faut donc pour cela retirer l’héritage.

clip_image001[4]

Et maintenant si on essaie de nouveau de supprimer nos ACE on peut remarquer que celle-ci ont bien disparu.

 

image

Il est maintenant facile d’imaginer la création d’un script pouvant réappliquer correctement des droits sur une toute une arborescence de répertoires profils en récupérant par exemple le nom du répertoire profil et en réaffectant celui-ci dans une boucle pour notre variable $account.

 

image

 

clip_image005

Ainsi, l’utilisateur authentifié en user2, ne pourra accéder qu’à son répertoire profil.

Vérification d’utilisateurs existant dans un domaine en Powershell

Vous disposez d’une liste exhaustive de comptes utilisateurs dans un fichier et vous désirez savoir ceux d’entre eux qui sont bien existant dans le domaine courant.

Pour cela, nous allons parcourir ce fichier et établir une connexion sur ces utilisateurs. Si la connexion sur l’utilisateur se passe bien, nous l’ajouterons dans un second fichier. Si cet utilisateur n’existe pas, nous l’ignorerons.

Exemple de fichiers contenant sur une colonne des utilisateurs existant ou non dans le domaine courant.

image

image

 

image

Résultat obtenu dans un fichier result.txt :

image

Le script nous a bien permit de récupérer uniquement les utilisateurs existant dans le domaine courant.

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
    }
}

Powershell–Gestion du réseau

Contexte

Il arrive souvent lors de l’installation de certains produits ou fonctionnalitée de devoir réaliser des opérations de vérification des pré-requis. Le premier pré-requis a satisfaire concerne souvent le réseau:

  • Suis-je en capacité de joindre ma passerelle?
  • Le ou les contrôleurs hébergeant les rôles FSMO sont-ils joignable?
  • Mes serveurs DNS sont-ils joignable?

Pour réaliser ces opérations sur quelques serveurs cela peut être réalisé manuellement, mais lorsque le nombre de serveur est conséquent, cela peut s’avéré fastidieux. Je vous propose de travailler en powerShell pour simplifier/automatiser cette opération.

Etape 1: récupérer la configuration de machine

Pour cela rien de bien compliquer, la commande ipconfig /all nous retourne l’ensemble des éléments nécessaire:

image

Maintenant il faut pouvoir isolé chaque paramètre de réponse (ici identifiés de 1 a 6). Pour cela un traitement sur le retour d’ipconfig est nécessaire:

  1. 1. Adresse IPv4:  ((ipconfig | findstr [0-9].\.)[0]).Split()[-1]
  2. 2. Masque : ((ipconfig | findstr [0-9].\.)[1]).Split()[-1]
  3. 3 Passerelle : ((ipconfig | findstr [0-9].\.)[2]).Split()[-1]
  4. 4 Serveur DHCP : ((ipconfig /all| findstr [0-9].\.)[3]).Split()[-1]
  5. 5 DNS Principal : ((ipconfig /all| findstr [0-9].\.)[5]).Split()[-1]
  6. 6 DNS Secondaire ((ipconfig /all| findstr [0-9].\.)[6]).Split()[-1]

 

Etape 2: Exécuter un ping en powershell

Pour réaliser cette opération les commandes suivante nous retourne un résultat contenant les valeur attendu:

image

  • new-object System.Net.NetworkInformation.ping
  • $reply = $ping.Send("192.168.0.254")

Nous savons donc que le ping a fonctionné au travers du status. qu’il reste a isoler puis a traiter. Pour l’isolation, l’utilisation des variables nous simplifie la tache:

image

Etape 3: Automatisation des résultats

Afin de valider le bon fonctionnement des pré-requis lié au réseau, nous pouvons traiter les retours au travers de différents moyens, pour ma part, je préfère utilisé les conditions au travers du If – Else

   1: #***** Stockage des parametre dans une variable*****#
   2:     $IP= ((ipconfig | findstr [0-9].\.)[0]).Split()[-1]
   3:     $IPMask= ((ipconfig | findstr [0-9].\.)[1]).Split()[-1]
   4:     $IPgtw= ((ipconfig | findstr [0-9].\.)[2]).Split()[-1]
   5:     $IPDHCP=((ipconfig /all| findstr [0-9].\.)[3]).Split()[-1]
   6:     $DNS1=((ipconfig /all| findstr [0-9].\.)[5]).Split()[-1]
   7:     $DNS2=((ipconfig /all| findstr [0-9].\.)[6]).Split()[-1]
   8:  
   9: #**Test passerelle**#
  10:     $reply = ""
  11:     $status =""
  12:     $ping = new-object System.Net.NetworkInformation.ping
  13:     $reply = $ping.Send($IPgtw)
  14:  
  15: if ($reply.status -eq "success")
  16:     {
  17:     write-host "Passerelle joignable" -foregroundColor green
  18:     }
  19:     Else
  20:     {
  21:     write-host "Passerelle injoignable" -foregroundColor red
  22:     }
  23:  
  24: #**Test DHCP**#
  25:     $reply = ""
  26:     $status =""
  27:     $ping = new-object System.Net.NetworkInformation.ping
  28:     $reply = $ping.Send($IPDHCP)
  29:  
  30: if ($reply.status -eq "success")
  31:     {
  32:     write-host "DHCP joignable" -foregroundColor green
  33:     }
  34:     Else
  35:     {
  36:     write-host "DHCP injoignable" -foregroundColor red
  37:     }
  38: #**Test passerelle**#
  39:     $reply = ""
  40:     $status =""
  41:     $ping = new-object System.Net.NetworkInformation.ping
  42:     $reply = $ping.Send($DNS1)
  43:  
  44: if ($reply.status -eq "success")
  45:     {
  46:     write-host "DNS joignable" -foregroundColor green
  47:     }
  48:     Else
  49:     {
  50:         $reply = ""
  51:         $status =""
  52:         $ping = new-object System.Net.NetworkInformation.ping
  53:         $reply = $ping.Send($DNS2)
  54:         if ($reply.status -eq "success")
  55:             {
  56:             write-host "DNS joignable" -foregroundColor green
  57:             }
  58:             Else
  59:             {
  60:             write-host "DNS injoignable" -foregroundColor red
  61:             }        
  62:     }
  63:  

Le résultat positif retourne:

image

Le résultat négatif retourne:

image

Conclusion

Cette vérification permet de réaliser un enchainement de script ou d’action si et seulement si les paramètres réseaux sont correct. Par exemple en créant un flag si les résultats sont positif !