📜 ⬆️ ⬇️

Chapter 21. Part 2 - Creating objects and data output objects. PowerShell in depth - Don Jones, Richard Siddaway

Here are different ways to create PowerShell objects. Tips and tricks are given. The text is too big. For all learners poks.

In addition to readability, the number of keystrokes, the requirements for maintaining the order of properties, all of these methods essentially do the same. A few subtle differences: technique 1, hash table. As a rule, the fastest, technology 2 is slower, technology 3 can be much slower.

A good review of learn-powershell.net/2010/09/19/custom-powershell-objects-and-performance measured the speed of object creation performed by MVP Boe Prox. A comparison of the speed of the three methods, the Add-Member is 10 times slower. So this is a plus for technique 1. We did not test technique 4 as Boe did, but our tests show that technique 4 is 10% faster than technique 1. Technique 5 should be used in cases where the typing of properties matters.

')
Self translation:

21.2 Syntax for creating custom objects
We often said that there are always several ways to do something in PowerShell, and this is true for user objects. We will show you all the basic ways, because you will surely come across them in life, we want you to recognize them and use them whenever you want.

Chapter 21.1 Technique number 1. Using hash tables to create custom objects.

Let's start the techniques that we usually use ourselves when we need to create our own object or combine information from different objects into one for subsequent output. We call this path official, or recommended. We use it because it makes it easy to write code, we read well and ultimately allows us to do our work faster.
This method is shown in Listing 21.2 below.

#   ,         $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 PSObject –Property $props Write-Output $obj 


By executing this code, you will get a result similar to this:

 Manufacturer : Microsoft Corporation OSVersion : 6.3.9600 OSArchitecture : 64-bit BIOSSerial : 036685734653 ComputerName : RSSURFACEPRO2 Model : Surface Pro 2 ProcArchitecture : 64 


Since at the output, you have an object with more than four properties. PowerShell made a list output on the screen. You could perform

 Write-Output $obj | ft 


to get a table. Note that the fact is that you created one object by combining information from four objects. You did this by creating a hash table in which you entered the desired property names, the values ​​for them became the property values ​​of other objects. This is what you did in the hash table pointing:

 Manufacturer=$cs.manufacturer 


If you put the hash table entries on one line, you will need to separate each property with a semicolon. If you put each property on a separate line, you do not need a semicolon, it is much easier for you to read and edit the code.
The parentheses with the preceding @ sign say that the hash table begins next. Since the table is in the $ props variable ; it is easy to transfer it in the -property parameters of the new object. The PSObject object is specifically designed for this purpose.

The advantage of this approach is that it is easy to build a hash table on the fly and create many user objects from it. You may notice that in the output object the properties are not of the same order as they were defined in the table. One of the possible solutions is to create formatting for a custom object (a special XML file describing how to display, in what order, etc.) or, if you use powershell 3 and higher, you can use the ordered property

 $props = [ordered]@{ OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth} 


Everything else is the same. Now the properties of the object will be displayed in the order in which they were written. If you pass $ obj to Get-Member , you will see that this is a PS-CustomObject .

Note By default, PowerShell does not track the order of elements in a hash table. That's why when you see the final output, its properties go in the wrong order in which you created them. Starting in PowerShell 3, you can fix this by using the [ordered] attribute. This creates an ordered dictionary (another name for the hash tables) and maintains the order of the elements in it.

21.2.2 Technique 2. Using Select-Object
This method was a favorite in PowerShell v1 , and we still see people using it. We do not like it because it is much more difficult to read. The following listing shows the technique where we create an empty object, and then write the values ​​of these properties.

Listing 21.3. Creating an object using Select-Object
 #      $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 #    Select-Object $obj = 1 | Select-Object ComputerName,OSVersion,OSArchitecture, ProcArchitecture,Model,Manufacturer,BIOSSerial #   $obj.ComputerName = $os.CSName $obj.OSVersion = $os.version $obj.OSArchitecture = $os.osarchitecture $obj.ProcArchitecture = $proc.addresswidth $obj.BIOSSerial = $bios.serialnumber $obj.Model = $cs.model $obj.Manufacturer = $cs.manufacturer Write-Output $obj 


Notice that in Listing 21.3, $ obj = 1 was done, in essence, the value 1 will never be used.

TIP You will see many examples when the empty string is used as an initializer: $ obj = "" | select .... It's just a way to define $ obj as an object, throw something into the pipeline to go to the Select-Object, which will do all the work.

There is a flaw in this approach. Give $ obj to get-member and see the result.

 PS C:\> $obj | Get-Member TypeName: Selected.System.Int32 Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() BIOSSerial NoteProperty System.String BIOSSerial= ComputerName NoteProperty System.String ComputerName= WIN-KNBA0R0TM23 Manufacturer NoteProperty System.String Manufacturer= VMware, Inc. Model NoteProperty System.String Model= VMware Virtual Platform OSArchitecture NoteProperty System.String OSArchitecture= 64-bit OSVersion NoteProperty System.String OSVersion= 6.1.7601 ProcArchitecture NoteProperty System.UInt16 ProcArchitecture=64 

Properties are in place, but TypeName can lead to problems or even just confusion, it all depends on what else you intend to do with this object. We recommend avoiding this technique.

translation box
Here it means:
let's set an example in Get-Member from Listing 21.2 - where we created the hash table
image

Now let's use GM as an example from Listing 21.3 - creating through Select-Object
image


