Subscaper
Subscaper

Reputation: 252

Execute a Powershell Script with parameters in C#

Im stuck on this project, Im trying to create a user with a Powershell script, but i want to run the script from my Windowsform.

Script looks like this :

[CmdletBinding()]
 param (
[string] $Password
)  
[SecureString] $securePassword = ConvertTo-SecureString $Password -AsPlainText -Force

CreateUser $Username $Fullname $securePassword $Groups

function CreateUser { 
Param([string] $Username, [string] $Fullname, [SecureString] $Password, [string[]] $Groups)

Process{   
New-localuser -name $Username -FullName $Fullname -password $Password | Out-Null

    Write-Host "User" $_.username "created!"
    
    AddUserToGroup($Username, $Groups)
}
}

function AddUserToGroup([string] $Username, [string[]] $Groups){
Write-Output "Hello World";
}

I know that code works cause when I run it in the Powershell then it works.

I need to Add 4 parameters in th C# code, so Username, fullname, password and groups[array], cause the method in the script needs those.

When i try to run the script from my C# code then i get the Error :

The term "" 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.

My C# looks like this

        RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
        runspace.Open();

        RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
        string _pathToPSFile = File.ReadAllText(@"C:\Code\PathToScript\CreateUser.ps1");
        Pipeline pipeline = runspace.CreatePipeline();
        Command scriptCommand = new Command(_pathToPSFile);
        List<CommandParameter> commandParameters = new List<CommandParameter>();
        foreach (string scriptParameter in scriptParameters)
        {
            CommandParameter commandParm = new CommandParameter(null, scriptParameter);
            commandParameters.Add(commandParm);
            scriptCommand.Parameters.Add(commandParm);
        }
        pipeline.Commands.Add(scriptCommand);
        Collection<PSObject> psObjects;
        psObjects = pipeline.Invoke();

I dont know what happens when i run the script with c# and add the parameteres, do i have to call the function in the C# code, or does it execute automatically ? I'm a beginner in Powershell Code

Really need help here :)

If you need more information, or when something isn't clear, please let me know :)

EDIT #1 C# Code looks like this now, had to Add the Runspace Invoke, cause of ExecutionPolicy Problems

        RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
        runspace.Open();

        RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
        scriptInvoker.Invoke("$ExecutionPolicy = Get-ExecutionPolicy -Scope CurrentUser");
        scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted -Scope CurrentUser ");

        PowerShell ps = PowerShell.Create();
        ps.Runspace = runspace;
        ps.AddCommand(@"C:\Code\Internal\as1UserManager\as1UserManager\PSScripts\CreateUser.ps1");

        foreach (string scriptParameter in scriptParameters)
        {
            ps.AddArgument(scriptParameter);
        }

        Collection<PSObject> psObjects = ps.Invoke();
        scriptInvoker.Invoke("Set-ExecutionPolicy -Scope CurrentUser $ExecutionPolicy -Force");

EDIT #2 I had to Add the params in the CmdletBinding(), as suggested. And of course its not running, called the funcion CreateUser, before it even exists. Now everything is fine. Code looks like that now

[CmdletBinding()]
param (  
[string] $Username = "Leon",
[string] $Fullname = "Kennedy",
[string] $Password = "sml12345",
[string] $Groups = "something"
) 
[SecureString] $securePassword = ConvertTo-SecureString $Password              -AsPlainText -Force


function CreateUser {
Param([string] $Username, [string] $Fullname, [SecureString]    securePassword, [string] $Groups)

Process{   
New-localuser -name $Username -FullName $Fullname -password  $securePassword | Out-Null

    Write-Host "User" $Username "created!"
    
    AddUserToGroup($Username, $Groups)
   }
}

CreateUser $Username $Fullname $securePassword $Groups

function AddUserToGroup([string] $Username, [string] $Groups){
Write-Output "Hello World";
}

Upvotes: 5

Views: 11523

Answers (2)

mklement0
mklement0

Reputation: 440471

As an aside: There's a problem with your script: function CreateUser is called before it is defined, which fails.

A Command object, when created with its single-argument constructor, refers to a command name or file path, not to a script file's content, which is what you're attempting to via File.ReadAllText().[1] Note that, similarly, the related .AddCommand() method, directly available on a PowerShell instance, expects only a name or file path, whereas it is the distinct .AddScript() method that expects source-code text.[2]

Therefore, try the following instead:

Command scriptCommand = new Command(@"C:\Code\PathToScript\CreateUser.ps1");

Note:


[1] It is possible to construct a Command instance with script text, i.e., a piece of source code, namely if you pass true to the 2nd parameter (somewhat confusingly named isScript); e.g., new Command("'hi'", true). However, doing so via first explicitly reading the script file into memory is not only unnecessary in your case, it also changes certain aspects of the code's behavior, notably with respect to what the automatic $PSScriptRoot and $PSCommandPath variables report.

[2] Note that if you happen to pass a script-file path that doesn't contains spaces to .AddScript(), invocation will also succeed, but the script won't receive arguments, because the code is in effect evaluated as
. { C:\Code\PathToScript\CreateUser.ps1 } ... (... represents the arguments) - see this answer for more information.

Upvotes: 3

Mathias R. Jessen
Mathias R. Jessen

Reputation: 175085

Create an instance of the PowerShell class instead, it'll allow you to add un-named arguments:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();

PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddCommand(@"C:\Code\PathToScript\CreateUser.ps1");

foreach (string scriptParameter in scriptParameters)
{
    ps.AddArgument(scriptParameter);
}

Collection<PSObject> psObjects;
psObjects = pipeline.Invoke();

Upvotes: 6

Related Questions