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 :

avis pour amélioration [PowerShell]


Sujet :

Scripts/Batch

  1. #1
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut avis pour amélioration
    Bonsoir à tous,


    Je suis un débutant en PowerShell, et bien que déjà initié au scripting sous Linux (bash/perl), les conventions de scripts sysadmin Windows me sont totalement inconnues... c'est pourquoi je souhaiterais avoir quelques critiques (constructives ) sur ce petit exemple
    (il s'agit de compiler un mémoire en latex avec conversion des eps en pdf histoire d'avoir un pdf utilisable au lieu de la bouse issue de dvips puis ps2pdf... au final l'objectif est de reconstruire un make complet sous forme de DSL)

    je n'aime pas du tout mon utilisation excessive de Invoke-Expression, si vous aviez des méthodes propres pour faire un style de Invoke-Command $commande @args


    la "bibliothèque de fonctions"
    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
    Function Check-Command
    {
        Param(
            [parameter(Position=0,Mandatory=$true)][string] $Command,
            [parameter(Mandatory=$false)][System.Management.Automation.ActionPreference] $ErrAction = [System.Management.Automation.ActionPreference]::Inquire
        )
        Return (Get-Command -CommandType Application -ErrorAction $ErrAction $Command).Definition
    }
    
    Function Replace-Extension
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $FileName,
            [Parameter(Mandatory=$true,Position=1)][string] $FinalExtension
        )
        $InitialExtension = [regex]::Replace($FileName, "(.+)\.([^\.]+)$", '$2')
        Return (($FileName) -Replace "$InitialExtension$", $FinalExtension)
    }
    
    Function Check-Location
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $CurrentLocation,
            [Parameter(Mandatory=$true,Position=1)][string] $FilePath
        )
        $Location = Split-Path $FilePath
        If ($CurrentLocation -ne $Location)
        {
            Set-Location $Location
            Return $Location
        }
        Return $CurrentLocation
    }
    
    Function Check-MustBeUpdated
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $ExistingLocation,
            [Parameter(Mandatory=$true,Position=1)][string] $NewLocation,
            [Parameter(Mandatory=$true,Position=2)] $Test
        )
        If (Test-Path $NewLocation)
        {
            If (& $Test $ExistingLocation (Get-Item $NewLocation))
            {
                Return $false
            }
        }
        Return $true
    }
    
    Function Keep-Location ($code)
    {
        Push-Location
        & $code
        Pop-Location
    }
    le script
    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
    Param(
        # Programmes externes
        [parameter(Mandatory=$false)][string] $ExecLatex = 'pdflatex',
        [parameter(Mandatory=$false)][string] $ExecBibtex = 'bibtex',
        [parameter(Mandatory=$false)][string] $Converter = 'epstopdf',
        # Paramètres 
        [parameter(Mandatory=$false)][string] $ImgRoot = 'images',
        [parameter(Mandatory=$false)][string] $Filter = '*.eps',
        [parameter(Mandatory=$false)][string] $FinalExtension = 'pdf',
        [parameter(Mandatory=$false)][string] $MainLatex = 'memoire',
        [parameter(Mandatory=$false)][string] $LatexOptions = ' -quiet -halt-on-error -disable-installer '
    )
    
    . .\my_utils.ps1
    
    ########################################################################
    
    ForEach ($prg in $ExecLatex,$ExecBibtex,$Converter)
    {
        Check-Command $prg
    }
    
    $cmdLatex = "$ExecLatex $LatexOptions '$MainLatex'"
    $cmdBibtex = "$ExecBibtex '$MainLatex'"
    
    Keep-Location {
        $currentDir = $ImgRoot
        $test = { Param($old,$new) Return ($new.LastWriteTime -gt $old.LastWriteTime) }
        ForEach ($img in (Get-ChildItem $ImgRoot -Recurse -Include $Filter))
        {
            $currentDir = Check-Location $currentDir $img
            $pdfName = Replace-Extension ($img.Name) $FinalExtension
            If (Check-MustBeUpdated $img $pdfName $test)
            {
                Invoke-Expression ($Converter + ' ' + ($img.Name))
            }
        } 
    }
    
    
    Invoke-Expression $cmdLatex -ErrorAction Stop
    Invoke-Expression $cmdBibtex -ErrorAction Stop
    Invoke-Expression $cmdLatex -ErrorAction Stop
    Invoke-Expression $cmdLatex -ErrorAction Stop

    par avance
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  2. #2
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    au finale l'objectif est de reconstruire un make complet sous forme de DSL
    Peut-être que PSake peut t'aider...
    Citation Envoyé par gorgonite
    si vous aviez des méthodes propres pour faire un style de Invoke-Command $commande @args
    Invoke-Command est dédié au remoting.
    Citation Envoyé par gorgonite
    je n'aime pas du tout mon utilisation excessive de Invoke-Expression,
    Utilise le pipeline :
    Citation Envoyé par gorgonite
    $cmdLatex,$cmdBibtex,$cmdLatex,$cmdLatex |Invoke-Expression -ErrorAction Stop
    Tu peux aussi manipuler des scriptblocks au lieu de string et les exécuter dans la portée courante avec le point au lieu du ET commercial (&).
    Voir aussi ceci qui peut faciliter le codage au détriment, relatif, du déploiement.

    Dans Check-Command il y a peut être un pb potentiel, car Get-Command peut renvoyer + applis selon le contenu du path, enfin c'est à vérifier.

    Split-path peut poser pb si on utilise un nom de lecteur inconnu.

    Pour la convention de nommage de PS, Test est préférable à Check.

  3. #3
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par Laurent Dardenne Voir le message
    Peut-être que PSake peut t'aider...
    ok... donc ça existait déjà

    Citation Envoyé par Laurent Dardenne Voir le message
    Tu peux aussi manipuler des scriptblocks au lieu de string et les exécuter dans la portée courante avec le point au lieu du ET commercial (&).
    Voir aussi ceci qui peut faciliter le codage au détriment, relatif, du déploiement.

    je ne vois pas comment transformer "$ExecLatex $LatexOptions" en fermeture attendant comme argument $MainLatex

    à moins que vous ne parliez de faire ceci ?
    auquel cas, je ne vois pas trop l'intérêt d'alourdir ma notation pour aussi peu de gain en expressivité

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $cmdLatex = "$ExecLatex $LatexOptions '$MainLatex'".ExpandString().NewScriptBlock()
    
    ...
    
    . $cmdLatex

    Citation Envoyé par Laurent Dardenne Voir le message
    Split-path peut poser pb si on utilise un nom de lecteur inconnu.

    J'ai mis cela avant... est-ce suffisant ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	If ( -not (Test-Path $FilePath))
    	{
    		Throw "error: $FilePath"
    	}
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  4. #4
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    auquel cas, je ne vois pas trop l'intérêt d'alourdir ma notation pour aussi peu de gain en expressivité
    Ici l'appel à expandstring est redondant, c'était juste une autre possibilité :-)
    Citation Envoyé par gorgonite
    J'ai mis cela avant... est-ce suffisant ?
    Je pense, reste à le tester.

  5. #5
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    nouvelle version... avec un New-ScriptBlock (récupéré sur un blog)


    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
    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
    Function Test-Command
    {
        Param(
            [parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)][string] $Command,
            [parameter(Mandatory=$false)][System.Management.Automation.ActionPreference] $ErrAction = [System.Management.Automation.ActionPreference]::Inquire
        )
        BEGIN { }
        PROCESS {
            Return @(Get-Command -CommandType Application -ErrorAction $ErrAction $Command)[0].Definition
        }
        END { }
    }
    
    Function Rename-ItemExtension
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $FileName,
            [Parameter(Mandatory=$true,Position=1)][string] $FinalExtension
        )
        #$InitialExtension = [regex]::Replace($FileName, "(.+)\.([^\.]+)$", '$2')
        #Return (($FileName) -Replace "$InitialExtension$", $FinalExtension)
        $File = Get-Item $FileName
        $InitialExtension = $File.Extension
        Return ($File.BaseName + '.' + $FinalExtension)
    }
    
    Function Test-MustChangeLocation
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $CurrentLocation,
            [Parameter(Mandatory=$true,Position=1)][string] $FilePath
        )
        If ( -not (Test-Path $FilePath))
        {
            Throw "error: $FilePath"
        }
        $Location = Split-Path $FilePath
        If ($CurrentLocation -ne $Location)
        {
            Set-Location $Location
            Return $Location
        }
        Return $CurrentLocation
    }
    
    Function Test-MustBeUpdated
    {
        Param(
            [Parameter(Mandatory=$true,Position=0)][string] $ExistingLocation,
            [Parameter(Mandatory=$true,Position=1)][string] $NewLocation,
            [Parameter(Mandatory=$true,Position=2)][scriptblock] $Test
        )
        If (Test-Path $NewLocation)
        {
            If (. $Test $ExistingLocation (Get-Item $NewLocation))
            {
                Return $false
            }
        }
        Return $true
    }
    
    Function Invoke-ScriptBlock
    {
        Param(
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)][scriptblock] $code,
            [switch] $KeepLocation
        )
        if ($KeepLocation)
        {
            Push-Location
        }
        . $code
        if ($KeepLocation)
        {
            Pop-Location
        }
    }
    
    Function New-ScriptBlock
    {
        Param([Parameter(Position=0,Mandatory=$true)][string] $textofscriptblock)
        $executioncontext.InvokeCommand.NewScriptBlock($textofscriptblock)
    }
    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
    Param(
        # Programmes externes
        [parameter(Mandatory=$false)][string] $ExecLatex = 'pdflatex',
        [parameter(Mandatory=$false)][string] $ExecBibtex = 'bibtex',
        [parameter(Mandatory=$false)][string] $Converter = 'epstopdf',
        # Paramètres 
        [parameter(Mandatory=$false)][string] $ImgRoot = 'images',
        [parameter(Mandatory=$false)][string] $Filter = '*.eps',
        [parameter(Mandatory=$false)][string] $FinalExtension = 'pdf',
        [parameter(Mandatory=$false)][string] $MainLatex = 'memoire',
        [parameter(Mandatory=$false)][string] $LatexOptions = ' -quiet -halt-on-error -disable-installer '
    )
    
    . .\my_utils.ps1
    
    ########################################################################
    
    $ExecLatex,$ExecBibtex,$Converter | Test-Command
    
    $cmdLatex  = New-ScriptBlock "$ExecLatex $LatexOptions '$MainLatex'"
    $cmdBibtex = New-ScriptBlock "$ExecBibtex '$MainLatex'"
    
    Invoke-ScriptBlock -KeepLocation {
        $currentDir = $ImgRoot
        $test = { Param($old,$new) Return ($new.LastWriteTime -gt $old.LastWriteTime) }
        (Get-ChildItem $ImgRoot -Recurse -Include $Filter) | Foreach-Object {
            $currentDir = Test-MustChangeLocation $currentDir $_
            $pdfName = Rename-ItemExtension ($_.Name) $FinalExtension
            If (Test-MustBeUpdated $_ $pdfName $test)
            {
                & $Converter ($_.Name)
            }
        } 
    }
    
    $cmdLatex,$cmdBibtex,$cmdLatex,$cmdLatex | Foreach-Object { 
        Invoke-Command -ErrorAction Stop -ScriptBlock $_ 
    }
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  6. #6
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    au passage, vu le grand nombre de fichiers et que chaque conversion eps -> pdf est une tâche "mono-threadée" prenant près d'une minute, j'ai décidé de paralléliser quelque peu le script


    Pour cela, je passe par une routine Foreach-Parallel

    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
    Function Foreach-Parallel
    {
        Param (
            [Parameter(Mandatory=$true,Position=0)][scriptblock] $Task,
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] $Data,
            [Parameter(Mandatory=$false)][ValidateScript({$_ -gt 0})][int] $Max = 2
        )
        Begin 
        {
            $jobs =  New-Object System.Collections.ArrayList
        }
        Process
        {
            While ($jobs.Count -ge $Max)
            {
                Wait-Job -Any $jobs | Out-Null
                $finishedJobs =  ($jobs | Where-Object { $_.State -eq 'Completed' })
                $finishedJobs | Foreach-Object { $jobs.Remove($_) }
            }
            $jobs.Add((Start-Job { . $Task $Data }))
        }
        End
        {
            Wait-Job $jobs | Out-Null
        }
    }
    dans cette version, les jobs sont bien lancés, mais il semble que rien ne soit fait (alors que tous les jobs sont bien lancés )

    Je pense toutefois remplacer à terme les Wait-Job par un simple System.Threading.Semaphore

    Edit : 2nde version avec des threads et non des jobs

    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
    61
    62
    63
    64
    65
    66
    67
    68
    Function New-Thread {
        $config   = [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace.RunspaceConfiguration
        $runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace($config)
        $thread   = New-Object System.Object
    
        $thread | Add-Member NoteProperty "Runspace" $runspace
        $thread | Add-Member NoteProperty "Pipeline" $null
        $thread | Add-Member ScriptProperty "Running" { return ($this.Pipeline -ne $null -and (-not $this.Pipeline.Error.EndOfPipeline -or -not $this.Pipeline.Output.EndOfPipeline)) }
    
        $thread.Runspace.Open()
    
        return $thread
    }
    
    Function Start-Thread {
        param ([object]$thread = $null,[ScriptBlock]$scriptBlock = $(throw "The parameter -scriptBlock is required."))
    
        if ($thread -eq $null) {$thread = New-Thread}
    
        if ($thread.Running) {throw "The thread is already running, please wait for it complete before trying again."}
    
        $thread.Pipeline = $thread.Runspace.CreatePipeline($scriptBlock)
        $thread.Pipeline.Input.Close()
        $thread.Pipeline.InvokeAsync()
    
        return $thread
    }
    
    Function Join-Thread {
        Param ([object]$thread = $(throw "The parameter -thread is required."))
    
        If ($thread.Pipeline -ne $null) {
            while ($true) {
                Read-Thread -thread $thread
                if ($thread.Pipeline.Error.EndOfPipeline -and $thread.Pipeline.Output.EndOfPipeline) {break}
                $thread.Pipeline.Output.WaitHandle.WaitOne(250, $false) | Out-Null
            }
    
            Stop-Thread $thread
    
            if ($thread.Pipeline.PipelineStateInfo.State -eq "Failed") {
                throw $thread.Pipeline.PipelineStateInfo.Reason
            }
        }
    }
    
    Function Foreach-Parallel
    {
        Param (
            [Parameter(Mandatory=$true,Position=0)][scriptblock] $Task,
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] $Data,
            [Parameter(Mandatory=$false)][ValidateScript({$_ -gt 0})][int] $Max = 2
        )
        Begin 
        {
            $jobs =  New-Object System.Collections.ArrayList
            $pool = New-Object System.Threading.Semaphore $Max,$Max
        }
        Process
        {       
            $jobs.Add((Start-Thread -ScriptBlock { $pool.WaitOne() ; . $Task $Data ; $pool.Release() } ))
        }
        End
        {
            $jobs | Foreach-Object { Join-Thread -thread $_ }
        }
    }
    idem... rien n'est fait


    Qu'en pensez-vous ?


    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  7. #7
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par gorgonite
    Citation Envoyé par Laurent Dardenne Voir le message
    Peut-être que PSake peut t'aider...
    ok... donc ça existait déjà
    en fait, non... il semblerait qu'aucune construction de graphe de dépendance des taches ne soit faite afin de pouvoir exécuter parallèlement un nombre N (paramétré) de tâches sans risque
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  8. #8
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    Qu'en pensez-vous ?
    Attention à l'efffet de bord dans Foreach-Parallel avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $jobs.Add((Start-Job { . $Task $Data }))
    Cette méthode renvoi un integer, le mieux est d'utiliser [void]$jobs.Add ...

    N'ayant pas le code complet sous les yeux, tu as peut être un pb de portée de variable. Dans ce cas pour les jobs utilise $globale:MaVar et pour les runspaces il faut injecter les variables à l'aide de la méthode SetVariable du Runspace.

    Citation Envoyé par gorgonite
    Je pense toutefois remplacer à terme les Wait-Job par un simple System.Threading.Semaphore
    Cela fonctionne, mais c'est parfois délicat à mettre au point, PS n'est pas fait pour ça, le mieux étant d'utiliser la mécanique des jobs.

  9. #9
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par Laurent Dardenne Voir le message
    Attention à l'efffet de bord dans Foreach-Parallel avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $jobs.Add((Start-Job { . $Task $Data }))
    Cette méthode renvoi un integer, le mieux est d'utiliser [void]$jobs.Add ...
    en effet... corrigé ça pourrit moins la console

    Citation Envoyé par Laurent Dardenne Voir le message
    N'ayant pas le code complet sous les yeux, tu as peut être un pb de portée de variable. Dans ce cas pour les jobs utilise $globale:MaVar et pour les runspaces il faut injecter les variables à l'aide de la méthode SetVariable du Runspace.

    Cela fonctionne, mais c'est parfois délicat à mettre au point, PS n'est pas fait pour ça, le mieux étant d'utiliser la mécanique des jobs.

    testé et foiré... aussi bien en Job qu'en Thread
    je fais sûrement me faire des vraies classes C# (mais le framework .net 4 et powershell n'ont pas l'air de faire bon ménage)
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  10. #10
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    en effet... corrigé ça pourrit moins la console
    Lorsque qu'on utilise le pipeline c'est déjà plus gênant car moins 'visible'.
    Citation Envoyé par gorgonite
    je fais sûrement me faire des vraies classes C#
    Pas sûr que cela résolve ton pb...

  11. #11
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Au fait, pour récupérer le résultat des jobs tu utilises bien Receive-Job dans un segment de pipeline, car $jobs est déclaré dans le bloc Begin (portée locale aux segments).

  12. #12
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par Laurent Dardenne Voir le message
    Au fait, pour récupérer le résultat des jobs tu utilises bien Receive-Job dans un segment de pipeline, car $jobs est déclaré dans le bloc Begin (portée locale aux segments).

    je n'ai pas besoin de récupérer le moindre résultat... juste d'attendre d'être sûr que le traitement soit fini


    ma version actuelle:
    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
    Function Foreach-Parallel
    {
        Param (
            [Parameter(Mandatory=$true,Position=0)][scriptblock] $Task,
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] $Data,
            [Parameter(Mandatory=$false)][ValidateScript({$_ -gt 0})][int] $Max = 4
        )
        Begin 
        {
            $jobs =  New-Object System.Collections.ArrayList
            #Set-Variable pool (New-Object System.Threading.Semaphore $Max,$Max) -scope global
        }
        Process
        {
    		$job = { . $Task $Data } # ; $global:pool.Release() }
    		#[void] $global:pool.WaitOne()
    		[void] $jobs.Add((Start-Job $job ))
        }
        End
        {
            Wait-Job -Job $jobs | Out-Null
        }
    }
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  13. #13
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    je n'ai pas besoin de récupérer le moindre résultat... juste d'attendre d'être sûr que le traitement soit fini
    Au temps pour moi.

    Après qq essais, ceci devrait t'aider :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
      $job = {param($task, $data) iex $Task } 
      [void]$jobs.Add((Start-Job -scriptblock $job -argument @($Task,$Data)))
    On doit passer les données utilisées par le scriptblock du job via le paramètre ArgumentList.
    L'autre soucis est que le SB est converti en string on doit donc dans ce cas utiliser Invoke-Expression.
    Deux pas en avant, un pas en arrière

  14. #14
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Par contre dans le lien cité (du post précédent), l'auteur indique, si j'ai bien compris, que PS v2 ne supporte pas les closures, c'est faux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $sb={"test"}
    $sb.GetNewClosure()

  15. #15
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    ce ne serait pas plutôt ?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $job = {param($task, $data) iex "$Task $data" }
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  16. #16
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    ce ne serait pas plutôt ?
    Pour ton contexte oui, je n'ai pas utilisé $data dans mes tests, ce n'était pas le plus important.

  17. #17
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par Laurent Dardenne Voir le message
    Pour ton contexte oui, je n'ai pas utilisé $data dans mes tests, ce n'était pas le plus important.


    Voici mon code actuel

    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
    Function Foreach-Parallel
    {
        Param (
            [Parameter(Mandatory=$true,Position=0)][scriptblock] $Task,
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] $Data,
            [Parameter(Mandatory=$false)][ValidateScript({$_ -gt 0})][int] $Max = 4
        )
        Begin 
        {
            $jobs =  New-Object System.Collections.ArrayList
        }
        Process
        {
            $job = { 
                Param($t,$d) 
                "$t $d"
                Invoke-Expression "$t $d" 
            }
            [void] $jobs.Add((Start-Job $job -Argument @($Task,$Data) ))
        }
        End
        {
            Receive-Job $jobs
            Wait-Job -Job $jobs | Out-Null
        }
    }

    aucune erreur ne semble survenir, mais je ne reçois pas les messages émis "$t $d", et l'opération de conversion n'est pas effectuée...


    je me repencherai sur ce problème dans quelques jours...

    pour ton temps et ton aide
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  18. #18
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gorgonite
    pour ton temps et ton aide
    De rien.
    Citation Envoyé par gorgonite
    mais je ne reçois pas les messages émis "$t $d",
    Par défaut l'émission du résultat se fait dans le pipeline, donc ici celle du job, il faut utiliser Write-host ou Write-Debug pour forcer l'affichage sur la console, mais dans le dernier cas il faut ajouter, dans le code du job, $DebugPreference="Continue".

    Peux-tu joindre un fichier contenant l'ensemble des fichiers ?

  19. #19
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Par défaut
    Citation Envoyé par Laurent Dardenne Voir le message
    Par défaut l'émission du résultat se fait dans le pipeline, donc ici celle du job, il faut utiliser Write-host ou Write-Debug pour forcer l'affichage sur la console, mais dans le dernier cas il faut ajouter, dans le code du job, $DebugPreference="Continue".

    j'avais aussi essayé avec Write-Host.. en vain

    Citation Envoyé par Laurent Dardenne Voir le message
    Peux-tu joindre un fichier contenant l'ensemble des fichiers ?

    fait
    Fichiers attachés Fichiers attachés
    Evitez les MP pour les questions techniques... il y a des forums
    Contributions sur DVP : Mes Tutos | Mon Blog

  20. #20
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Billets dans le blog
    1
    Par défaut
    Ceci fonctionne :
    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
    Function Foreach-Parallel
    {
        Param (
            [Parameter(Mandatory=$true,Position=0)][scriptblock] $Task,
            [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1)] $Data,
            [Parameter(Mandatory=$false)][ValidateScript({$_ -gt 0})][int] $Max = 4
        )
        Begin 
        {
            Write-debug "Begin"
            $jobs =  New-Object System.Collections.ArrayList
        }
        Process
        {
            Write-debug "Process"
            $job = { 
                Param($t,$d) 
                write-Warning "$t $d"
                 #trace-command -name InvokeExpressionCommand -command Invoke-Expression "$t $d"  -filepath c:\Temp\Tace-iex.txt  
                Invoke-Expression "$t $d" 
            }
            [void] $jobs.Add((Start-Job $job -Argument @($Task,$Data) ))
        }
        End
        {
            Write-debug "End"
            Wait-Job -Job $jobs | Receive-Job 
        }
    }
    #remove-job *
    del C:\Temp\Log.txt -Force -EA SilentlyContinue
    $sb={cmd /c dir C:\temp} 
    $Data=" > C:\Temp\Log.txt"
    Foreach-Parallel $sb $data
    get-job
    Type C:\Temp\Log.txt
    Au cas où, tu peux utiliser Trace-Command pour vérifier si l'appel ne pose pas de pb.

    Il y a peut être un pb de path ? Bien qu'à priori tu utilises $env:path
    Il me semble (pas testé) que dans le job le chemin courant n'est pas identique à celui de la console.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. avis pour améliorer mon diagramme de classe: gestion des sujets PFE
    Par win_ubuntu dans le forum Diagrammes de Classes
    Réponses: 0
    Dernier message: 12/08/2014, 21h35
  2. Votre avis pour améliorer mon code (opérations matricielles)
    Par Schopenhauer dans le forum Débuter
    Réponses: 42
    Dernier message: 17/09/2010, 19h25
  3. avis pour améliorer mon cv
    Par Nath_k dans le forum CV
    Réponses: 4
    Dernier message: 20/09/2009, 12h45
  4. Réponses: 30
    Dernier message: 05/08/2009, 19h25
  5. [CV] Avis pour améliorer mon cv
    Par lapanne dans le forum CV
    Réponses: 7
    Dernier message: 17/10/2007, 15h04

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