21.2.2 Technique 3. Using Add-Member
This method is considered formal. We believe that it illustrates what is happening in life with formal approaches. It is the most computationally expensive, the slowest of all, so it is not often that you meet people using it in real life. This is the most common approach to PowerShell v1 . There are two variations, and first listing with the code.

Listing 21.4. Creating an object using Add-Member
 #      $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 #      $obj = New-Object –TypeName PSObject #       $obj | Add-Member NoteProperty ComputerName $os.CSName $obj | Add-Member NoteProperty OSVersion $os.version $obj | Add-Member NoteProperty OSArchitecture $os.osarchitecture $obj | Add-Member NoteProperty ProcArchitecture $proc.addresswidth $obj | Add-Member NoteProperty BIOSSerial $bios.serialnumber $obj | Add-Member NoteProperty Model $cs.model $obj | Add-Member NoteProperty Manufacturer $cs.manufacturer Write-Output $obj 

We created a PSObject and add one property to it at a time. You need to call a method every time you add a NoteProperty which contains only a static value. To shorten the code, we used the positional parameters Add-Member. If you use the full syntax, then each Add-Member statement will look like this.

 Add-Member -MemberType NoteProperty -Name ComputerName -Value $os.CSName 

You see that a lot of code comes out.

A variation on this method is to use the -PassThru parameter (abbreviated to -Pass in Listing 21.5) of the Add-Member command. This parameter will put the modified object back into the pipeline so that you can pass it on to the next command, and so on.

Let us show by example

Listing 21.4. Creating an object using Add-Member with the -PassThru option
 #      $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 #      $obj = New-Object –TypeName PSObject #   $obj | Add-Member NoteProperty ComputerName $os.CSName –pass | Add-Member NoteProperty OSVersion $os.version –pass | Add-Member NoteProperty OSArchitecture $os.osarchitecture –Pass | Add-Member NoteProperty ProcArchitecture $proc.addresswidth –pass | Add-Member NoteProperty BIOSSerial $bios.serialnumber –pass | Add-Member NoteProperty Model $cs.model –pass | Add-Member NoteProperty Manufacturer $cs.manufacturer Write-Output $obj 


You can meet this approach in life. In fact, from the point of view of exploitation, this is a vital technique, because what is happening is much clearer. This approach does not follow syntactic labels and is easier to understand step by step.

insert translator
means that debugging is easier


21.2.4 Technique 4. Using Type Declaration

This is one of the variations of the technique 1, works only in PowerShell v3 and v4, this method is more compact. You start with the same hash table.
 #      $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 $obj = [pscustomobject]@{ OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth } Write-Output $obj 


You could continue to fill the $ props variable, the trick of this technique is that the order of properties in the object will be preserved as well as if we used the [ordered] directive

Council The type we use is PSCustomObject. You must use this type because in .NET terms you use the PSObject constructor with no parameters. Do not try to reduce the code by specifying a PSObject object instead of PSCustomObject, you will not get the desired result.

You may have noticed that the previous methods add properties in a different order than you add them. In technique 1, for example, we did not add Computer_Name first, but it would be listed first in the list. Don't worry, in the overwhelming majority of cases, PowerShell works with properties in any order. Technique 4 preserves the order of properties, if you need to use it.

21.2.5 Technique 5. Creating a new class

Not often used technology. It gives some advantages in processing on the conveyor. It can be evaluated as an advanced technique, not all followers will want to delve into .NET. But the option is available as an option.

Listing 21.7 Creating an object using a class
 $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 


Listing 21.7 begins by creating a record containing a class # C code describing the class. The class has a name, MyObj, and makes a series of class property descriptions. In this example, the properties are specified as strings, but it is allowed to mix types. And although we are not going to write down to set properties in the future, the definition of a class requires the GET and SET entries, otherwise PowerShell will throw an exception.

Add-Type is used to compile a class, after which we can use it instead of PSObject. To set the properties of an object, the technique presented here and in Listing 21.6 can be used:
 $obj = [MyObject]@{OSVersion=$os.version Model=$cs.model Manufacturer=$cs.manufacturer BIOSSerial=$bios.serialnumber ComputerName=$os.CSName OSArchitecture=$os.osarchitecture ProcArchitecture=$proc.addresswidth } 

let's test in get-member
 PS C:\> $obj | get-member TypeName: MyObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() BIOSSerial Property string BIOSSerial {get;set;} ComputerName Property string ComputerName {get;set;} Manufacturer Property string Manufacturer {get;set;} Model Property string Model {get;set;} OSArchitecture Property string OSArchitecture {get;set;} OSVersion Property string OSVersion {get;set;} ProcArchitecture Property string ProcArchitecture {get;set;} 


This one is more bulky, but it has its advantages. If you declare a property as a string and try to write a number there, an error message will be generated.

21.2.6 What are the differences ???

In addition to readability, the number of keystrokes, the requirements for maintaining the order of properties, all of these methods essentially do the same.

A few subtle differences: technique 1, hash table. Usually the fastest, especially when you work with several objects, technique 2 is a little slower, technique 3 can be much slower.

A good review of learn-powershell.net/2010/09/19/custom-powershell-objects-and-performance measured the speed of object creation performed by MVP Boe Prox. A comparison of the speed of the three methods, the Add-Member is 10 times slower. So this is a plus for technique 1. We did not test technique 4 as Boe did, but our tests show that technique 4 is 10% faster than technique 1. Technique 5 should be used in cases where the typing of properties matters.

Source: https://habr.com/ru/post/278637/


All Articles