Reputation: 252
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
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
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