michi.wtr
Goto Top

C-Sharp Abhängige Klassen in PowerShell implementieren

Hi zusammen,

da ich ein PowerShell Skript schreibe, welches parallel zu einem Programm läuft das ich geschrieben hatte, möchte ich zwei der im Projekt enthaltenen C# Klassen in PowerShell implementieren.

Hierfür habe ich mir die Klassen LogType.cs und LogWriter.cs auf einen freigegebenen Ordner kopiert.

LogType ist lediglich ein Enum:
namespace Rechnungsverteiler.tools
{
    public enum LogType
    {
        Info,
        Warning,
        Error
    }
}

LogWriter die Klasse, welche die Logdateien schreibt:
using System;
using System.IO;
using System.Text;
using Rechnungsverteiler.tools;

namespace Rechnungsverteiler.tools
{
    public class LogWriter
    {
        private readonly FileInfo file;

        /// <summary>
        /// Creates LogWriter for specific logfile.
        /// </summary>
        /// <param name="filePath">Path to logfile.</param> 
        public LogWriter(string filePath)
        {
            try
            {
                if (!File.Exists(filePath))
                    NewLog(filePath);

                file = new FileInfo(filePath);
            }
            catch
            {
                // Write-Mail
            }
        }



        /// <summary>
        /// Write new log message.
        /// </summary>
        /// <param name="logType">Type of log entry.</param> 
        /// <param name="content">Content of log entry.</param> 
        public void Write(LogType logType, string content)
        {
            try
            {
                file.IsReadOnly = false;
                using (StreamWriter sw = new StreamWriter(file.FullName, true))
                {
                    sw.WriteLine(String.Format("{0:dd.MM.yyyy hh:mm:ss} : {1,7} | {2}", DateTime.Now, logType, content));  
                }
            }
            catch
            {
                // Write-Mail
            }
            finally
            {
                try
                {
                    file.IsReadOnly = true;
                }
                catch { }
            }
        }



        /// <summary>
        /// Splits the last log entry to new one by writing a bar of %%%%%%%%%%%%%.
        /// </summary>
        public void NewSession()
        {
            try
            {
                file.IsReadOnly = false;
                using (StreamWriter sw = new StreamWriter(file.FullName, true))
                {
                    sw.WriteLine("\r\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r\n");  
                }
            }
            catch
            {
                // Write-Mail
            }
            finally
            {
                try
                {
                    file.IsReadOnly = true;
                }
                catch { }
            }
        }



        /// <summary>
        /// Create new logfile
        /// </summary>
        /// <param name="path">Path for logfile</param> 
        private void NewLog(string path)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(File.Create(path)))
                {
                    sw.WriteLine(new StringBuilder("************************************************************\r\n").AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                                   "*  E-Invoice-LogDatei                                      *").AppendLine(  
                                                   "*  ==================                                      *").AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                     String.Format("*  User: {0,-48}  *", System.Security.Principal.WindowsIdentity.GetCurrent().Name)).AppendLine(  
                                     String.Format("*  Date: {0,-48:dd.MM.yyyy}  *", DateTime.Now)).AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                                   "************************************************************\r\n").ToString());  
                }
                File.SetAttributes(path, FileAttributes.ReadOnly);
            }
            catch
            {
                // Write-Mail
            }
        }
    }
}


Diese möchte ich nun mit Add-Type für ein Skript in PowerShell hinzufügen:
Add-Type -TypeDefinition (Get-Content -Path .\LogType.cs | Out-String)
Add-Type -TypeDefinition (Get-Content -Path .\LogWriter | Out-String)

Da die Klasse LogWriter in der Methode Write(LogType logtype, string content) aber die 1. Klasse kennen muss, bekomme ich beim Hinzufügen mit Add-Type fogende Fehlerausgaben:

screenshot 2023-04-27 112828


Der Typ [Rechnungsverteiler.tools.LogType] wird problemlos hinzugefügt, jedoch wird diese beim Hinzufügen des Typs [Rechnungsverteiler.tools.LogWriter] nicht erkannt....

Wenn ich die Klasse ohne Namespace erzeuge (einfach namespace Zeilen löschen) wird mir der Typ [LogType] auch problemlos hinzugefügt, jedoch wird der Typ nicht beim Hinzufügen der [LogWriter] Klasse erkannt.

Auch wenn ich auf using Rechnungsvertieler.tools; in LogWriter verzichte und stattdessen Write(Rechnungsverteiler.tools.LogType....) verwende leider kein Erfolg.

In der Hilfe habe ich gesehen, dass man statt -TypeDefinition auch -UsingNamespace benutzen könnte, jedoch wird das in den Examples für den Import einer cs-Datei nicht mit aufgeführt.

Hätte jemand eine Ahnung wie ich noch vorgehen könnte?

Content-ID: 6933815873

Url: https://administrator.de/forum/c-sharp-abhaengige-klassen-in-powershell-implementieren-6933815873.html

