I want to execute a powershell script via winforms and get well-formatted output. I managed to get it to work but now I need to pass parameters to my script. I can't manage to make that happen.
Here is my RunScript function :
private string RunScript(string scriptFile)
{
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
Pipeline pipeLine = runSpace.CreatePipeline();
Command script = new Command(scriptFile);
script.Parameters.Add("COM_USERNAME", usernameBox.Text);
script.Parameters.Add("COM_PASSWORD", passwordBox.Text);
script.Parameters.Add("installDir", installDirBox.Text);
script.Parameters.Add("TEMPVAULT_PATH", tempVaultBox.Text);
script.Parameters.Add("MAX_REQ_LIMIT", maxReqLimBox.Text);
script.Parameters.Add("MAX_BUFF_LIMIT", maxBuffLimBox.Text);
pipeLine.Commands.AddScript(script.ToString());
pipeLine.Commands.Add("Out-String");
Collection<PSObject> results = pipeLine.Invoke();
runSpace.Close();
StringBuilder strBuilder = new StringBuilder();
foreach (PSObject item in results)
{
strBuilder.AppendLine(item.ToString());
}
return strBuilder.ToString();
}
And this is the script that I am trying with:
param (
[bool] $STARTSERVICE = $false ,
[bool] $INSTALL = $false ,
[bool] $INSTALL_DASHBOARD = $false,
[bool] $DASHBOARD_SETTINGS = $false,
[bool] $DASHBOARD_CREATENEWDB = $false,
[bool] $DALIM_SETTINGS = $false,
[bool] $INSTALLIIS = $true,
[bool] $FIRST_INSTALL = $true,
[bool] $RECOVERY = $false,
[string] $COM_USERNAME,
[string] $COM_PASSWORD,
[string] $RECOVERY_ADM_NAME,
[string] $RECOVERY_ADM_PWD,
[string] $Windows2012DVDLetter = "F:",
[string] $COM_UNCPATH,
[string] $installDir = "C:\Program Files\App\",
[string] $TEMPVAULT_PATH = "C:\TempVault",
$SOAP_MaxPostSize = 4294967295,
$MAX_REQ_LIMIT = 500000000,
$MAX_BUFF_LIMIT = 500000000
)
Write-Output "`nUsername = " $COM_USERNAME
Write-Output "`nPassword = " $COM_PASSWORD
Write-Output "`nCOM_UNCPATH = " $COM_UNCPATH
Write-Output "`nMaximum Request Limit = " $MAX_REQ_LIMIT
Write-Output "`nMaximum Buff Limit = " $MAX_BUFF_LIMIT
Write-Output "`nIsFirstInstall = " $FIRST_INSTALL
Write-Output "`nInstallation Directory = " $installDir
Write-Output "`nTempVault Path = " $TEMPVAULT_PATH
Write-Output "`nRestriction level = " $RESTRICT_LVL
I have output with only the pre-registered in the script values showing, but the ones I'm trying to show (textboxes inputs) don't. Have I missed something?
Note: The following assumes that scriptFile
is the path of a *.ps1
file, not that file's content (a string containing Powershell code).
See the bottom section for how to handle the latter case.
You can greatly simplify your invocation :
private string RunScript(string scriptFile)
{
using (var ps = PowerShell.Create()) {
ps.AddCommand(scriptFile) // Be sure to pass a *full path*
.AddParameter("COM_USERNAME", usernameBox.Text)
.AddParameter("COM_PASSWORD", passwordBox.Text)
.AddParameter("installDir", installDirBox.Text)
.AddParameter("TEMPVAULT_PATH", tempVaultBox.Text)
.AddParameter("MAX_REQ_LIMIT", maxReqLimBox.Text)
.AddParameter("MAX_BUFF_LIMIT", maxBuffLimBox.Text)
.AddCommand('Out-String'); // Add a pipeline segment
// Return the 1st (and in this case only) output object, as a string.
return ps.Invoke<string>()[0];
}
}
Using PowerShell.Create()
creates an instance of class PowerShell
, which provides a higher-level API based on an implicitly created runspace:
.AddCommand()
repeatedly automatically adds new pipeline segments.As for what you tried :
pipeLine.Commands.AddScript(script.ToString());
The .AddScript()
method is for adding arbitrary pieces of PowerShell code , not for adding Command
instances with associated parameters.
( Command
instances represent either a PowerShell command such as Out-String
or the name / path of an external executable or the path [1] to a script file ( *.ps1
)).
By stringifying the Command
instance stored in script
with .ToString()
, you're effectively just passing the script path as the command to execute - all the parameters you've added with .AddParameter()
are lost, which is why you only saw the default parameter values in the script's output.
Instead, you should have added your Command
instance as follows :
pipeLine.Commands.Add(script)
If scriptFile
is not a file path , but the contents of a script file (a string containing PowerShell code):
As you've since clarified, this is your actual use case, because the script is embedded as a resource in your executable that you pass with RunScript(Properties.Resources.<the script>)
Adapt the simplified approach at the top as follows:
// If `scriptFile` is the *contents* of a *.ps1 file,
// add it as a script [block] with .AddScript(),
// then add parameters (and the additional pipeline command).
ps.AddScript(scriptFile)
.AddParameter("COM_USERNAME", usernameBox.Text)
.AddParameter("COM_PASSWORD", passwordBox.Text)
.AddParameter("installDir", installDirBox.Text)
.AddParameter("TEMPVAULT_PATH", tempVaultBox.Text)
.AddParameter("MAX_REQ_LIMIT", maxReqLimBox.Text)
.AddParameter("MAX_BUFF_LIMIT", maxBuffLimBox.Text)
.AddCommand('Out-String'); // Add a pipeline segment
[1] PowerShell only allows by-name-only executions (eg, foo.ps1
) for executables / scripts located in a directory listed in the PATH
environment variable. Otherwise, a file path must be specified, and it's safest to use a full path , because .NET's current directory usually differs from PowerShell's.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.