Question [Function]Gestion d'un "reste à faire"
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
Réduire
Plus d'informations
- Messages : 6311
- Remerciements reçus 68
il y a 16 ans 2 mois #6009
par Laurent Dardenne
Tutoriels PowerShell
[Function]Gestion d'un "reste à faire" a été créé par Laurent Dardenne
Lors de traitement sur une liste d'élements on a souvent besoin de réitérer ce même traitement sur les éléments qui n'ont pu être traités pour une raison ou pour une autre.
La fonction suivante permet de gérer, au travers de deux listes en mémoire, \"le reste à faire\".
[code:1]
Function Invoke-RemainderObject([Object[]] $ToDo,
[REF]$Done,
[String] $FilterName,
[Object[]] $Property,
[switch] $List)
{ #Cette fonction facilite la gestion du \"reste à faire\" sur une collection d'objets.
#La liste $Todo contient tous les objets à traiter, la soustraction de la liste $Done,
#qui contient la liste des objets déjà traités lors d'une itération précédente,
# constitue le reste à faire.
#
#Le paramètre $FilterName contient le nom d'un filtre renvoyant les objets à traiter
#selon la condition établie dans ce filtre.
#
#Exemple :
# Filter Test-ComputerConnection {
# if ((Test-Connection $_ -ErrorAction \"SilentlyContinue\" -count 1).StatusCode -eq 0)
# {$_}
# }
#
# #Liste contenant tous les noms de machine
# $Todo=@(\"pc1\",\"pc2\",\"pc3\",\"pc4\",\"LocalHost\"«»)
# #Liste contenant tous les noms de machine déjà traitées
# [REF]$Done=@(\"pc2\",\"pc4\"«»)
# #Renvoi la liste des machines restant à traiter ou à retraiter suite à une erreur
# Invoke-RemainderObject $ToDo $Done -List
# #Exécute le traitment pour le \"reste à faire\"
# $ToDo|
# Invoke-RemainderObject -D $Done -F Test-ComputerConnection|
# Foreach { Get-WmiObject - computername $_ Win32_ComputerSystem}
#
#Renvoi :
# soit $Null s'il n'y a plus d'objet à traiter ou si aucun traitement
# n'a réussi sur ceux-ci.
# soit la liste des objets traités avec succés.
#
# $Todo contient la liste de tous les objets à traiter.
# Cette liste peut provenir du pipeline, dans ce cas on attend la réception
# de tous les objets avant de les propager dans les segments suivants
#
# $Done contient la liste de tous les objets qui ont déjà été traités.
#
#Le filtre $FilterName DOIT, si le traitement réussi, renvoyer l'objet qu'il a reçut
#, mais pas d'autre informations.
#
# $Property contient les noms de propriété utilisées lors de la comparaison
# entre la liste $Todo et la liste $Done.
#
#Le switch $List permet uniquement de récupérer la liste des objets restant à traiter.
#Dans ce cas aucun traitement sur les objets restant à traiter n'est effectué.
Function GetRemainderObject
{ #Construit la liste des objets restants à traiter
#renvoi $null s'il n'y a aucune différence
#entre les deux listes
$Max=[Math]::Max($ToDo.count,$Done.Value.count)
Compare-object $Done.Value $ToDo -Sync $Max -Property $Property -passthru
}
$DataFromPipeline=$input|%{$_}
if ($Todo -and $DataFromPipeline)
{throw \"Impossible de coupler l'usage du pipeline avec le paramètre `$ToDo\"}
If ($Todo -eq $null)
{
if ($DataFromPipeline -eq $null)
{Throw \"Le paramètre ToDo contient `$null.\" }
$Todo=$DataFromPipeline
}
If ($Done -eq $null) {Throw \"Le paramètre Done contient `$null.\" }
if ($List)
{
If ($Script -ne $null) {Throw \"L'option -List n'utilise pas le paramètre Script.\" }
GetRemainderObject
}
elseIf ([string]::IsNullOrEmpty($FilterName))
{Throw \"Le paramètre Script est une chaîne vide ou contient `$null.\" }
#Reste-t-il des objets de la liste à traiter ?
#Sinon, on renvoie $null
elseif ($ToDo.Count -ne $Done.Value.Count)
{
if ($Done.Value.Count -gt 0)
{ $Remainder=GetRemainderObject}
else
{[object[]] $Remainder= $Todo}
#Renvoi $null si aucun des objets restant à traiter
#n'est réémis dans le pipeline.
$Remainder|
&$FilterName|
#Renseigne la liste des objets traités puis réémet l'objet qui vient d'être traité
Foreach {
if ($Done.Value -notcontains $_)
{$Done.Value +=$_ ; $_}
}
}#Todo.Count
} #Invoke-RemainderObject
[/code:1]
Un exemple autour de la recherche des machines offline/online :
[code:1]
Filter Test-ComputerConnection {
if ((Test-Connection $_ -ErrorAction \"SilentlyContinue\" -count 1).StatusCode -eq 0)
{$_}
}
#Liste contenant tous les noms de machine
$Todo=@(\"pc1\",\"pc2\",\"pc3\",\"pc4\",\"LocalHost\"«»)
#Liste contenant tous les noms de machine déjà traitées
[REF]$Done=@(\"pc2\",\"pc4\"«»)
#Renvoi la liste des machines restant à traiter ou à retraiter suite à une erreur
Invoke-RemainderObject $ToDo $Done -List
$MachinesOnLine=Invoke-RemainderObject $ToDo $Done -F Test-ComputerConnection
$MachinesOnLine
#réinitialise la liste pour le test suivant
[REF]$Done=@(\"pc2\",\"pc4\"«»)
#Exécute le traitment pour le \"reste à faire\"
$ToDo|Invoke-RemainderObject -D $Done -F Test-ComputerConnection|Foreach { Get-WmiObject -computername $_ Win32_ComputerSystem}
#liste des machine traitées
$Done.Value
\"Reste à faire ? $(!($ToDo.Count -eq $Done.Value.Count))\"
\"Liste des objets restant $(Invoke-RemainderObject $ToDo $Done -List)\"
[/code:1]
Un autre exemple autour de la suppression de fichiers de tests :
[code:1]
$path=\"C:\Temp\"
del \"$Path\File*.txt\" -Whatif
Break
del \"$Path\File*.txt\" -force
1..9|% {\"test\" > \"$Path\File$_.txt\"}
$AllFiles=dir \"$Path\File*.txt\"
#Positionne l'attribut en lecture seule
1,3,5|% {$F=$AllFiles[($_-1)];$F.Attributes = $F.Attributes -bor [System.IO.FileAttributes]::ReadOnly}
[REF]$Done=@()
filter Remove-File{
del $_ -verbose -ea SilentlyContinue
if ($?)
{ $_ }
}
$Error.Clear()
#Allfiles
dir \"$Path\File*.txt\"|
#supprime les fichiers créés, si l'action réussi on réémet l'objet
Invoke-RemainderObject -Done $Done -F Remove-File|
Foreach {Write-host \"Le fichier $_ a été supprimé\" -fore White}
\"Liste des fichiers restant $(Invoke-RemainderObject $AllFiles $Done -List)\"
$Done.Value
Write-Host \"Les objets en erreur\"
$Error
[/code:1]
Ni la récupération de la liste des objets traités ni celle des objets retenus par le filtre, ne sont implémentées, pas plus que la persistance des listes $Todo et $Done.
Les objets retenus par le filtre seront de nouveau traités lors de la prochaine itération, sous réserve que la liste $Done n'est pas effacée. Si c'est le cas l'ensemble des objets sera de nouveau traité.
Le cmdlet Export-CliXml peut être utilisé pour la persistance, attention toutefois a la validité des propriétés utilisées dans vos traitements.
Testé avec la v1 et v2 sous XP x32.<br><br>Message édité par: Laurent Dardenne, à: 6/06/10 16:17
La fonction suivante permet de gérer, au travers de deux listes en mémoire, \"le reste à faire\".
[code:1]
Function Invoke-RemainderObject([Object[]] $ToDo,
[REF]$Done,
[String] $FilterName,
[Object[]] $Property,
[switch] $List)
{ #Cette fonction facilite la gestion du \"reste à faire\" sur une collection d'objets.
#La liste $Todo contient tous les objets à traiter, la soustraction de la liste $Done,
#qui contient la liste des objets déjà traités lors d'une itération précédente,
# constitue le reste à faire.
#
#Le paramètre $FilterName contient le nom d'un filtre renvoyant les objets à traiter
#selon la condition établie dans ce filtre.
#
#Exemple :
# Filter Test-ComputerConnection {
# if ((Test-Connection $_ -ErrorAction \"SilentlyContinue\" -count 1).StatusCode -eq 0)
# {$_}
# }
#
# #Liste contenant tous les noms de machine
# $Todo=@(\"pc1\",\"pc2\",\"pc3\",\"pc4\",\"LocalHost\"«»)
# #Liste contenant tous les noms de machine déjà traitées
# [REF]$Done=@(\"pc2\",\"pc4\"«»)
# #Renvoi la liste des machines restant à traiter ou à retraiter suite à une erreur
# Invoke-RemainderObject $ToDo $Done -List
# #Exécute le traitment pour le \"reste à faire\"
# $ToDo|
# Invoke-RemainderObject -D $Done -F Test-ComputerConnection|
# Foreach { Get-WmiObject - computername $_ Win32_ComputerSystem}
#
#Renvoi :
# soit $Null s'il n'y a plus d'objet à traiter ou si aucun traitement
# n'a réussi sur ceux-ci.
# soit la liste des objets traités avec succés.
#
# $Todo contient la liste de tous les objets à traiter.
# Cette liste peut provenir du pipeline, dans ce cas on attend la réception
# de tous les objets avant de les propager dans les segments suivants
#
# $Done contient la liste de tous les objets qui ont déjà été traités.
#
#Le filtre $FilterName DOIT, si le traitement réussi, renvoyer l'objet qu'il a reçut
#, mais pas d'autre informations.
#
# $Property contient les noms de propriété utilisées lors de la comparaison
# entre la liste $Todo et la liste $Done.
#
#Le switch $List permet uniquement de récupérer la liste des objets restant à traiter.
#Dans ce cas aucun traitement sur les objets restant à traiter n'est effectué.
Function GetRemainderObject
{ #Construit la liste des objets restants à traiter
#renvoi $null s'il n'y a aucune différence
#entre les deux listes
$Max=[Math]::Max($ToDo.count,$Done.Value.count)
Compare-object $Done.Value $ToDo -Sync $Max -Property $Property -passthru
}
$DataFromPipeline=$input|%{$_}
if ($Todo -and $DataFromPipeline)
{throw \"Impossible de coupler l'usage du pipeline avec le paramètre `$ToDo\"}
If ($Todo -eq $null)
{
if ($DataFromPipeline -eq $null)
{Throw \"Le paramètre ToDo contient `$null.\" }
$Todo=$DataFromPipeline
}
If ($Done -eq $null) {Throw \"Le paramètre Done contient `$null.\" }
if ($List)
{
If ($Script -ne $null) {Throw \"L'option -List n'utilise pas le paramètre Script.\" }
GetRemainderObject
}
elseIf ([string]::IsNullOrEmpty($FilterName))
{Throw \"Le paramètre Script est une chaîne vide ou contient `$null.\" }
#Reste-t-il des objets de la liste à traiter ?
#Sinon, on renvoie $null
elseif ($ToDo.Count -ne $Done.Value.Count)
{
if ($Done.Value.Count -gt 0)
{ $Remainder=GetRemainderObject}
else
{[object[]] $Remainder= $Todo}
#Renvoi $null si aucun des objets restant à traiter
#n'est réémis dans le pipeline.
$Remainder|
&$FilterName|
#Renseigne la liste des objets traités puis réémet l'objet qui vient d'être traité
Foreach {
if ($Done.Value -notcontains $_)
{$Done.Value +=$_ ; $_}
}
}#Todo.Count
} #Invoke-RemainderObject
[/code:1]
Un exemple autour de la recherche des machines offline/online :
[code:1]
Filter Test-ComputerConnection {
if ((Test-Connection $_ -ErrorAction \"SilentlyContinue\" -count 1).StatusCode -eq 0)
{$_}
}
#Liste contenant tous les noms de machine
$Todo=@(\"pc1\",\"pc2\",\"pc3\",\"pc4\",\"LocalHost\"«»)
#Liste contenant tous les noms de machine déjà traitées
[REF]$Done=@(\"pc2\",\"pc4\"«»)
#Renvoi la liste des machines restant à traiter ou à retraiter suite à une erreur
Invoke-RemainderObject $ToDo $Done -List
$MachinesOnLine=Invoke-RemainderObject $ToDo $Done -F Test-ComputerConnection
$MachinesOnLine
#réinitialise la liste pour le test suivant
[REF]$Done=@(\"pc2\",\"pc4\"«»)
#Exécute le traitment pour le \"reste à faire\"
$ToDo|Invoke-RemainderObject -D $Done -F Test-ComputerConnection|Foreach { Get-WmiObject -computername $_ Win32_ComputerSystem}
#liste des machine traitées
$Done.Value
\"Reste à faire ? $(!($ToDo.Count -eq $Done.Value.Count))\"
\"Liste des objets restant $(Invoke-RemainderObject $ToDo $Done -List)\"
[/code:1]
Un autre exemple autour de la suppression de fichiers de tests :
[code:1]
$path=\"C:\Temp\"
del \"$Path\File*.txt\" -Whatif
Break
del \"$Path\File*.txt\" -force
1..9|% {\"test\" > \"$Path\File$_.txt\"}
$AllFiles=dir \"$Path\File*.txt\"
#Positionne l'attribut en lecture seule
1,3,5|% {$F=$AllFiles[($_-1)];$F.Attributes = $F.Attributes -bor [System.IO.FileAttributes]::ReadOnly}
[REF]$Done=@()
filter Remove-File{
del $_ -verbose -ea SilentlyContinue
if ($?)
{ $_ }
}
$Error.Clear()
#Allfiles
dir \"$Path\File*.txt\"|
#supprime les fichiers créés, si l'action réussi on réémet l'objet
Invoke-RemainderObject -Done $Done -F Remove-File|
Foreach {Write-host \"Le fichier $_ a été supprimé\" -fore White}
\"Liste des fichiers restant $(Invoke-RemainderObject $AllFiles $Done -List)\"
$Done.Value
Write-Host \"Les objets en erreur\"
$Error
[/code:1]
Ni la récupération de la liste des objets traités ni celle des objets retenus par le filtre, ne sont implémentées, pas plus que la persistance des listes $Todo et $Done.
Les objets retenus par le filtre seront de nouveau traités lors de la prochaine itération, sous réserve que la liste $Done n'est pas effacée. Si c'est le cas l'ensemble des objets sera de nouveau traité.
Le cmdlet Export-CliXml peut être utilisé pour la persistance, attention toutefois a la validité des propriétés utilisées dans vos traitements.
Testé avec la v1 et v2 sous XP x32.<br><br>Message édité par: Laurent Dardenne, à: 6/06/10 16:17
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
Réduire
Plus d'informations
- Messages : 6311
- Remerciements reçus 68
il y a 15 ans 9 mois #7076
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet Re:[Function]Gestion d'un "reste à faire"
Correction de la fonction et ajout d'un paramètre Property.
Un test autour des jobs, bien que Get-Job -State xxx soit suffisant pour retrouver les jobs en cours (reste) et ceux terminé (fait) :
[code:1]
#A exécuter en une seule fois dans la console,
# copier/coller
$Jobs=@()
1..5|% {$Jobs+=Start-job -name \"Job$_\" {sleep 35}}
6..10|% {$Jobs+=Start-job -name \"Job$_\" {sleep 6}}
[REF]$Completed=@()
$Jobs|Invoke-RemainderObject -D $Completed -List
Filter Test-JobCompleted {
if ($_.State -eq \"Completed\"«»)
{$_}
}
$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$Completed.Value
Sleep 15
$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$completed.value
\"---\"
$JobsRestant=Invoke-RemainderObject $Jobs $Completed -Property Name -List
$JobsRestant
Sleep 30
$null=$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$Completed.Value
$JobsRestant=Invoke-RemainderObject $Jobs $Completed -Property Name -List
$JobsRestant
#Terminé, tout est fait.
[/code:1]<br><br>Message édité par: Laurent Dardenne, à: 19/07/10 18:49
Un test autour des jobs, bien que Get-Job -State xxx soit suffisant pour retrouver les jobs en cours (reste) et ceux terminé (fait) :
[code:1]
#A exécuter en une seule fois dans la console,
# copier/coller
$Jobs=@()
1..5|% {$Jobs+=Start-job -name \"Job$_\" {sleep 35}}
6..10|% {$Jobs+=Start-job -name \"Job$_\" {sleep 6}}
[REF]$Completed=@()
$Jobs|Invoke-RemainderObject -D $Completed -List
Filter Test-JobCompleted {
if ($_.State -eq \"Completed\"«»)
{$_}
}
$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$Completed.Value
Sleep 15
$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$completed.value
\"---\"
$JobsRestant=Invoke-RemainderObject $Jobs $Completed -Property Name -List
$JobsRestant
Sleep 30
$null=$Jobs|Invoke-RemainderObject -D $Completed -F Test-JobCompleted -Property Name
$Completed.Value
$JobsRestant=Invoke-RemainderObject $Jobs $Completed -Property Name -List
$JobsRestant
#Terminé, tout est fait.
[/code:1]<br><br>Message édité par: Laurent Dardenne, à: 19/07/10 18:49
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
Temps de génération de la page : 0.043 secondes
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Contributions à la communauté
- [Function]Gestion d'un "reste à faire"