Ausgedruckt am: 30.12.2024 um 17:12 Uhr

Kraemer
Kraemer 27.04.2023 um 13:53:51 Uhr
Goto Top
Auf die schnelle fällt mir nur folgendes ein:

$Code=Get-Content -Path .\LogType.cs
$Code+=Get-Content -Path .\LogWriter.cs
Add-Type -TypeDefinition $code -Language CSharp	

Gruß
6247018886
Lösung 6247018886 27.04.2023 aktualisiert um 14:34:23 Uhr
Goto Top
Add-Type @'  
using System;
using System.IO;
using System.Text;

namespace Rechnungsverteiler.tools
{
    public enum LogType
    {
        Info,
        Warning,
        Error
    }
    public class LogWriter
    {
        private readonly FileInfo file;

        /// <summary>
        /// Creates LogWriter for specific logfile.
        /// </summary>
        /// <param name="filePath">Path to logfile.</param> 
        public LogWriter(string filePath)
        {
            try
            {
                if (!File.Exists(filePath))
                    NewLog(filePath);

                file = new FileInfo(filePath);
            }
            catch
            {
                // Write-Mail
            }
        }

        /// <summary>
        /// Write new log message.
        /// </summary>
        /// <param name="logType">Type of log entry.</param> 
        /// <param name="content">Content of log entry.</param> 
        public void Write(LogType logType, string content)
        {
            try
            {
                file.IsReadOnly = false;
                using (StreamWriter sw = new StreamWriter(file.FullName, true))
                {
                    sw.WriteLine(String.Format("{0:dd.MM.yyyy hh:mm:ss} : {1,7} | {2}", DateTime.Now, logType, content));  
                }
            }
            catch
            {
                // Write-Mail
            }
            finally
            {
                try
                {
                    file.IsReadOnly = true;
                }
                catch { }
            }
        }



        /// <summary>
        /// Splits the last log entry to new one by writing a bar of %%%%%%%%%%%%%.
        /// </summary>
        public void NewSession()
        {
            try
            {
                file.IsReadOnly = false;
                using (StreamWriter sw = new StreamWriter(file.FullName, true))
                {
                    sw.WriteLine("\r\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r\n");  
                }
            }
            catch
            {
                // Write-Mail
            }
            finally
            {
                try
                {
                    file.IsReadOnly = true;
                }
                catch { }
            }
        }



        /// <summary>
        /// Create new logfile
        /// </summary>
        /// <param name="path">Path for logfile</param> 
        private void NewLog(string path)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(File.Create(path)))
                {
                    sw.WriteLine(new StringBuilder("************************************************************\r\n").AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                                   "*  E-Invoice-LogDatei                                      *").AppendLine(  
                                                   "*  ==================                                      *").AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                     String.Format("*  User: {0,-48}  *", System.Security.Principal.WindowsIdentity.GetCurrent().Name)).AppendLine(  
                                     String.Format("*  Date: {0,-48:dd.MM.yyyy}  *", DateTime.Now)).AppendLine(  
                                                   "*                                                          *").AppendLine(  
                                                   "************************************************************\r\n").ToString());  
                }
                File.SetAttributes(path, FileAttributes.ReadOnly);
            }
            catch
            {
                // Write-Mail
            }
        }
    }
}
'@  

(New-Object Rechnungsverteiler.tools.LogWriter "$home\Desktop\test.log").Write([Rechnungsverteiler.tools.LogType]::Error,"SampleError")  

Oder eben zusammenfügen, Reihenfolge beachten (using Anweisungen müssen zu beginn stehen!)

Add-Type -TypeDefinition (Get-Content ".\LogWriter.cs",".\LogType.cs" -Raw | out-string)  
Oder eben die von c# generierte DLL direkt mit Add-Type laden:
Add-Type -Path "C:\Pfad\Logwriter.dll"  
Cheers briggs
mayho33
mayho33 27.04.2023 um 14:31:22 Uhr
Goto Top
Hi,

die gängige Art C#-Code in PS anzuwenden geht so:

$myCode = @'  
using ...
namespace mynamespace
{
    public class myclass
    {
        public <retunvalue> myMethod(<type> value1, <type> value2, ...)
        {
            ....
            ....
            return value;
        }
    }
}
'@  

Add-Type -TypeDefinition $myCode -Language CSharp <version explicit> -ErrorAction <ErrorAction> -WarningAction <-WarningAction>

    return [mynamespace.myclass]::myMethod(valueA, valueB, ...);

Mit dem Laden ist PS ein wenig eigen. Partial Classes sind ihm total egal. Manchmal bricht PS ab, weil es meint eine Klasse wäre bereits geladen. Hier also auf die Verwaltung achten, genau wie in C#

Zum Einbinden externer Assemblies zb:
$ScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
[Void] [System.Reflection.Assembly]::LoadFile("$($ScriptRoot )\nlog.dll")  

