J'ai un script qui exécute les commandes suivantes:
$args = @" & -quit -batchmode -logFile "$logfile" -buildWindows64Player "$($fullpath)\Project.exe" "@
Je veux mesurer combien de temps cela prend. Basé sur cet article , j'essaye ce qui suit:
Start-Process : Cannot validate argument on parameter 'ArgumentList'. The argument is null, empty, or an element of the argument collection contains a null value. Supply a collection that does not contain any null values and then try the command again. At C:\!scripts\pullandbuild.ps1:78 char:90 + ... d -expression { $result = Start-Process -Wait -PassThru $proc $args } + ~~~~~ + CategoryInfo : InvalidData: (:) [Start-Process], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartProcessCommand
Malheureusement, cela génère l'erreur suivante:
$buildtime = measure-command -expression { $result = Start-Process -Wait -PassThru $proc $args }
En raison d'autres problèmes que j'ai rencontrés avec les chaînes et l'expansion des variables, $ args
est défini comme ceci:
$result = Start-Process -Wait -PassThru $proc $args
Comment peut Je répare ça? Ou existe-t-il un autre moyen de capturer le runtime du script? J'essaie d'apprendre PS donc je préfère éviter de simplement capturer le temps avant de l'exécuter et après avoir exécuté et comparé, mais si c'est ma seule option, je le ferai.
3 Réponses :
Edit: Je viens de vérifier, votre variable $ args est vide, il s'avère que $ args est une variable intégrée. Une fois que j'ai changé le nom de la variable, il n'est plus nul, essayez ça.
Et si vous essayez l'une de ces approches:
1.
$startTime = Get-Date $processToRun = Start-Process notepad.exe -PassThru -Wait $finishTime = Get-Date $timeDifference = New-TimeSpan -Start $startTime -End $finishTime
Autres approches: l'utilisation de Get-Date
est pratique, surtout si vous voulez voir la sortie de la commande, mais notez qu'il est préférable d'utiliser (Get-Date) .ToUniversalTime () code > ou, dans PSv5 +,
[datetime] :: UtcNow
. Measure-Command
utilise une synchronisation plus précise, bien que cela importera probablement rarement dans la pratique. Notez que vous pouvez soustraire directement 2 instances [datetime]
pour obtenir une instance [timespan]
( $ finishTime - $ startTime
) - pas besoin de New-TimeSpan
. Une mise en garde concernant System.Diagnostics.Process.StartTime
: il ne fonctionne pas sur les plates-formes de type Unix dans PowerShell Core et renvoie $ null
.
Pour mettre des guillemets:
"Start-Process -Wait -PassThru $ proc $ args"
devrait être:
$ buildtime = mesure-commande -expression {$ results = "Start-Process -Wait -PassThru $ proc $ args"}
et
'@ & -quit -batchmode "-logFile $ logfile" -buildWindows64Player "$ ($ fullpath) \ Project.exe" @'
Veuillez formater correctement votre code et votre exemple d'entrée / sortie .
Ce que vous proposez est une chaîne extensible , pas une commande à exécuter.
la réponse de stivix contient le pointeur crucial - $ args
est un variable automatique à ne pas utiliser en tant que variable personnalisée - mais cela vaut la peine d'approfondir:
$ args
est automatiquement défini sur le tableau ( [object []]
) d'arguments de position passés à un script simple [bloc] ou fonction [1] , à l'intérieur de cette unité de code; si aucun argument n'est passé, $ args
contient un tableau vide.
Puisque vous ne pouvez pas passer d'arguments destinés à être vus par un bloc de script passé à Measure-Command Le paramètre
-Expression
de code>, $ args
est par définition le tableau vide à l'intérieur de ce bloc de script, ce qui a provoqué l'échec de Start-Process
.
En passant: ce Start-Process
échoue avec un tableau vide - au lieu de l'interpréter comme "aucun argument à passer" - est un problème dans Windows PowerShell qui a depuis été corrigé dans PowerShell Core.
Ce PowerShell vous permet d'attribuer un la valeur de $ args
est problématique.
Malheureusement, cela fait partie d'un problème plus vaste consistant à ne pas empêcher l'utilisation personnalisée des variables automatiques - voir ce problème GitHub .
L'aspect insidieux de ce comportement est que le problème n'apparaît que lorsque vous entrez un script [bloc] ou une fonction; dans la portée de l'appelant , la valeur personnalisée affectée à $ args
prend effet, comme le montre l'exemple suivant:
after assignment: [hi] in script block: []; element count: 0
Ce qui précède donne:
$args = 'hi' # !! To be avoided. Assign a custom value to $args # Echo the custom value, in the same scope. "after assignment: [$args]" # Call a script block and echo $args there. & { "in script block: [$args]; element count: $($args.Count)" }
La première ligne de sortie montre que l'affectation dans la portée de l'appelant a fonctionné comme prévu.
La deuxième ligne de sortie montre que $ args
a été automatiquement défini sur un tableau vide lors de l'entrée dans le bloc de script, car aucun argument n'a été passé au bloc de script ( {.. .}
).
Note: Techniquement, une variable locale $ args
est créée à l'intérieur du bloc de script, et la copie de l'appelant est toujours accessible si vous accédez explicitement à la portée de l'appelant (par exemple via (Get-Variable args -Scope 1 -ValueOnly)
), mais l'approche la plus judicieuse est d'éviter l'utilisation personnalisée de $ args code> complètement.
[1] $ args
contient uniquement les arguments qui ne sont pas liés aux paramètres explicitement déclarés , si seulement. Dans le script avancé ou des fonctions , vous ne pouvez jamais passer d'arguments qu'à des paramètres explicitement définis, donc $ args
n'est pas défini ici, car son utilisation serait inutile; en fait, dans un script / fonction avancé, $ args
conserve la définition personnalisée $ args
d'un appelant si elle est exécutée dans le même domaine de portée, mais il ne faut pas s'y fier.
N'écrivez pas manuellement dans
$ args
, c'est un variable automatique