Comment exécuter une commande native arbitraire à partir d'une chaîne de caractères?
je peux exprimer mon besoin avec le scénario suivant: écrire une fonction qui accepte qu'une chaîne de caractères soit exécutée comme une commande native.
ce n'est pas une idée trop farfelue: si vous interfacez avec d'autres utilitaires en ligne de commande d'ailleurs dans la compagnie qui vous fournissent une commande pour exécuter mot à mot. Parce que vous ne contrôlez pas la commande, vous devez accepter n'importe quelle commande valide comme entrée . Ce sont les principaux hoquet que je n'ai pas pu surmonter facilement:
-
La commande peut exécuter un programme vivant dans un chemin avec un espace:
$command = '"C:Program FilesTheProgRunit.exe" Hello';
-
la commande peut comporter des paramètres avec des espaces:
$command = 'echo "hello world!"';
-
La commande peut avoir à la fois simple et double tiques:
$command = "echo `"it`'s`"";
est là tout propre façon de régler ce problème? Je n'ai pu concevoir que des solutions de rechange somptueuses et moches, mais pour un langage de script, je pense que ça devrait être très simple.
3 réponses
Invoke-Expression
, alias aussi iex
. Les exemples 2 et 3 seront les suivants:
iex $command
certaines chaînes ne fonctionneront pas en tant que telles, comme votre exemple #1 parce que l'exe est entre guillemets. Cela fonctionnera, car le contenu de la chaîne sont exactement comment vous pouvez l'exécuter directement à partir d'une invite de commande Powershell:
$command = 'C:\somepath\someexe.exe somearg'
iex $command
cependant, si l'exe est entre guillemets, vous avez besoin de l'aide de &
pour obtenir il s'exécute, comme dans cet exemple, à partir de la ligne de commande:
>> &"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"
et puis dans le script:
$command = '"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"'
iex "& $command"
probablement, vous pourriez traiter presque tous les cas en détectant si le premier caractère de la chaîne de commande est "
, comme dans cette implémentation naïve:
function myeval($command) {
if ($command[0] -eq '"') { iex "& $command" }
else { iex $command }
}
Mais vous pouvez trouver d'autres cas qui doivent être invoqué d'une manière différente. Dans ce cas, vous devez soit utiliser try{}catch{}
, peut-être pour des types d'exceptions/messages spécifiques, ou examiner la chaîne de commande.
si vous recevez toujours des chemins absolus au lieu des chemins relatifs, vous ne devriez pas avoir beaucoup de cas spéciaux, s'il y en a, en dehors des 2 ci-dessus.
S'il vous plaît voir aussi ce rapport de Microsoft Connect sur essentiellement, comment blummin' difficile il est d'utiliser PowerShell pour exécuter des commandes shell (oh, l'ironie).
http://connect.microsoft.com/PowerShell/feedback/details/376207 /
ils suggèrent d'utiliser --%
comme un moyen de forcer PowerShell à cesser d'essayer d'interpréter le texte à droite.
par exemple:
MSBuild /t:Publish --% /p:TargetDatabaseName="MyDatabase";TargetConnectionString="Data Source=.\;Integrated Security=True" /p:SqlPublishProfilePath="Deploy.publish.xml" Database.sqlproj
la réponse acceptée ne fonctionnait pas pour moi quand j'essayais d'analyser le Registre pour les chaînes de désinstallation, et de les exécuter. Il s'avère que je n'avais pas besoin de l'appel à Invoke-Expression
après tout.
j'ai finalement trouvé ce joli modèle pour voir comment exécuter des chaînes de désinstallation:
$path = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
$app = 'MyApp'
$apps= @{}
Get-ChildItem $path |
Where-Object -FilterScript {$_.getvalue('DisplayName') -like $app} |
ForEach-Object -process {$apps.Set_Item(
$_.getvalue('UninstallString'),
$_.getvalue('DisplayName'))
}
foreach ($uninstall_string in $apps.GetEnumerator()) {
$uninstall_app, $uninstall_arg = $uninstall_string.name.split(' ')
& $uninstall_app $uninstall_arg
}
cela fonctionne pour moi, à savoir parce que $app
est une application interne qui, je le sais, n'aura que deux arguments. Pour plus d' vous pouvez utiliser le join operator . Aussi, j'ai juste utilisé une carte de hachage, mais vraiment, vous voudriez probablement utiliser un tableau.
aussi, si vous avez plusieurs versions de la même application installée, ce désinstallateur va les parcourir toutes en même temps, ce qui confond MsiExec.exe
, donc il y a ça aussi.