Grüße!
michi.wtr
michi.wtr 27.04.2023 um 14:36:02 Uhr
Goto Top
Zitat von @Kraemer:

Auf die schnelle fällt mir nur folgendes ein:

$Code=Get-Content -Path .\LogType.cs
$Code+=Get-Content -Path .\LogWriter.cs
Add-Type -TypeDefinition $code -Language CSharp	

Gruß

Das habe ich bereits probiert :\ gibt mir aber genau dieselben Exceptions, auch wenn ich die Namespaces weglasse....


Zitat von @6247018886:

Add-Type @'  
using System;
using System.IO;
using System.Text;

namespace Rechnungsverteiler.tools
{
    public enum LogType
    {
        Info,
        Warning,
        Error
    }
    public class LogWriter
    {
        private readonly FileInfo file;
Cheers briggs

Super, das Zusammenfügen der .cs Dateien zu einer hat funktioniert face-smile
Für den Moment ist das natürlich schön, aber leider finde ich keine Beispiele im Netz, in dem zwei Klassen importiert werden, von denen die eine die andere kennen muss. Das wär noch cool zu wissen.

Vielen lieben Dank euch,
Micha
6247018886
6247018886 27.04.2023 aktualisiert um 14:40:20 Uhr
Goto Top
Lad doch einfach wie oben schon erwähnt das kompilierte .NET Assembly der Klasse ...
Add-Type -Path "C:\Pfad\Logwriter.dll"  
feddisch.

in dem zwei Klassen importiert werden, von denen die eine die andere kennen muss. Das wär noch cool zu wissen.
Das geht problemlos, aber du kannst in PS nicht ein und die selben Namespace/Klasse doppelt definieren. Was du oben ja machst.
michi.wtr
michi.wtr 27.04.2023 um 18:33:30 Uhr
Goto Top
Zitat von @6247018886:

Lad doch einfach wie oben schon erwähnt das kompilierte .NET Assembly der Klasse ...
Add-Type -Path "C:\Pfad\Logwriter.dll"  
feddisch.

in dem zwei Klassen importiert werden, von denen die eine die andere kennen muss. Das wär noch cool zu wissen.
Das geht problemlos, aber du kannst in PS nicht ein und die selben Namespace/Klasse doppelt definieren. Was du oben ja machst.

Ah okay, die LogWriter.dll werd ich mal suchen face-smile aber ich definiere nicht 2x denselben Namspace/Klasse, einmal definiere ich Namespace/LogType, ein Enum um den Art des Logeintrags festzulegen und einmal definiere ich Namexpace/LogWriter um die Logdatei zu schreiben. Der benötigt nur das Wissen um welche Art von Eintrag es sich handelt, denn Zukünftig soll die Klasse noch bei Errors eine E-Mail an mich senden, damit ich den Code ausbessern kann an den stellen.
6247018886
6247018886 27.04.2023 aktualisiert um 18:39:26 Uhr
Goto Top
Zitat von @michi.wtr:
aber ich definiere nicht 2x denselben Namspace/Klasse, einmal definiere ich Namespace/LogType, ein Enum um den Art des Logeintrags festzulegen und einmal definiere ich Namexpace/LogWriter um die Logdatei zu schreiben.
Ja aber für die PowerShell überschreibst du beim zweiten mal mit Add-Type quasi den ganzen Namespace den du vorher schon importiert hast und da beim zweiten mal der Typ nicht enthalten ist, peng.
michi.wtr
michi.wtr 28.04.2023 um 10:01:18 Uhr
Goto Top
Zitat von @6247018886:

Zitat von @michi.wtr:
aber ich definiere nicht 2x denselben Namspace/Klasse, einmal definiere ich Namespace/LogType, ein Enum um den Art des Logeintrags festzulegen und einmal definiere ich Namexpace/LogWriter um die Logdatei zu schreiben.
Ja aber für die PowerShell überschreibst du beim zweiten mal mit Add-Type quasi den ganzen Namespace den du vorher schon importiert hast und da beim zweiten mal der Typ nicht enthalten ist, peng.

Verstehe, gibt es eine Möglichkeit den Namespace nicht zu überschreiben sondern zu erweitern?
Mit hinzufügen über die .dll-Dateien könnte ich diese ja Referenzieren glaube ich, aber müsste doch auch mit -TypeDefinition gehen?
6247018886
6247018886 28.04.2023 aktualisiert um 10:06:58 Uhr
Goto Top
Dir steht jederzeit frei das Enum in einen separaten Namespace zu packen wenn du nicht alles an einer Stelle beisammen hast.
mayho33
mayho33 28.04.2023 um 10:19:50 Uhr
Goto Top
Wenn du die Enums in einem übergeordneten Namespace packst, wie @6247018886 das schon angedeutet hat, dann hast du sie überall verfügbar.

Außerdem hast du sie dann an einer zentralen Stelle liegen und kannst die besser verwalten.