Benutzer mit den meisten Antworten
Objekte typisieren mit .TypeNames.Insert und .GetType() in Powershell

Frage
-
Mithilfe von .TypeNames.Insert soll es möglich sein, einem benutzerdefinierten Objekt - egal ob es mit der "Select" oder der New-Object-Methode erstellt wurde - einen Objekttyp zu geben.
Es sollte dann auch möglich sein, diesen Objekttyp mit .GetType() wieder auszulesen.
So wie in den existierenden Beispielen scheint das aber nicht (mehr ?) zu funktionieren:
Es wird immer nur "PsObject" zurückgeliefert!http://technet.microsoft.com/en-us/magazine/hh750381.aspx
http://stackoverflow.com/questions/12682631/change-the-type-name-of-a-powershell-object-from-pscustomobject-to-something-i-c
Gibt es hier vielleicht Versionsunterschiede zwischen PowerShell 1.0 und 2.0?Ich habe einen Workaround gefunden, der aber sicher weniger performant ist, als
.GetType().$o ="" | Select Bug, Fryingpan
$o.PSobject.TypeNames.Insert(0,"Ladybug")
"GetType: " + $o.GetType().Name
# Workaround:
"TypeName: " + ($o | Get-Member | Select -First 1 ).TypeNameOder geht es doch noch irgendwie mit .GetType()?
Antworten
-
Warum willst Du den Objekten denn einen Namen geben? Geht es Dir eher um Kosmetik oder erwartest Du eine Funktion dahinter?
Wenn es Dir um das Umwandeln von Objekten geht, ist der Name wie schon beschrieben nicht genug. Auch die System.Convert Klasse wird wahrscheinlich nicht ausreichen, wenn Du Objekte hast, die, was die Vererbung angeht, nicht voneinander abhängen.
Wenn Du zwei Klassen hast, deren Objekte in die jeweilig andere Klasse gewandelt werden können sollen, geht dies über das Definieren impliziter Operatoren. Klingt kompliziert, ist es aber nicht:Type conversions with implicit and explicit operators
Das ist dann aber weit weg vom "einfachen" PowerShell Scripting, kann aber in der PowerShell extrem hilfreich sein, wenn man eine Klasse so gebaut hat.
-Raimund
- Bearbeitet Raimund AndréeMicrosoft employee Mittwoch, 16. Januar 2013 13:11
- Als Antwort vorgeschlagen Alex Pitulice Freitag, 18. Januar 2013 10:04
- Als Antwort markiert Denniver ReiningMVP, Moderator Montag, 21. Januar 2013 14:49
-
Hallo Norbert,
ab Powershell v5 kannst du Klassen benutzen, die dann auch mit GetType() den "korrekten" Typ zurück geben.
class MyObject { [string] $ComputerName; [string] $Model; [string] $Manufacturer; [string] $BIOSSerial; [string] $OSArchitecture; [string] $OSVersion; [string] $ProcArchitecture; } $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select-Object –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $obj = New-Object –TypeName MyObject –Property $props Write-Output $obj Write-Output $obj.GetType().Name $obj | Format-Custom
Oder hier mit Einbindung von C#-Code, wie du es bereits angesprochen hast.
$source=@" public class MyObject { public string ComputerName {get; set;} public string Model {get; set;} public string Manufacturer {get; set;} public string BIOSSerial {get; set;} public string OSArchitecture {get; set;} public string OSVersion {get; set;} public string ProcArchitecture {get; set;} } "@ Add-Type -TypeDefinition $source -Language CSharpversion3 $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost |Select –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $obj = New-Object –TypeName MyObject –Property $props Write-Output $obj Write-Output $obj.GetType().Name
Das sollte doch genau das sein, was du benötigst?!
Schau auch noch hier
Wenn du schon entsprechende HashTables gebaut hast, könntest du diese sogar per Casting konvertieren.
class MyObject { [string] $ComputerName; [string] $Model; [string] $Manufacturer; [string] $BIOSSerial; [string] $OSArchitecture; [string] $OSVersion; [string] $ProcArchitecture; } $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select-Object –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $test=[MyObject]$props $test.GetType()
Alternativ ist Folgendes etwas schneller als dein damaliger WA:
$obj.PsObject.Typenames[0]
Liebe Grüße
Please vote as helpful and mark as answer if a post helped you.
This posting is provided "AS IS" with no warranties, and confers no rights.- Als Antwort markiert NLA Dienstag, 23. Februar 2016 16:08
-
Ich habe diese Vorgehensweise auch in meinem Blog beschrieben
PowerShell eigene Objekte erstellen Custom Objects
http://www.admin-source.de/BlogDeu/463/powershell-eigene-objekte-erstellen-custom-objects
Man darf sich das nicht so einfach vorstellen!
Wenn man an deiner Tür das Namensschild ändert, dann ändert sich ja nicht Bewohner!
Das Ändern des Namens Ist nur für PowerShell sichtbar und dies wird NUR von einigen (nicht allen) PowerShell Cmdlets und Methoden beachtet!
Die Methode xxx.getType() ist aber eine .NET Funktion!
xxx.getType() schaut nicht auf das Namenschild an der Tür, sondern es schaut in den Raum hinein, welches Objekt sich darin befindet!
Um den Objekt-Typen auf .NET Ebene zu ändern, musst du das Objekt mit .Net Funktionen oder CType() oder DirectCast() umwandeln (Fachwort: Casten oder Casting). In PowerShell geht das auch über die Type-Acceleratoren. Die Objekte sind danach wirklich einen anderer Typ!
PowerShell Beispiel:# String in einen Integer wandeln ([Int]"12").GetType() # String eines Datums in ein DateTime Objekt verwandeln [DateTime]"01.01.2013" | Get-Member # jedes .NET Objekt (Klasse) das eine Parse() Methode hat, kann auf diese Weise in PowerShell gecastet werden ([Version]'1.1.1').gettype()
Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
My PowerShell Blog http://www.admin-source.info
[string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
German ? Come to German PowerShell Forum!- Als Antwort vorgeschlagen Peter Kriegel Freitag, 18. Januar 2013 10:30
- Als Antwort markiert Denniver ReiningMVP, Moderator Montag, 21. Januar 2013 14:49
Alle Antworten
-
Ich habe diese Vorgehensweise auch in meinem Blog beschrieben
PowerShell eigene Objekte erstellen Custom Objects
http://www.admin-source.de/BlogDeu/463/powershell-eigene-objekte-erstellen-custom-objects
Man darf sich das nicht so einfach vorstellen!
Wenn man an deiner Tür das Namensschild ändert, dann ändert sich ja nicht Bewohner!
Das Ändern des Namens Ist nur für PowerShell sichtbar und dies wird NUR von einigen (nicht allen) PowerShell Cmdlets und Methoden beachtet!
Die Methode xxx.getType() ist aber eine .NET Funktion!
xxx.getType() schaut nicht auf das Namenschild an der Tür, sondern es schaut in den Raum hinein, welches Objekt sich darin befindet!
Um den Objekt-Typen auf .NET Ebene zu ändern, musst du das Objekt mit .Net Funktionen oder CType() oder DirectCast() umwandeln (Fachwort: Casten oder Casting). In PowerShell geht das auch über die Type-Acceleratoren. Die Objekte sind danach wirklich einen anderer Typ!
PowerShell Beispiel:# String in einen Integer wandeln ([Int]"12").GetType() # String eines Datums in ein DateTime Objekt verwandeln [DateTime]"01.01.2013" | Get-Member # jedes .NET Objekt (Klasse) das eine Parse() Methode hat, kann auf diese Weise in PowerShell gecastet werden ([Version]'1.1.1').gettype()
Please click “Mark as Answer” if my post answers your question and click “Vote As Helpful” if my Post helps you.
Bitte markiere hilfreiche Beiträge von mir als “Als Hilfreich bewerten” und Beiträge die deine Frage ganz oder teilweise beantwortet haben als “Als Antwort markieren”.
My PowerShell Blog http://www.admin-source.info
[string](0..21|%{[char][int]([int]("{0:d}" -f 0x28)+('755964655967-86965747271757624-8796158066061').substring(($_*2),2))})-replace' '
German ? Come to German PowerShell Forum!- Als Antwort vorgeschlagen Peter Kriegel Freitag, 18. Januar 2013 10:30
- Als Antwort markiert Denniver ReiningMVP, Moderator Montag, 21. Januar 2013 14:49
-
Warum willst Du den Objekten denn einen Namen geben? Geht es Dir eher um Kosmetik oder erwartest Du eine Funktion dahinter?
Wenn es Dir um das Umwandeln von Objekten geht, ist der Name wie schon beschrieben nicht genug. Auch die System.Convert Klasse wird wahrscheinlich nicht ausreichen, wenn Du Objekte hast, die, was die Vererbung angeht, nicht voneinander abhängen.
Wenn Du zwei Klassen hast, deren Objekte in die jeweilig andere Klasse gewandelt werden können sollen, geht dies über das Definieren impliziter Operatoren. Klingt kompliziert, ist es aber nicht:Type conversions with implicit and explicit operators
Das ist dann aber weit weg vom "einfachen" PowerShell Scripting, kann aber in der PowerShell extrem hilfreich sein, wenn man eine Klasse so gebaut hat.
-Raimund
- Bearbeitet Raimund AndréeMicrosoft employee Mittwoch, 16. Januar 2013 13:11
- Als Antwort vorgeschlagen Alex Pitulice Freitag, 18. Januar 2013 10:04
- Als Antwort markiert Denniver ReiningMVP, Moderator Montag, 21. Januar 2013 14:49
-
Hallo NLA,
Ist die Thematik abgeklärt? Wenn ja - bitte markiere die entsprechenden Beiträge "als Antwort".
Viele Grüße,
AlexAlex Pitulice, MICROSOFT
Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können. -
Ich möchte hier meinen alten Thread noch einmal aufgreifen, da seinerzeit nicht klar geworden war, um was es mir eigentlich ging. Mein Lösungsansatz hat funktioniert, aber ganz befriedigend ist das nicht. Wenn ich einen "harten" benutzerdefinierten Datentyp will, muss ich C#-Code einbetten.
Ich möchte ein benutzerdefiniertes Objekt erstellen und diesem eine Typenbezeichnung geben, so wie Rückgabewerte von Commandlets diesen auch liefern. Vom Ansatz her sind dynamische Objekte in PowerShell etwas anderes, als Instanzen von Klassen in C#, vielleicht sogar eher so wie in JavaScript.
Auf jeden Fall können jederzeit Member hinzugefügt oder auch per Select-Object weggefiltert werden.
Wenn ein Objekt nun aber eine bestimmte Typenbezeichnung hat, kann ich davon ausgehen, dass es wahrscheinlich auch bestimmte Member hat. Was für ein Objekt ich vor mir habe, muss ich dann nicht anhand der Kombination von Properties erraten, sondern habe wenigstens eine Grundannahme, was mich erwartet. Ich muss ggf. immer noch prüfen, ob ein Member tatsächlich existiert, aber die Unsicherheit ist etwas begrenzter.
Das sehe ich nicht als Kosmetik.Ich erhalte damit die Möglichkeit, in einer Collection verschiedene Objekttypen zu haben. Damit lassen sich z.B. die verschiedenen Satzarten aus einer VSAM-Datei (Host ..Cobol..Steinzeit) hervorragend abbilden, oder auch Entitäten aus XML-Dateien, die zwar variabel sind, aber ggf. einem Schema folgen usw.
Es gab auch mal einen Ansatz für dynamische Objekte in C#: https://clay.codeplex.com/
Die Clay-Objekte hatten zwar keinen aussagekräftigen Typ, aber einen ShapeName.
http://stackoverflow.com/questions/5075649/dump-objects-build-with-clay-in-c-sharpWie handhabt ihr das inzwischen?
NLA
- Bearbeitet NLA Mittwoch, 6. Januar 2016 15:45
-
Hallo Norbert,
ab Powershell v5 kannst du Klassen benutzen, die dann auch mit GetType() den "korrekten" Typ zurück geben.
class MyObject { [string] $ComputerName; [string] $Model; [string] $Manufacturer; [string] $BIOSSerial; [string] $OSArchitecture; [string] $OSVersion; [string] $ProcArchitecture; } $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select-Object –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $obj = New-Object –TypeName MyObject –Property $props Write-Output $obj Write-Output $obj.GetType().Name $obj | Format-Custom
Oder hier mit Einbindung von C#-Code, wie du es bereits angesprochen hast.
$source=@" public class MyObject { public string ComputerName {get; set;} public string Model {get; set;} public string Manufacturer {get; set;} public string BIOSSerial {get; set;} public string OSArchitecture {get; set;} public string OSVersion {get; set;} public string ProcArchitecture {get; set;} } "@ Add-Type -TypeDefinition $source -Language CSharpversion3 $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost |Select –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $obj = New-Object –TypeName MyObject –Property $props Write-Output $obj Write-Output $obj.GetType().Name
Das sollte doch genau das sein, was du benötigst?!
Schau auch noch hier
Wenn du schon entsprechende HashTables gebaut hast, könntest du diese sogar per Casting konvertieren.
class MyObject { [string] $ComputerName; [string] $Model; [string] $Manufacturer; [string] $BIOSSerial; [string] $OSArchitecture; [string] $OSVersion; [string] $ProcArchitecture; } $os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost $cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost $bios = Get-WmiObject –Class Win32_BIOS –comp localhost $proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select-Object –First 1 $props = @{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} $test=[MyObject]$props $test.GetType()
Alternativ ist Folgendes etwas schneller als dein damaliger WA:
$obj.PsObject.Typenames[0]
Liebe Grüße
Please vote as helpful and mark as answer if a post helped you.
This posting is provided "AS IS" with no warranties, and confers no rights.- Als Antwort markiert NLA Dienstag, 23. Februar 2016 16:08