开发者

Trying to execute PowerShell 2.0 script from a .NET installer's custom action

开发者 https://www.devze.com 2023-01-23 22:02 出处:网络
I\'ve been working on this issue for a couple days and have read several posts here, but I can\'t get my implementation to work. I am calling the powershell script during the Commit custom action. Whe

I've been working on this issue for a couple days and have read several posts here, but I can't get my implementation to work. I am calling the powershell script during the Commit custom action. When I get to the pipeline.Invoke() method, I get an exception that says the entire script "is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again."

Here is my script:

Param(
    [parameter(Mandatory=$true,ValueFromPipeline=$true)]
    [string]$installPath
    );

schtasks /create /TN MyTask /RU domain\account /RP password /xml $installPath\MyTaskSchedule.xml;

I've tried it with and without the traili开发者_开发问答ng semi-colons, with and without a wrapping function. I've verified that the C# code is passing the correct install path and that the xml file exists in the directory before this step is hit. I can run this from PowerShell itself and it works just fine.

Here is my code:

public override void Commit( System.Collections.IDictionary savedState )
{
    base.Commit( savedState );

    String targetDirectory = this.Context.Parameters["TDir"].ToString();
    String script = System.IO.File.ReadAllText( targetDirectory + "TaskScheduler.ps1" );

    RunspaceConfiguration c = RunspaceConfiguration.Create();

    using ( Runspace runspace = RunspaceFactory.CreateRunspace() )
    {
        runspace.Open();
        using ( Pipeline pipeline = runspace.CreatePipeline() )
        {
            Command myCommand = new Command( script );
            CommandParameter param = new CommandParameter( "installPath", targetDirectory.Replace("\\\\", "\\") );

            myCommand.Parameters.Add( param );
            pipeline.Commands.Add( myCommand );

            try
            {
                 pipeline.Invoke();
            }
            catch ( Exception e )
            {
                 MessageBox.Show( e.Message );
            }
        }
    }
}

When the exception is caught at pipeline.Invoke, the entire script is displayed (with the $installPath instead of the actual path) as a string before the error message detailed above. I've tried several checks within the script itself, but I get the same results no matter what, which tells me that the runspace just doesn't like the script itself.


You should pass true as the second parameter in the constructor: new Command(script, true). It tells that the command is a script code, not a command name.

Here is a working PowerShell analogue of your code:

# This script calls the external command (cmd) with passed in parameter
$script = @'
param
(
    [parameter(Mandatory=$true,ValueFromPipeline=$true)]
    [string]$installPath
)

cmd /c echo $installPath
'@

# Note: the second parameter $true tells that the command is a script code, not just a command name
$command = New-Object Management.Automation.Runspaces.Command $script, $true
$param = New-Object Management.Automation.Runspaces.CommandParameter "installPath", "C:\UTIL\INSTALL"
$command.Parameters.Add($param)

$rs = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$rs.Open()
$pipeline = $rs.CreatePipeline()
$pipeline.Commands.Add($command)
$pipeline.Invoke()

It prints (in the console host):

C:\UTIL\INSTALL
0

精彩评论

暂无评论...
验证码 换一张
取 消