IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Scripts/Batch Discussion :

Débutant Powershell - Cherche à exécuter un programme externe et gérer l'erreur [PowerShell]


Sujet :

Scripts/Batch

  1. #1
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut Débutant Powershell - Cherche à exécuter un programme externe et gérer l'erreur
    Bonjour

    J'ai développé en shell (bash) un script qui manipule les machines virtuelles de VirtualBox. Il utilise pour ça la commande dédiée "vboxmanage" qui est un exécutable à part entière (et qui permet toutes les actions voulues pourvu qu'on lui passe les bons mots-clefs). Donc j'appelle la commande, je traite ce qu'elle affiche etc. En bash je m'en sors très bien.

    Je cherche maintenant à adapter mon script en powershell ce qui me donne l'occasion de me mettre à ce langage. Sauf que je n'arrive pas à bien démarrer.

    Pour commencer, je cherche juste à récupérer le résultat renvoyé par vboxmanage. Là ça va => $data=vboxmanage showvminfo xxx ("xxx" étant le nom de ma machine virtuelle). Mais ensuite (comme je l'ai fait en bash), je veux traiter le cas où "xxx" n'existe pas. Dans ce cas, la commande vboxmanage répond ceci...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    VBoxManage.exe: error: Could not find a registered machine named 'xxx'
    VBoxManage.exe: error: Details: code VBOX_E_OBJECT_NOT_FOUND (0x80bb0001), component VirtualBoxWrap, interface IVirtualBox, callee IUnknown
    VBoxManage.exe: error: Context: "FindMachine(Bstr(VMNameOrUuid).raw(), machine.asOutParam())" at line 3139 of file VBoxManageInfo.cpp
    ... et retourne un code d'erreur qu'en bash je sais intercepter.

    De son côté, Windows détecte aussi cela comme une erreur puisque si on demande vboxmanage showvminfo xxx 2>err.txt le contenu va dans le fichier "err.txt". Mais même en étant détecté comme erreur, je n'arrive pas à l'intercepter.

    Voici ce que j'ai tenté en powershell
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # Script Powershell
     
    # Fonction qui récupère le uuid d'une machine
    function getUUID {
    	Write-Host "args=" $args[0]
    	try {
    		$data=vboxmanage showvminfo $args[0]
    		Write-Host $data
    	}
    	catch {
    		Write-Host 'Erreur' $_.Exception.Message
    	}
    }
     
    foreach ($x in $args) {
    	getUUID $x
    }

    Je pense qu'appeler directement la commande "vboxmanage" n'est pas une bonne idée. Par exemple pour lire un fichier, pas besoin d'appeler la commande MsDos type fichier, powershell possède un cmdlet "get-content" qui fait le job. Je me dis que l'équivalent doit exister pour traiter une commande (style les pipes) mais je ne trouve pas.

    Un petit coup de main pour démarrer s'il vous plait?

    Merci de votre attention.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  2. #2
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Bonjour, voici quelques façons de le faire

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    dir err 2>$null
    if (! $?)
    {
        Write-Host "Error 1"
    }
     
    $Error.Clear()
    dir err 2>$null
    if ($Error)
    {
        Write-Host "Error 2"
    }
     
     
    $ErrorActionPreference = 'Stop'
    try
    {
        dir err 2>$null
    }
    catch
    {
        Write-Host "Error 3"
    }
    finally
    {
        $ErrorActionPreference = "Continue"
    }

    plus d'info sur $? : https://learn.microsoft.com/fr-fr/po...-7.3#section-1

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ericlm128 Voir le message
    Bonjour, voici quelques façons de le faire

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    dir err 2>$null
    if (! $?)
    {
        Write-Host "Error 1"
    }
    Super sympa. J'ai testé les trois et (évidemment) toutes fonctionnent. Je n'avais pas perçu le rôle de $ErrorActionPreference = 'Stop'.

    J'aime bien la première (ressemblant à bash). Il y a moyen d'être plus explicite que if (! $?)? Perso j'aime bien ce qui est explicite. J'ai tenté if ($? == False), if ($? == $FALSE), if ($? != 0) mais rien. Ca parle de System.Management.Automation.InvocationInfo (probablement l'objet de $?). Enfin bon je pense que ça viendra avec l'expérience.

    Merci encore.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    dir err 2>$null
    if ($? -eq $false)
    {
        Write-Host "Error 4"
    }

    Comparison Operators : https://learn.microsoft.com/en-us/po...ison-operators

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Super, je suis parti

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # Script Powershell
     
    # Fonction qui récupère le uuid d'une machine
    function getUUID {
    	$data=vboxmanage showvminfo $args[0] 2>$null; $status=$?
    	if ($status -ne $true) { return $null }
     
    	foreach ($ligne in $data) {
    		if ($ligne.startswith("UUID")) {
    			return $ligne.split(":")[1].trim()
    		}
    	}
     
    	return $null;		# Sécurité
    }
     
    #foreach ($x in $args) {
    foreach ($vm in ("toto", "Xubuntu64")) {
    	$uuid=getUUID $vm
    	if ($uuid -eq $null) {
    		Write-Host "Machine [$vm] inconnue ($uuid) - Abort"
    		continue
    	}
    	Write-Host "Machine [$vm] ($uuid) en cours..."
    }
    Je sais que c'est très bébé mais ça viendra avec l'expérience

    Merci encore
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  6. #6
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Pas de problème on a tous débuté un jour

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut Petit poussin devient poussinou...
    Mon code commence à s'étoffer et je viens vous montrer ce que ça donne...
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    # Script Powershell
     
    # Fonction qui récupère le uuid d'une machine
    function getUUID($vm) {
    	$data=vboxmanage showvminfo $vm 2>$null; $status=$?
    	if (-not $status) { return $null }
     
    	foreach ($ligne in $data) {
    		if ($ligne.startswith("UUID:")) {
    			return $ligne.split(":")[1].trim()
    		}
    	}
    	return $null
    }
     
    # Fonction qui récupère les disques d'un host
    function getDisks($uuid) {
    	#Write-Host "uuid=[$uuid]"
     
    	$flag=$false
    	foreach ($ligne in vboxmanage showvminfo $uuid) {
    		# Détection début bloc disques
    		if (-not $flag -and $ligne -eq "Storage Controllers:") {
    			$flag=$true
    			continue
    		}
     
    		# Détection fin bloc disques
    		if ($flag -and $ligne -like "NIC ?:*") {
    			$flag=$false
    			continue
    		}
     
    		# Pas en zone disques alors pas besoin de traiter
    		if (-not $flag) { continue }
     
    		# Analyse bloc disques
    		$ligne=$ligne.trim()
     
    		# Recherche controleur (#n: 'controler', ...)
    		if ($ligne -like "#?: *") {
    			$controler=$ligne.split(",").split(":")[1].trim().replace("'", "")
    			continue
    		}
     
    		# Recherche port et uuid (Port p, Unit u: UUID: xxx)
    		if ($ligne -notlike "Port ?,*") { continue }
    		$uuid=$ligne.split(":")[-1].trim()
    		if ($uuid -eq "Empty") { continue }
    		$port=$ligne.split(",")[0].replace("Port ", "").trim()
    		@{
    			"controler"=$controler;
    			"port"=$port;
    			"uuid"=$uuid;
    		}
    	}
    }
     
    #foreach ($x in $args) {
    foreach ($vm in ("toto", "Xubuntu64")) {
    	$uuid=getUUID "$vm"
    	if ($uuid -eq $null) {
    		Write-Host "Machine [$vm] inconnue - Abort"
    		continue
    	}
    	Write-Host "Machine [$vm] ($uuid) en cours..."
     
    	foreach ($disk in getDisks $uuid) {
    		Write-Host "Controleur [$($disk["controler"])] - Port [$($disk["port"])] - uuid [$($disk["uuid"])]"
    	}
    }

    Je suis super content mais si vous avez des conseils à me donner... Par exemple à la fin de ma fonction "getDisks" je retourne un dictionnaire créé à la volée (enfin c'est pas vraiment un retour définitif, c'est plutôt un générateur style yield de Python que j'ai eu super du mal à trouver !!!).
    Au début je crééais le dictionnaire petit à petit avant de le retourner mais j'ai eu la surprise de voir au final apparaitre n fois les mêmes valeurs. Comme dans cet exemple...
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function xxx {
    	$res=@{}
    	foreach ($i in 1..5) {
    		$res["x"]="toto$($i)"
    		$res["y"]="titi$($i*10)"
    		$res
    	}
    }
     
    foreach ($x in xxx) {
    	"x: $($x["x"]) - y: $($x["y"])"
    }
    ... qui m'affiche 5 fois "x: toto5 - y: titi50".

    Alors que cette fonction réécrite ainsi...
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    function xxx {
    	foreach ($i in 1..5) {
    		@{"x"="toto$($i)"; "y"="titi$($i*10)"}
    	}
    }
    ... fonctionne parfaitement. Je sens vaguement que ça doit être une histoire d'objet unique (on a des soucis analogue en Python quand on veut copier des tableaux ou autres objets complexes puis qu'on modifie l'original => la copie est modifiée aussi) mais si qqun avait la gentillesse de détailler... Enfin c'est pas (pas encore) réellement important.

    Voili voilou...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Ce n'est pas un problème, il faut juste comprendre comment cela fonctionne mais ce comportement se retrouve dans tout les langages POO.
    Les type type d’objet (objets complexes) sont passé par référence contrairement au type Int (par exemple)
    Voir ceci : https://learn.microsoft.com/fr-fr/po...powershell-5.1


    Je n'aime pas du tout traiter une sortie texte avec des langages orientés objet, mais des fois nous n'avons pas le choix.
    Peux tu fournir un exemple de sortie de la commande vboxmanage showvminfo ?

    A voir ton code je dirais que tu as déjà fait du développement avec le Framework.NET (VB, C#...) ?

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ericlm128 Voir le message
    Ce n'est pas un problème, il faut juste comprendre comment cela fonctionne mais ce comportement se retrouve dans tout les langages POO.
    Pas en Python (malgré le fait que là aussi il n'y a qu'une seule et unique référence du dictionnaire retourné)
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    >>> def fct(n):
    ...     res=dict()
    ...     print(hex(id(res)))
    ...     for i in range(n):
    ...             res["x"]="toto%d" % i
    ...             res["y"]="titi%d" % (i*10)
    ...             yield res
    ... 
    >>> for x in fct(5):
    ...     print(hex(id(x)), x["x"], x["y"])
    ... 
    0x7f9d9b405600
    0x7f9d9b405600 toto0 titi0
    0x7f9d9b405600 toto1 titi10
    0x7f9d9b405600 toto2 titi20
    0x7f9d9b405600 toto3 titi30
    0x7f9d9b405600 toto4 titi40
    Mais je comprends l'idée sous-jacente du comportement. Comme je l'ai dit en Python ça ne le fait pas. Probablement parce qu'en Python le dictionnaire est retourné au moment de son remplissage alors que (hypothèse) Powershell fait une espèce de dump de tout ce qu'il doit renvoyer avant de le renvoyer effectivement. Rajouter l'heure courante à l'info retournée permettrait de vérifier ce détail (en Python l'heure courante est celle de l'exécution du yield).

    Citation Envoyé par ericlm128 Voir le message
    Je n'aime pas du tout traiter une sortie texte avec des langages orientés objet, mais des fois nous n'avons pas le choix.
    Ouaip. Sous Windows je ne voyais pas quoi utiliser. Je n'avais pas envie d'installer Python et je me suis dit "ok ça donnera l'occasion d'apprendre Powershell"...

    Citation Envoyé par ericlm128 Voir le message
    Peux tu fournir un exemple de sortie de la commande vboxmanage showvminfo ?
    138 lignes je vais pas toutes les mettres. Je te mets celles qui m'intéressent et en rouge les infos que je cherche à récupérer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    Name:                        Xubuntu64
    Encryption:     disabled
    Groups:                      /Linux
    Guest OS:                    Ubuntu (64-bit)
    UUID:                        0a55e753-84ac-42e9-970a-623b56fad055
    Config file:                 ... (un chemin sur ma machine)...
    Snapshot folder:          .. (un chemin sur ma machine)...
    Log folder:                  .. (un chemin sur ma machine)...
    Hardware UUID:               0a55e753-84ac-42e9-970a-623b56fad055
    Memory size:                 4096MB
    Page Fusion:                 disabled
    VRAM size:                   64MB
    CPU exec cap:                100%
    HPET:                        disabled
    CPUProfile:                  host
    Chipset:                     piix3
    Firmware:                    BIOS
    Number of CPUs:              4
    PAE:                         disabled
    Long Mode:                   enabled
    Triple Fault Reset:          disabled
    APIC:                        enabled
    X2APIC:                      enabled
    Nested VT-x/AMD-V:           disabled
    CPUID Portability Level:     0
    CPUID overrides:             None
    Boot menu mode:              message and menu
    Boot Device 1:               DVD
    Boot Device 2:               HardDisk
    Boot Device 3:               Not Assigned
    Boot Device 4:               Not Assigned
    ... (plein de lignes)...
    ... (plein de lignes)...
    ... (plein de lignes)...
    Default Frontend:            
    VM process priority:         default
    Storage Controllers:
    #0: 'IDE', Type: PIIX4, Instance: 0, Ports: 2 (max 2), Bootable
      Port 0, Unit 0: Empty
    #1: 'SATA', Type: IntelAhci, Instance: 0, Ports: 7 (max 30), Bootable
      Port 0, Unit 0: UUID: 7eea1903-174d-4ad0-a8bf-91a812d53ca3
        Location: "...(l'emplacement du vdi)..."
      Port 1, Unit 0: UUID: bdb412c0-e661-4f3d-840b-813810279b46, hot-pluggable
        Location: "...(l'emplacement du vdi)..."
      Port 2, Unit 0: UUID: f50c8420-d1a7-4f58-813f-4bddd7a2419f
        Location: "...(l'emplacement du vdi)..."
      Port 3, Unit 0: UUID: 00551a97-a123-454f-b43b-f00ab01aa139
        Location: "...(l'emplacement du vdi)..."
    NIC 1:                       MAC: 08002788CE21, Attachment: Bridged Interface 'Intel(R) Ethernet Connection (7) I219-V', Cable connected: on, Trace: off (file: none), Type: 82543GC, Reported speed: 0 Mbps, Boot priority: 0, Promisc Policy: allow-all, Bandwidth group: none
    NIC 2:                       disabled
    NIC 3:                       disabled
    NIC 4:                       disabled
    NIC 5:                       disabled
    NIC 6:                       disabled
    NIC 7:                       disabled
    NIC 8:                       disabled
    Pointing Device:             USB Tablet
    ... (plein de lignes)...
    ... (plein de lignes)...
    ... (plein de lignes)...
    Citation Envoyé par ericlm128 Voir le message
    A voir ton code je dirais que tu as déjà fait du développement avec le Framework.NET (VB, C#...) ?
    Suis linuxien pur et dur . C, un peu de C++ (pour Qt) et Python mais lui je l'ai bien kiffé et je m'y suis mis à fond. Lui aussi il est POO, lui aussi il connait les tableaux associatifs, lui aussi il sait retourner un gros ensemble d'infos (on dit "un iterable") et lui aussi on peut lui dire de retourner cet iterable d'un coup ou élément par élément (générateur). Et lui aussi il travaille par référence dans la copie de ses objets complexes. Et il n'y a pas 1000 façons de coder non plus. Avec le C (programmation modulaire) on apprend à bien découper les choses, avec Unix on apprend la bonne philosophie des actions (une fonction ne fait qu'une chose mais la fait bien), ne reste ensuite qu'à y rajouter un peu de POO derrière avec Python et voilà...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Je dirais qu'en Python c'est la même chose sur ton exemple même si le résultat est différent.
    C'est le mot clé yield qui fait toute la différence car la fonction suspend son travail jusqu’à la demande du prochain item (next) de l'itérateur.

    En PowerShell, sans nécessité particulière nous avons plus l'habitude de travailler avec des PSCustomObject
    Voici quelques approches simple :
    1)
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function xxx
    {
        1..5 | ForEach-Object {
            [PSCustomObject]@{
                x = "toto$($_)"
                y = "titi$($_ * 10)"
            }
        }
    }
     
    foreach($i in xxx)
    {
        "x: $($i.x) - y: $($i.y)"
    }

    ou

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $items = 1..5 | ForEach-Object {[PSCustomObject]@{x = "toto$($_)";y = "titi$($_ * 10)"}}
    $items | ForEach-Object {"x: $($_.x) - y: $($_.y)"}

    2)
    Je pense qu'en PowerShell il faut souvent utiliser la puissance des pipelines | qui traite les éléments retournées 1 par 1 (au fil de l'eau) à la manière du yield

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function xxx {
    	$res=@{}
    	foreach ($i in 1..5) {
    		$res["x"]="toto$($i)"
    		$res["y"]="titi$($i*10)"
    		$res
    	}
    }
     
    xxx | ForEach-Object {"x: $($_["x"]) - y: $($_["y"])"}

    Il faut s'avoir qu'une fonction PowerShell à la structure (simplifié) suivante :
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Function Test-ScriptCmdlet
    {
        BEGIN{}
        PROCESS{}
        END{}
    }
    Sans block de spécifié toute la fonction est un block process.
    Plus d'info sur le fonctionnement ici : https://learn.microsoft.com/fr-fr/po...essing-methods



    Les 3 codes proposées produise le même résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    x: toto1 - y: titi10
    x: toto2 - y: titi20
    x: toto3 - y: titi30
    x: toto4 - y: titi40
    x: toto5 - y: titi50



    PS : Je connais aussi Python et c'est le même comportement même si python à une gestion un peu particulière (Call by sharing)
    Chaque langage à ses particularités et ses implémentations mais la logique reste la même.

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    d1 = {"x": "1x"}
    d2 = d1 # Assigne la référence de d1 (par référence)
    d2["x"] = "2x"
    print(d1) # {'x': '2x'}
     
    d3 = {"x": "1x"}
    d4 = d3.copy()  # Assigne la référence d'une copie de d3 (par référence)
    d4["x"] = "2x"
    print(d3) # {'x': '1x'}
     
    s1 = "s1"
    s2 = s1 # Assigne la valeur de s1 (par valeur)
    s2 = "s2"
    print(s1) # s1

  11. #11
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Je jetterai un coup d’œil à ton fichier texte de sortie afin de te proposer un traitement, ça peut être intéressant de voir différentes manières de faire. Si la mienne est différente je ne sais pas encore

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par ericlm128 Voir le message
    Je pense qu'en PowerShell il faut souvent utiliser la puissance des pipelines | qui traite les éléments retournées 1 par 1 (au fil de l'eau) à la manière du yield
    Ca j'avais vu. Ce qui m'a gêné, c'est que tu n'es pas libre du nom de tes variables. Toi tu utilises "$_" que je ne connaissais pas mais les exemple montrent $PSItem. Avec foreach() je peux nommer ma variable de boucle à mon choix et ça j'aime bien. Après peut-être que je prendrai l'habitude

    Citation Envoyé par ericlm128 Voir le message
    Je jetterai un coup d’œil à ton fichier texte de sortie afin de te proposer un traitement, ça peut être intéressant de voir différentes manières de faire. Si la mienne est différente je ne sais pas encore
    En fait mon traitement ne génère aucun fichier, il ne fait que des actions.

    Si ça t'intéresse (et si tu connais VirtualBox), voici le contexte: sous VirtualBox, un disque immuable est un disque figé dans un état défini. On prépare le disque et dès qu'il nous convient on le rend immuable. On peut ensuite le rendre normal si on veut le faire évoluer puis de nouveau immuable etc.
    Un disque immuable est un disque qui reprend son état défini au moment où la machine démarre. Une fois démarrée il se comporte normalement du point de vue de l'utilisateur de la machine. On peut le modifier, créer des dossiers, le formater, etc. Mais au démarrage suivant de la machine toutes les modifs ont disparues car le disque a repris son état défini lors de sa mise en "immuable".
    Je m'en sers pour figer mes OS. Généralement j'ai un disque système immuable, et un disque de datas normal. Ainsi je peux tester mes vm dans différentes configurations, si j'ai un logiciel à tester je peux l'installer etc sans crainte de pourrir mon OS.
    Toutefois les modifs durant la vie du disque se font dans un second disque fork du premier. Et ce second disque, lui, il grossit durant cette vie. Et VirtualBox ne le remet pas à 0. A chaque démarrage le disque immuable est réinitialisé "logiquement" mais son clone, lui, garde sa taille ou s'agrandit mais ne baisse jamais. Et ça sur la machine physique ça prend de la place (j'ai des disques immuables de 100Go => ils ne font pas 100Go en réel car quand je les ai mis en immuable ils étaient au min mais une fois la machine démarrée ils peuvent atteindre cette taille et s'ils l'atteignent alors le fork, lui, fait réellement 100Go !!!)

    La solution c'est de supprimer physiquement le clone. A ce moment là, au démarrage suivant, le disque immuable en crée un neuf. Sauf que si on supprime le clone, VirtualBox commence par détacher le disque immuable de la machine. Donc ensuite il faut le rattacher. Et ça à force (quand tu as 5 ou 6 machines avec parfois 3 disques immuables) ça devient assez chiant.

    Donc je me suis mis dans l'idée de développer un script qui, pour toute machine
    • identifie les disques clones (et aussi de quel disque immuable ils sont clonés)
    • les supprime
    • réattache les disques immuables en question à la machine à son bon emplacement (le port)


    Et là mon script est fini. Je l'ai testé dans différentes configurations, il m'a tout nettoyé nickel
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    # Script Powershell
     
    # Fonction qui récupère des informations sur un host
    function getHostInfo($vm, $info) {
    	$data=vboxmanage showvminfo "$vm" 2>$null; $status=$?
    	if (-not $status) { return $null }
     
    	foreach ($ligne in $data) {
    		switch -exact ($info) {
    			"uuid" {
    				#UUID: xxx
    				if ($ligne.startswith("UUID:")) {
    					return $ligne.split(":")[1].trim()
    				}
    			}
    			"state" {
    				# State: xxx (since ...)
    				if ($ligne.startswith("State:")) {
    					return $ligne.split(":")[1].split("(")[0].trim()
    				}
    			}
    		}
    	}
    	return $null
    }
     
    # Fonction qui récupère les disques d'un host
    function getDisks($uuid) {
    	#Write-Host "uuid=[$uuid]"
     
    	$flag=$false
    	foreach ($ligne in vboxmanage showvminfo "$uuid") {
    		# Détection début bloc disques
    		if (-not $flag -and $ligne -eq "Storage Controllers:") {
    			$flag=$true
    			continue
    		}
     
    		# Détection fin bloc disques
    		if ($flag -and $ligne -like "NIC ?:*") {
    			$flag=$false
    			continue
    		}
     
    		# Pas en zone disques alors pas besoin de traiter
    		if (-not $flag) { continue }
     
    		# Analyse bloc disques
    		$ligne=$ligne.trim()
     
    		# Recherche controleur (#n: 'controler', ...)
    		if ($ligne -like "#?: *") {
    			$controler=$ligne.split(",")[0].split(":")[1].trim().replace("'", "")
    			continue
    		}
     
    		# Recherche port et uuid (Port p, Unit u: UUID: xxx)
    		if ($ligne -notlike "Port ?,*") { continue }
    		$ligne=$ligne.split(",")
    		$uuid=$ligne[1].split(":")[-1].trim()
    		if ($uuid -eq "Empty") { continue }
    		$port=$ligne[0].replace("Port ", "").trim()
    		@{
    			"controler"=$controler;
    			"port"=$port;
    			"uuid"=$uuid;
    			"parent"=getDiskInfo $uuid "parent";
    		}
    	}
    }
     
    # Fonction qui récupère des informations sur un disque
    function getDiskInfo($uuid, $info) {
    	#Write-Host "uuid=[$uuid]"
    	foreach ($ligne in vboxmanage showhdinfo "$uuid") {
    		switch -exact ($info) {
    			"parent" {
    				if ($ligne.startswith("Parent UUID:")) {
    					return $ligne.split(":")[-1].trim()
    				}
    			}
    			"location" {
    				if ($ligne.startswith("Location:")) {
    					return $ligne.split(":")[-1].trim()
    				}
    			}
    		}
    	}
    	return $null
    }
     
    # Programme principal
    foreach ($vm in $args) {
    	# Vérification machine - Récupération uuid
    	$uuid=getHostInfo "$vm" "uuid"
    	if ($uuid -eq $null) {
    		Write-Host "Machine [$vm] inconnue - Abort"
    		continue
    	}
     
    	# Vérification machine arrêtée
    	if (-not $(getHostInfo "$uuid" "state").startswith("powered off")) {
    		Write-Host "Machine [$vm] ($uuid) en fonction, impossible de nettoyer - Abort"
    		continue
    	}
    	Write-Host "Machine [$vm] ($uuid) prête pour nettoyage..."
    	$check=@{
    		"disks"=0;
    		"clean"=0;
    	}
     
    	# Récupération disques
    	foreach ($disk in getDisks $uuid) {
    		# Récupération disque parent
    		if ($disk["parent"] -eq "base") { continue }
    		$disk["name"]=([io.fileinfo](getDiskInfo $disk["parent"] "location")).basename
    		Write-Host "Controleur [$($disk["controler"])] - Port [$($disk["port"])] - uuid [$($disk["uuid"])] - parent [$($disk["parent"])] - name [$($disk["name"])]"
    		$check["disks"]++
     
    		# Détachement disque
    		vboxmanage storageattach "$uuid" --storagectl "$($disk["controler"])" --port "$($disk["port"])" --medium none 2>$null; $status=$?
    		if (-not $status) {
    			Write-Host "Détachement disque $($disk["uuid"])] échoué - Abort"
    			continue
    		}
    		Write-Host "Détachement disque $($disk["uuid"])] ok"
     
    		# Suppression disque
    		vboxmanage closemedium "$($disk["uuid"])" --delete; $status=$?
    		if (-not $status) {
    			Write-Host "Suppression disque $($disk["uuid"])] échouée - Abort"
    			continue
    		}
    		Write-Host "Suppression disque $($disk["uuid"])] ok"
     
    		# Réattachement disque parent
    		vboxmanage storageattach "$uuid" --type hdd --storagectl "$($disk["controler"])" --port "$($disk["port"])" --medium "$($disk["parent"])" 2>$null; $status=$?
    		if (-not $status) {
    			Write-Host "Réattachement disque [$($disk["name"])] échoué - Abort"
    			continue
    		}
    		Write-Host "Réattachement disque [$($disk["name"])] port [$($disk["port"])] ok"
    		$check["clean"]++
    	}
     
    	# Machine nettoyée
    	if ($check["disks"] -eq $check["clean"]) {
    		Write-Host "Machine [$vm] ($uuid) nettoyée ($($check["disks"]) disques)"
    	} else {
    		Write-Host "Machine [$vm] ($uuid) incohérente (disques=$($check["disks"]), clean=$($check["clean"]))"
    	}
    	Write-Host
    }

    Je t'ai donné un fichier issu de vboxmanage showvminfo. Il faut toutefois rajouter une ligne State: running (since 2023-01-25T08:34:07.279000000) qui n'était pas dans mon exemple et indiquant si la machine tourne (running) ou est à l'arrêt ("powered off" à la place de "running") car on ne peut pas détacher de disques d'une machine qui tourne.

    Il y a ensuite le résultat de vboxmanage showhdinfo qui donne les infos sur un disque précis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    UUID:           7eea1903-174d-4ad0-a8bf-91a812d53ca3
    Parent UUID:    base
    State:          locked write
    Type:           writethrough
    Location:       ...(un chemin windows)...
    Storage format: VDI
    Format variant: dynamic default
    Capacity:       15360 MBytes
    Size on disk:   14641 MBytes
    Encryption:     disabled
    Property:       AllocationBlockSize=1048576
    In use by VMs:  Xubuntu64 (UUID: 0a55e753-84ac-42e9-970a-623b56fad055)
    La ligne Parent UUID: base indique qu'il s'agit d'un disque normal (non cloné). Sinon elle donne le uuid du disque immuable dont il est issu.

    Donc (pour résumer) vboxmanage showvminfo me donne tous les disques de mon host (mais quand le disque est immuable alors ça montre le uuid du disque fils (celui qui vit réellement et qui grossit et non celui du parent). Il me faut alors passer par vboxmanage showhdinfo de chaque disque récupéré pour savoir si le disque est normal ou cloné. S'il est normal je le saute (je ne veux pas le supprimer surtout !!!) et s'il est fork je récupère le uuid de son parent le disque immuable. Et là je détache le fork, je le suprime et je rattache son parent (le disque immuable) au même emplacement.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Expert confirmé

    Homme Profil pro
    Responsable déploiement (SCCM, InTune, GPO)
    Inscrit en
    Juillet 2014
    Messages
    3 183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Responsable déploiement (SCCM, InTune, GPO)
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2014
    Messages : 3 183
    Points : 5 754
    Points
    5 754
    Par défaut
    Oui je connais bien ce principe de disque persistent ou non avec vmware.
    Vmware paraît d'ailleurs bien plus accessible via une intégration de cmdlets (module) complet Powershell.
    Bon le principal est que ton objectif sois atteint et que cela fonctionne 👍

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Prob Exécuter un programme externe "Calc"
    Par badboykiller dans le forum VB.NET
    Réponses: 2
    Dernier message: 01/03/2010, 17h36
  2. Réponses: 3
    Dernier message: 07/08/2008, 10h00
  3. [PHP-JS] Exécuter un programme externe
    Par MagicManu dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 06/05/2008, 08h35
  4. Exécuter un programme externe
    Par nourbane dans le forum ASP
    Réponses: 3
    Dernier message: 07/09/2006, 18h52
  5. Comment exécuter un programme externe ?
    Par spikto dans le forum Langage
    Réponses: 12
    Dernier message: 27/06/2005, 16h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo