Comment exécutez-vous la commande suivante dans PowerShell?
Déploiement Web C:\Program Files\IIS\Microsoft\msdeploy.exe -verb: sync -source: dbfullsql = "Source de données = mysource; Integrated Security = false; ID utilisateur = sa; Pwd = sapass!; Database = mydb;" -dest: dbfullsql = "Source de données =.\mydestsource; Sécurité intégrée = false; ID utilisateur = sa; Pwd = sapass!; Database = mydb;", nom_ordinateur = 10.10.10.10, nom d'utilisateur = administrateur, mot de passe = adminpass "
Lorsque PowerShell voit une commande commençant par une chaîne, il évalue simplement la chaîne. En d'autres termes, il la renvoie à l'écran, par exemple:
PS> "Hello World"
Hello World
Si vous souhaitez que PowerShell interprète la chaîne en tant que nom de commande, utilisez l'opérateur call (&) comme suit:
PS> & 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe'
Après cela, vous ne devez probablement citer que des paires paramètre/argument contenant des espaces et/ou des caractères de citation. Lorsque vous appelez un fichier EXE de ce type avec des arguments de ligne de commande complexes, il est généralement très utile de disposer d'un outil qui vous montrera comment PowerShell envoie les arguments au fichier EXE. Les PowerShell Community Extensions ont un tel outil. C'est ce qu'on appelle echoargs. Vous venez de remplacer le fichier EXE par echoargs - en laissant tous les arguments en place, et il vous montrera comment le fichier EXE recevra les arguments, par exemple:
PS> echoargs -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass
Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data>
Arg 2 is <Source=mysource;Integrated>
Arg 3 is <Security=false;User>
Arg 4 is <ID=sa;Pwd=sapass!;Database=mydb;>
Arg 5 is <-dest:dbfullsql=Data>
Arg 6 is <Source=.\mydestsource;Integrated>
Arg 7 is <Security=false;User>
Arg 8 is <ID=sa;Pwd=sapass!;Database=mydb; computername=10.10.10.10 username=administrator password=adminpass>
En utilisant echoargs, vous pouvez expérimenter jusqu’à ce que vous obteniez le résultat souhaité, par exemple:
PS> echoargs -verb:sync "-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;"
Arg 0 is <-verb:sync>
Arg 1 is <-source:dbfullsql=Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;>
Il s'est avéré que j'essayais trop de conserver les guillemets autour de la chaîne de connexion. Apparemment, cela n'est pas nécessaire car même cmd.exe les supprimera.
BTW, chapeau à l'équipe PowerShell. Ils m'ont tout à fait aidé à me montrer l'incantation spécifique des guillemets simples et doubles pour obtenir le résultat souhaité - si vous deviez conserver les guillemets internes à la place. :-) Ils réalisent également que c'est un domaine de douleur, mais ils sont motivés par le nombre de personnes touchées par un problème particulier. S'il s'agit d'un domaine de douleur pour vous, alors votez pour ceci Soumission de bugs PowerShell .
Pour plus d'informations sur l'analyse de PowerShell, consultez mon Série de blogs PowerShell efficaces - en particulier élément 10 - "Présentation des modes d'analyse de PowerShell"
MISE À JOUR 4/04/2012: Cette situation est beaucoup plus facile à gérer dans PowerShell V3. Voir ce article de blog pour plus de détails .
Il suffit d’ajouter l’opérateur & avant le nom de fichier .exe. Voici une commande pour installer SQL Server Express en mode silence:
$fileExe = "T:\SQLEXPRADV_x64_ENU.exe"
$CONFIGURATIONFILE = "T:\ConfSetupSql2008Express.ini"
& $fileExe /CONFIGURATIONFILE=$CONFIGURATIONFILE
J'avais des espaces dans les commandes et les paramètres, et voici ce qui a fonctionné pour moi:
$Command = "E:\X64\Xendesktop Setup\XenDesktopServerSetup.exe"
$Parms = "/COMPONENTS CONTROLLER,DESKTOPSTUDIO,DESKTOPDIRECTOR,LICENSESERVER,STOREFRONT /PASSIVE /NOREBOOT /CONFIGURE_FIREWALL /NOSQL"
$Prms = $Parms.Split(" ")
& "$Command" $Prms
C'est fondamentalement la même chose que la réponse d'Akira, mais cela fonctionne si vous construisez dynamiquement vos paramètres de commande et les mettez dans une variable.
Cela a fonctionné pour moi:
& 'D:\Server\PSTools\PsExec.exe' @('\\1.1.1.1', '-accepteula', '-d', '-i', $id, '-h', '-u', 'domain\user', '-p', 'password', '-w', 'C:\path\to\the\app', 'Java', '-jar', 'app.jar')
Il suffit de placer des chemins ou des chaînes de connexion dans un élément de tableau et de diviser les autres éléments en un élément de tableau chacun.
Il y a beaucoup d'autres options ici: https://social.technet.Microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx
Microsoft devrait simplifier cette procédure et la rendre compatible avec la syntaxe d'invite de commande.
Voir cette page: https://slai.github.io/posts/powershell-and-external-commands-done-right/
Résumé utilisant vshadow comme exécutable externe:
$exe = "H:\backup\scripts\vshadow.exe"
&$exe -p -script=H:\backup\scripts\vss.cmd E: M: P:
Au cas où quelqu'un se demanderait comment exécuter un fichier exécutable:
.....>.\file.exe
ou
......> full\path\to\file.exe
J'ai pu faire fonctionner ma commande similaire en utilisant l'approche suivante:
msdeploy.exe -verb=sync "-source=dbFullSql=Server=THESERVER;Database=myDB;UID=sa;Pwd=saPwd" -dest=dbFullSql=c:\temp\test.sql
Pour votre commande (pas que cela aide beaucoup maintenant), les choses ressembleraient à ceci:
msdeploy.exe -verb=sync "-source=dbfullsql=Server=mysource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;" "-dest=dbfullsql=Server=mydestsource;Trusted_Connection=false;UID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass
Les points clés sont:
Je n'ai pas essayé d'ajouter la partie "nom_ordinateur" à la fin de la ligne de commande, mais j'espère que cette information aidera les autres lecteurs à se familiariser avec le résultat souhaité.
Nouvelle chaîne d'échappement dans PowerShell V3, citée dans Nouvelles fonctionnalités du langage V3:
Réutilisation plus facile des lignes de commande à partir de Cmd.exe
Le Web est plein de lignes de commande écrites pour Cmd.exe. Ces lignes de commandes fonctionnent assez souvent dans PowerShell, mais lorsqu'elles incluent certains caractères, par exemple un point-virgule (;), un signe dollar ($) ou une accolade, vous devez apporter des modifications, probablement en ajoutant des guillemets. Cela semblait être la source de nombreux maux de tête mineurs.
Pour aider à résoudre ce scénario, nous avons ajouté une nouvelle méthode pour «échapper» à l'analyse syntaxique des lignes de commande. Si vous utilisez un paramètre magique -%, nous arrêtons l'analyse normale de votre ligne de commande et passons à quelque chose de beaucoup plus simple. Nous ne correspondons pas aux citations. Nous ne nous arrêtons pas au point-virgule. Nous ne développons pas les variables PowerShell. Nous développons les variables d’environnement si vous utilisez la syntaxe Cmd.exe (par exemple,% TEMP%). Autre que cela, les arguments jusqu'à la fin de la ligne (ou pipe, si vous êtes en cours de tuyauterie) sont passés tels quels. Voici un exemple:
PS> echoargs.exe --% %USERNAME%,this=$something{weird}
Arg 0 is <jason,this=$something{weird}>
Il existe plusieurs méthodes que vous pouvez utiliser pour le faire.
Il existe d'autres méthodes telles que l'utilisation de l'applet de commande Call Operator (&), Invoke-Expression, etc., mais elles sont considérées comme dangereuses. Microsoft recommande d'utiliser Start-Process.
Méthode 1
Un exemple simple
Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root","-proot","-h localhost"
Dans ton cas
Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync","-source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","-dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`"","computername=10.10.10.10","username=administrator","password=adminpass"
Dans cette méthode, vous séparez chaque paramètre de ArgumentList en utilisant des virgules.
Méthode 2
Exemple simple
Start-Process -NoNewWindow -FilePath "C:\wamp64\bin\mysql\mysql5.7.19\bin\mysql" -ArgumentList "-u root -proot -h localhost"
Dans ton cas
Start-Process -NoNewWindow -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync -source:dbfullsql=`"Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`" -dest:dbfullsql=`"Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;`",computername=10.10.10.10,username=administrator,password=adminpass"
Cette méthode est plus simple car elle permet de saisir vos paramètres en une fois.
Notez que, dans powershell, pour représenter le guillemet (") dans une chaîne, vous devez insérer l'accent Grave (`) (c'est la touche située au-dessus de la touche de tabulation du clavier américain).
-NoNewWindow Le paramètre est utilisé pour afficher le nouveau processus dans la fenêtre de la console actuelle. Par défaut, Windows PowerShell ouvre une nouvelle fenêtre.
Références: Powershell/Scripting/Start-Process
J'ai essayé toutes les suggestions mais je ne pouvais toujours pas exécuter msiexec.exe
avec des paramètres contenant des espaces. Donc ma solution a fini par utiliser System.Diagnostics.ProcessStartInfo
:
# can have spaces here, no problems
$settings = @{
CONNECTION_STRING = "... ..."
ENTITY_CONTEXT = "... ..."
URL = "..."
}
$settingsJoined = ($settings.Keys | % { "$_=""$($settings[$_])""" }) -join " "
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.WorkingDirectory = $ScriptDirectory
$pinfo.FileName = "msiexec.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "/l* install.log /i installer.msi $settingsJoined"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
Une autre solution consiste à utiliser un commutateur de commande Base64 encoded:
powershell -EncodedCommand "QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA=="
Une fois décodé, vous verrez que c'est l'extrait de code original de l'OP, avec tous les arguments et guillemets préservés.
powershell.exe -EncodedCommand
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
La commande d'origine:
C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"
Il se transforme en ceci une fois encodé en Base64:
QwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEkASQBTAFwATQBpAGMAcgBvAHMAbwBmAHQAIABXAGUAYgAgAEQAZQBwAGwAbwB5AFwAbQBzAGQAZQBwAGwAbwB5AC4AZQB4AGUAIAAtAHYAZQByAGIAOgBzAHkAbgBjACAALQBzAG8AdQByAGMAZQA6AGQAYgBmAHUAbABsAHMAcQBsAD0AIgBEAGEAdABhACAAUwBvAHUAcgBjAGUAPQBtAHkAcwBvAHUAcgBjAGUAOwBJAG4AdABlAGcAcgBhAHQAZQBkACAAUwBlAGMAdQByAGkAdAB5AD0AZgBhAGwAcwBlADsAVQBzAGUAcgAgAEkARAA9AHMAYQA7AFAAdwBkAD0AcwBhAHAAYQBzAHMAIQA7AEQAYQB0AGEAYgBhAHMAZQA9AG0AeQBkAGIAOwAiACAALQBkAGUAcwB0ADoAZABiAGYAdQBsAGwAcwBxAGwAPQAiAEQAYQB0AGEAIABTAG8AdQByAGMAZQA9AC4AXABtAHkAZABlAHMAdABzAG8AdQByAGMAZQA7AEkAbgB0AGUAZwByAGEAdABlAGQAIABTAGUAYwB1AHIAaQB0AHkAPQBmAGEAbABzAGUAOwBVAHMAZQByACAASQBEAD0AcwBhADsAUAB3AGQAPQBzAGEAcABhAHMAcwAhADsARABhAHQAYQBiAGEAcwBlAD0AbQB5AGQAYgA7ACIALABjAG8AbQBwAHUAdABlAHIAbgBhAG0AZQA9ADEAMAAuADEAMAAuADEAMAAuADEAMAAsAHUAcwBlAHIAbgBhAG0AZQA9AGEAZABtAGkAbgBpAHMAdAByAGEAdABvAHIALABwAGEAcwBzAHcAbwByAGQAPQBhAGQAbQBpAG4AcABhAHMAcwAiAA==
et voici comment reproduire à la maison:
$command = 'C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe -verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
$encodedCommand
# The clip below copies the base64 string to your clipboard for right click and paste.
$encodedCommand | Clip
Cela a fonctionné pour moi:
PowerShell.exe -Command "& ""C:\Some Script\Path With Spaces.ps1"""
La clé semble être que toute la commande est entourée de guillemets extérieurs, le signe "&" est utilisé pour indiquer qu'un autre fichier de commande enfant est en cours d'exécution, puis des guillemets échappés (double doublé) autour du chemin/nom du fichier avec des espaces en vous vouliez exécuter en premier lieu.
Ceci est également l'achèvement de la seule solution de contournement au problème de connexion MS selon laquelle -File ne renvoie pas les codes de retour non nuls et -Command est la seule alternative. Mais jusqu'à présent, on pensait que l'une des limites de -Command était qu'elle ne supportait pas les espaces. J'ai également mis à jour cet élément de feedback.
Vous pouvez exécuter des fichiers exe de manière différente en PowerShell. Par exemple, si vous voulez exécuter unrar.exe et extraire un fichier .rar, vous pouvez simplement écrire dans powershell ceci:
$extract_path = "C:\Program Files\Containing folder";
$rar_to_extract = "C:\Path_to_Arch\file.rar"; #(or.exe if its a big file)
C:\Path_here\Unrar.exe x -o+ -c- $rar_to_extract $extract_path;
Mais parfois, cela ne fonctionne pas et vous devez donc utiliser le paramètre & comme indiqué ci-dessus: Par exemple, avec vboxmanage.exe (un outil permettant de gérer les machines virtuelles de la boîte virtuelle), vous devez appeler les paramètres en dehors de la chaîne, comme ceci: sans citations:
> $vmname = "misae_unrtes_1234123"; #(name too long, we want to change this)
> & 'C:\Program Files\Oracle\VirtualBox\VBoxManage.exe' modifyvm $vmname --name UBUNTU;
Si vous souhaitez appeler simplement un fichier archivé de winrar en tant que fichier .exe, vous pouvez également le décompresser à l'aide de la cmdlet invoke-command et d'un paramètre Silent/S (le fichier va s'exporter dans le même dossier que celui où il a été compressé).
> Invoke-Command -ScriptBlock { C:\Your-path\archivefile.exe /S };
Il existe donc plusieurs façons d’exécuter des fichiers .exe avec des arguments dans powershell.
Parfois, il faut trouver une solution de contournement pour le faire fonctionner correctement, ce qui peut nécessiter des efforts supplémentaires et des peines :), en fonction de la manière dont le fichier .exe a été compilé ou créé par ses créateurs.
Le code suivant fonctionnait parfaitement sur mon ordinateur portable:
& $msdeploy `
-source:package="$publishFile" `
-dest:auto,computerName="$server",includeAcls="False",UserName="$username",Password="$password",AuthType="$auth" `
-allowUntrusted `
-verb:sync `
-enableRule:DoNotDeleteRule `
-disableLink:AppPoolExtension `
-disableLink:ContentExtension `
-disableLink:CertificateExtension `
-skip:objectName=filePath,absolutePath="^(.*Web\.config|.*Environment\.config)$" `
-setParam:name=`"IIS Web Application Name`",value="$appName"
Puis, quand j'ai essayé de l'exécuter directement sur un serveur, j'ai commencé à avoir ces erreurs "Unrecognized argument ...etc.... All arguments must begin with "-". "
Après avoir essayé toutes les solutions de contournement possibles (sans succès), j'ai découvert que Powershell sur le serveur (Windows 2008 R2) était la version 3.0, alors que mon ordinateur portable en avait la 5.0. (vous pouvez utiliser "$ PSVersionTable" pour voir la version).
Après la mise à niveau de Powershell vers la dernière version, il a recommencé à fonctionner.
Alors, j'ai rencontré un problème similaire et j'ai choisi de le résoudre de cette façon:
invoke-expression
sur la nouvelle chaîne.Exemple de solution:
& {invoke-expression "C:\Program Files\IIS\Déploiement Web de Microsoft\msdeploy.exe -verb: sync-source: dbfullsql =` "source de données = mysource; sécurité intégrée/false = ID utilisateur = sa; Pwd = sapass !; Database = mydb; `" -dest: dbfullsql = `" Source de données =.\Mydestsource; Sécurité intégrée = false; ID utilisateur = sa; Pwd = sapass!; Database = mydb; `", nomordinateur = 10.10.10.10 nom d'utilisateur = administrateur, mot de passe = adminpass` ""}
Pour le nom de l'exécutable, la cmdlet new-alias peut être utilisée pour éviter de gérer les espaces ou de devoir ajouter l'exécutable à l'environnement $ PATH.
PS> new-alias msdeploy "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe"
PS> msdeploy ...
Pour lister ou modifier les alias PS, voir aussi
PS> get-alias
PS> set-alias
D'autres réponses abordent les arguments.
Vous pouvez utiliser:
Start-Process -FilePath "C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe" -ArgumentList "-verb:sync -source:dbfullsql="Data Source=mysource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;" -dest:dbfullsql="Data Source=.\mydestsource;Integrated Security=false;User ID=sa;Pwd=sapass!;Database=mydb;",computername=10.10.10.10,username=administrator,password=adminpass"
Le point clé à noter ici est que FilePath doit être à la position 0, selon le Guide d’aide. Pour appeler le guide d’aide d’un commandlet, il suffit de taper Get-Help <Commandlet-name> -Detailed
. Dans ce cas, il s'agit de Get-Help Start-Process -Detailed
.
J'utilise cette méthode simple, propre et efficace.
Je place des arguments dans un tableau, 1 par ligne. De cette façon, il est très facile à lire et à éditer. Ensuite, j'utilise une astuce simple consistant à transmettre tous les arguments entre guillemets doubles à une fonction comportant un seul paramètre. Cela les aplatit, y compris les tableaux, en une seule chaîne, que j'exécute ensuite à l'aide de 'Invoke-Expression' de PS. Cette directive est spécifiquement conçue pour convertir une chaîne en commande exécutable. Fonctionne bien:
# function with one argument will flatten
# all passed-in entries into 1 single string line
Function Execute($command) {
# execute:
Invoke-Expression $command;
# if you have trouble try:
# Invoke-Expression "& $command";
# or if you need also output to a variable
# Invoke-Expression $command | Tee-Object -Variable cmdOutput;
}
# ... your main code here ...
# The name of your executable app
$app = 'my_app.exe';
# List of arguments:
# Notice the type of quotes - important !
# Those in single quotes are normal strings, like 'Peter'
$args = 'arg1',
'arg2',
$some_variable,
'arg4',
"arg5='with quotes'",
'arg6',
"arg7 \ with \ $other_variable",
'etc...';
# pass all arguments inside double quotes
Execute "$app $args";