Wykonaj skrypt programu PowerShell z C # za pomocą argumentów wiersza polecenia


101

Muszę wykonać skrypt PowerShell z poziomu C #. Skrypt potrzebuje argumentów wiersza poleceń.

Oto, co zrobiłem do tej pory:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

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

RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(scriptFile);

// Execute PowerShell script
results = pipeline.Invoke();

plik scriptFile zawiera coś takiego jak „C: \ Program Files \ MyProgram \ Cokolwiek.ps1”.

Skrypt używa argumentu wiersza poleceń, takiego jak „-key Wartość”, podczas gdy Wartość może być czymś w rodzaju ścieżki, która może również zawierać spacje.

Nie udaje mi się to. Czy ktoś wie, jak przekazać argumenty wiersza polecenia do skryptu PowerShell z poziomu C # i upewnić się, że spacje nie stanowią problemu?


1
Aby wyjaśnić przyszłym użytkownikom, zaakceptowana odpowiedź rozwiązuje problem dla osób mających problemy z przestrzenią nawet bez parametrów użytkowania. Używając:, Command myCommand = new Command(scriptfile);a następnie pipeline.Commands.Add(myCommand);rozwiąż problem ucieczki.
— scharette

Odpowiedzi:


111

Spróbuj utworzyć plik skryptu jako osobne polecenie:

Command myCommand = new Command(scriptfile);

następnie możesz dodać parametry za pomocą

CommandParameter testParam = new CommandParameter("key","value");
myCommand.Parameters.Add(testParam);

i w końcu

pipeline.Commands.Add(myCommand);

Oto kompletny, zredagowany kod:

RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

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

RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);

Pipeline pipeline = runspace.CreatePipeline();

//Here's how you add a new script with arguments
Command myCommand = new Command(scriptfile);
CommandParameter testParam = new CommandParameter("key","value");
myCommand.Parameters.Add(testParam);

pipeline.Commands.Add(myCommand);

// Execute PowerShell script
results = pipeline.Invoke();

Nadal wydaje mi się, że problem polega na tym, że jeśli wartość jest taka jak c: \ program files \ myprogram, klucz jest ustawiony na c: \ program. :(
— Mephisztoe

Nieważne. Czasami pomaga, gdy wiesz, jak poprawnie podzielić ciągi. ;-) Jeszcze raz dziękuję, Twoje rozwiązanie pomogło mi w rozwiązaniu mojego problemu!
— Mephisztoe

@Tronex - powinieneś zdefiniować klucz jako parametr twojego skryptu. PowerShell ma kilka świetnych wbudowanych narzędzi do pracy ze ścieżkami. Może zadaj inne pytanie na ten temat. @ Kosi2801 ma poprawną odpowiedź dotyczącą dodawania parametrów.
— Steven Murawski

Wpisywanie mojej odpowiedzi nakłada się na Twoją .. Cieszę się, że udało Ci się rozwiązać ten problem!
— Steven Murawski

1
Zmienna scriptInvoker nie jest używana.
— niaher,

33

Mam inne rozwiązanie. Chcę tylko sprawdzić, czy wykonanie skryptu PowerShell powiedzie się, ponieważ być może ktoś może zmienić politykę. Jako argument podaję tylko ścieżkę skryptu do wykonania.

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = @"powershell.exe";
startInfo.Arguments = @"& 'c:\Scripts\test.ps1'";
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();

string output = process.StandardOutput.ReadToEnd();
Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest"));

string errors = process.StandardError.ReadToEnd();
Assert.IsTrue(string.IsNullOrEmpty(errors));

Zawartość skryptu to:

$someVariable = "StringToBeVerifiedInAUnitTest"
$someVariable

1
Cześć. Czy masz pojęcie, dlaczego uruchomienie programu PowerShell zgodnie z opisem i wykonanie procesu wszystkich poleceń (w naszym przypadku) nie kończy się?
— Eugeniu Torica

Z jakiej biblioteki korzystasz
— SoftwareSavant

11

Miałem problem z przekazaniem parametrów do metody Commands.AddScript.

C:\Foo1.PS1 Hello World Hunger
C:\Foo2.PS1 Hello World

scriptFile = "C:\Foo1.PS1"

parameters = "parm1 parm2 parm3" ... variable length of params

Rozwiązałem to, przekazując nulljako nazwę i parametr jako wartość do kolekcjiCommandParameters

Oto moja funkcja:

