Laden...

PowerShell script funktioniert direkt in PS, aber nicht aus C# heraus

Erstellt von ByteDevil vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.036 Views
ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren
PowerShell script funktioniert direkt in PS, aber nicht aus C# heraus

Hallo,

ich schreibe gerade an einer .Net Core Anwendung, in der ich die Assembly System.Speech nutzen möchte. Da diese aber nicht mit .Net Core 3.0 zusammen spielt, wollte ich sie über die PowerShell nutzen.
Folgender Code funktioniert:


private static void Execute(string command, bool wait)
{
    var cFile = System.IO.Path.GetTempPath() + Guid.NewGuid() + ".ps1";

    using var tw = new System.IO.StreamWriter(cFile, false, Encoding.UTF8);
    tw.Write(command);
 
    var start =
        new System.Diagnostics.ProcessStartInfo()
        {
            FileName = "C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe",  // CHUPA MICROSOFT 02-10-2019 23:45                    
                LoadUserProfile = false,
            UseShellExecute = false,
            CreateNoWindow = true,
            Arguments = $"-executionpolicy bypass -File {cFile}",
            WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
        };

    var p = System.Diagnostics.Process.Start(start);
  
    if (wait)
        p.WaitForExit();
}

public static void Speak(string textToSpeech, bool wait = false)
{
    // Command to execute PS  
    Execute($@"Add-Type -AssemblyName System.Speech;  
    $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;      
    $speak.Speak(""{textToSpeech}"");", wait); // Embedd text 
}

Ist aber irgendwie nicht das Gelbe vom Ei und ist nutzlos wenn ich einen Rückgabewert aus der PS haben möchte. Also habe ich mir via NuGet Microsoft.PowerShell.SDK (6.2.3) besorgt und die Execute Methode von oben ausgetauscht durch:


private static object Execute2(string command, bool wait)
{
    PowerShell PowerShellInstance = PowerShell.Create(RunspaceMode.NewRunspace);

    PowerShellInstance.AddScript(command);

    var results = PowerShellInstance.Invoke();

    foreach (PSObject outputItem in results)
    {
        Console.WriteLine(outputItem.BaseObject.ToString());
    }

    return results.Count > 0 ? results[0] : null;
}

PowerShellInstance.Streams.Error beinhaltet nun folgendes für mich:

"Exception calling "Speak" with "1" argument(s): "Object reference not set to an instance of an object.""

offenbar ist der SpeechSynthesizer null. Wieso klappt es wenn ich die PowerShell "manuell" öffne und hier nicht? Selbes Spiel wenn ich die Powershell öffne und den code hineinkopiere...geht wunderbar.

16.806 Beiträge seit 2008
vor 4 Jahren

Die Powershell Umgebung in der Shell ist völlig anders als hier - allein weil Du keine Shell hast.
Versuch doch einfach Mal nach und nach beginnend mit einem Hello World Projekt gewisse Dinge auszuschließen und so den Fehler eingrenzen zu können.

Offenbar willst Du auch über .NET Core Dinge quasi mit einem Workaround auf .NET Framework Elemente zugreifen.
Ob das so überhaupt funktioniert...

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Ja ich werde es morgen mal versuchen. Es ist frustrierend...möchte ungern noch was neues mit dem .Net Framework starten, weil ich nicht in ein paar Jahren in die Röhre gucken will. Aber es gibt noch fast nichts am Bibliotheken dafür...sehr nervig 😦

Kennst du einen anderen Weg wie ich Bibliotheken aus dem .Net Framework irgendwie in .Net Core nutzen kann?

16.806 Beiträge seit 2008
vor 4 Jahren

.NET Core 3 ist API Complete was die Migration von .NET Framework betrifft.
Auch alle großen SDKs und Projekte unterstützen .NET Core bzw. .NET Standard.

Dass es "fast nichts" gibt, das stimmt nicht.

PS: Wenn Du Code 1:1 aus dem Netz kopierst, dann darfst Du die Quelle gerne referenzieren 😉
Wenn Du ihn darüber hinaus nicht verstehst, dann ist das ganz schlecht:

Dein Code hast Du Dir aus einem Sample mit PowerShell 5 kopiert, das auf .NET Framework basiert.
Microsoft.PowerShell.SDK 6 ist jedoch PowerShell Core und damit .NET Core.
Wird also über diesen Weg sehr wahrscheinlich überhaupt nicht möglich sein, weil ganz einfach Dependencies fehlen.

Und da System.Speech Windows spezifisch ist, kann es natürlich nicht in .NET Core landen.

PPS: wir nutzen Azure Cognitive Services für Text to Speech bzw vise versa und .NET Core / JavaScript.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

API Complete?

Auch alle großen SDKs und Projekte unterstützen .NET Core bzw. .NET Standard.

Naja scheinbar ja nicht. System.Speech ist nicht verfügbar für .Net Core 3.0
Und auch sonst kann ich nichts freies finden das kompatibel wäre.

wir nutzen Azure Cognitive Services für Text to Speech bzw vise versa und .NET Core / JavaScript.

Damit habe ich auf Arbeit auch schon gearbeitet. Nur möchte ich mir das für ein privates, nicht kommerzielles Projekt nicht leisten. Zudem ist dafür eine Internetverbindung erforderlich. Und die Sprachsynthese die ich hier verwenden möchte, funktioniert eigentlich tadellos.

PS: Habe hier jemanden gefunden der genau das selbe Problem hat.

16.806 Beiträge seit 2008
vor 4 Jahren

Bitte richtig zitieren.

.NET Core 3 ist API Complete was die Migration von .NET Framework betrifft.

Alles, was von NetFx in NetCore kann und soll, wurde migriert.
Speech kann technisch nicht übernommen werden:

Naja scheinbar ja nicht. System.Speech ist nicht verfügbar für .Net Core 3.0

Basics:
Spracherkennung im .NET Framework läuft über die Windows Spracherkennungs API. .NET ist hier nur ein Wrapper.
In .NET Core sind nur APIs enthalten, die Betriebssystem unabhängig sind. Speech ist Windows-spezifisch.

Fazit: Speech kann nicht in .NET Core sein.
Und Speech wird so wenig verwendet, dass sich die handvoll Nutzer eben was anderes suchen müssen.

Du kannst aber problemlos mit .NET Core einen eigenen Wrapper gegen die Win32 API schreiben.
Nichts anderes, was .NET Framework gemacht hat.
Feel free: Microsoft Speech API

jemanden gefunden der genau das selbe Problem hat.

Und Karel hat passend geantwortet.

ByteDevil Themenstarter:in
132 Beiträge seit 2013
vor 4 Jahren

Ah, okay danke.

Du kannst aber problemlos mit .NET Core einen eigenen Wrapper gegen die Win32 API schreiben.
Nichts anderes, was .NET Framework gemacht hat.
Feel free:
>

Das war mir gar nicht so klar. Danke 😃 Vielleicht mache ich das sogar.