private static void RunPowershellScript(string scriptFile, string scriptParameters)
{
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    runspace.Open();
    RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
    Pipeline pipeline = runspace.CreatePipeline();
    Command scriptCommand = new Command(scriptFile);
    Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();
    foreach (string scriptParameter in scriptParameters.Split(' '))
    {
        CommandParameter commandParm = new CommandParameter(null, scriptParameter);
        commandParameters.Add(commandParm);
        scriptCommand.Parameters.Add(commandParm);
    }
    pipeline.Commands.Add(scriptCommand);
    Collection<PSObject> psObjects;
    psObjects = pipeline.Invoke();
}

Właśnie dodano:using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))...using (Pipeline pipeline = runspace.CreatePipeline())
— Red

Kiedy przekazuję wiele parametrów, występuje ten błąd: Nieobsłużony wyjątek typu „System.Management.Automation.ParseException” wystąpił w System.Management.Automation.dll
— Muhammad Noman

5

Możesz również po prostu użyć potoku z metodą AddScript:

string cmdArg = ".\script.ps1 -foo bar"            
Collection<PSObject> psresults;
using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                pipeline.Commands.AddScript(cmdArg);
                pipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
                psresults = pipeline.Invoke();
            }
return psresults;

Zajmie łańcuch i wszelkie parametry, które mu przekażesz.


4

Mój jest nieco mniejszy i prostszy:

/// <summary>
/// Runs a PowerShell script taking it's path and parameters.
/// </summary>
/// <param name="scriptFullPath">The full file path for the .ps1 file.</param>
/// <param name="parameters">The parameters for the script, can be null.</param>
/// <returns>The output from the PowerShell execution.</returns>
public static ICollection<PSObject> RunScript(string scriptFullPath, ICollection<CommandParameter> parameters = null)
{
    var runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();
    var pipeline = runspace.CreatePipeline();
    var cmd = new Command(scriptFullPath);
    if (parameters != null)
    {
        foreach (var p in parameters)
        {
            cmd.Parameters.Add(p);
        }
    }
    pipeline.Commands.Add(cmd);
    var results = pipeline.Invoke();
    pipeline.Dispose();
    runspace.Dispose();
    return results;
}

3

Oto sposób dodawania parametrów do skryptu, jeśli był używany

pipeline.Commands.AddScript(Script);

Dzieje się tak w przypadku użycia HashMap jako parametrów, gdzie klucz jest nazwą zmiennej w skrypcie, a wartością jest wartość zmiennej.

pipeline.Commands.AddScript(script));
FillVariables(pipeline, scriptParameter);
Collection<PSObject> results = pipeline.Invoke();

A metoda zmiennej wypełnienia to:

private static void FillVariables(Pipeline pipeline, Hashtable scriptParameters)
{
  // Add additional variables to PowerShell
  if (scriptParameters != null)
  {
    foreach (DictionaryEntry entry in scriptParameters)
    {
      CommandParameter Param = new CommandParameter(entry.Key as String, entry.Value);
      pipeline.Commands[0].Parameters.Add(Param);
    }
  }
}

w ten sposób możesz łatwo dodać wiele parametrów do skryptu. Zauważyłem również, że jeśli chcesz uzyskać wartość ze zmiennej w swoim skrypcie w następujący sposób:

Object resultcollection = runspace.SessionStateProxy.GetVariable("results");

// wyniki są nazwą v

będziesz musiał to zrobić tak, jak pokazałem, ponieważ z jakiegoś powodu, jeśli zrobisz to w sposób, w jaki Kosi2801 sugeruje, że lista zmiennych skryptu nie zostanie wypełniona twoimi własnymi zmiennymi.


3

Dla mnie najbardziej elastycznym sposobem uruchamiania skryptu PowerShell z C # było użycie PowerShell.Create().AddScript()

Fragment kodu to

string scriptDirectory = Path.GetDirectoryName(
    ConfigurationManager.AppSettings["PathToTechOpsTooling"]);

var script =    
    "Set-Location " + scriptDirectory + Environment.NewLine +
    "Import-Module .\\script.psd1" + Environment.NewLine +
    "$data = Import-Csv -Path " + tempCsvFile + " -Encoding UTF8" + 
        Environment.NewLine +
    "New-Registration -server " + dbServer + " -DBName " + dbName + 
       " -Username \"" + user.Username + "\" + -Users $userData";

_powershell = PowerShell.Create().AddScript(script);
_powershell.Invoke<User>();
foreach (var errorRecord in _powershell.Streams.Error)
    Console.WriteLine(errorRecord);

Możesz sprawdzić, czy wystąpił jakiś błąd, sprawdzając Streams.Error. Warto było sprawdzić kolekcję. Użytkownik to typ obiektu, który zwraca skrypt programu PowerShell.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.