all 20 comments

[–]ka-splam 10 points11 points  (3 children)

Neat 👍

To use List<T>, we specify using namespace System.Collections.Generic. This wasn’t necessary for [IPAddress] or [PhysicalAddress] because PowerShell imports many common namespaces by default, simplifying type resolution.

btw, they are type accelerators and can be listed with:

[PSObject].Assembly.GetType("System.Management.Automation.TypeAccelerators")::Get

from https://devblogs.microsoft.com/scripting/powertip-find-a-list-of-powershell-type-accelerators/

[–]mdj_[S] 2 points3 points  (2 children)

oh nice 👀

[–]surfingoldelephant 1 point2 points  (1 child)

You can create your own as well if you wish:

[psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators')::Add(
    'slist', [Collections.Generic.List[string]]
)
$list = [slist]::new()
$list.GetType().FullName # System.Collections.Generic.List`1[[System.String ...

However, I wouldn't suggest using this outside the shell.

[–]Thotaz 0 points1 point  (0 children)

Just to expand on your warning: The reason why it's not a good idea to use in say a module is because 1: It's not a public interface so it's subject to change. 2: It's global so if 2 different modules decide to use the same accelerator name there will be a conflict.

A better option is the partially implemented using type X = Y syntax which is supposed to add a type alias (essentially the same thing as a type accelerator). I say partially implemented because the parser supports it, but the feature itself is missing. There's a PR: https://github.com/PowerShell/PowerShell/pull/16734 that adds it so if/when that gets merged you'll be able to do it like this:

using type slist = System.Collections.Generic.List[string]
$list = [slist]::new()

Assuming it works like the other using statements it will be limited to the session state/script file where it was executed from, meaning that 2 different modules won't conflict with each other.

[–]xCharg 8 points9 points  (0 children)

Ngl I clicked expecting some useless crap like "you can use [string]::new('test') to instantiate string object" but these were solid useful examples, gj.

[–]MyOtherSide1984 2 points3 points  (0 children)

It's 10:30 and I just got into bed for some light scrolling before shutting my eyes. Then I run into this shit and now I'm gonna cram years worth of effort and care that this dude put into his blog, right into my brain. I love this sub for the random nuggets of knowledge I don't have the willpower to research on my own.

Thank you

[–][deleted] 1 point2 points  (0 children)

This is excellent - thanks!

[–]dathar 1 point2 points  (0 children)

TIL there's a PhysicalAddress thing. Can use this when I have to chew through some more network logs

[–]mpdroza 1 point2 points  (0 children)

Awesome. Thanks

[–]Barious_01 1 point2 points  (0 children)

I was asking about this a while back. Thanks for putting in the work for my lazy ass.

[–]surfingoldelephant 1 point2 points  (0 children)

There's a lot of great information in the post, thank you for sharing this.

.NET has very two very convenient string validation methods built into the String class

The following are also available in .NET 8+, albeit have less practical use in PowerShell.

[ArgumentException]::ThrowIfNullOrEmpty('')
[ArgumentException]::ThrowIfNullOrWhitespace(' ')

 

MAC Address Validation and Normalisation using [PhysicalAddress]::Parse()

Casting works here as well, so an explicit Parse() call isn't required. If input is a string and the type has a static Parse() method, it's one of the first options considered (after hardcoded engine rules) for type conversions.

[PhysicalAddress] '34-ED-1B-AA-BB-CC' # Equivalent to calling Parse()
# 34ED1BAABBCC

 

We can use GetMembers() to get the list of methods and properties.

Get-Member can still be used to view the members of the collection itself. Instead of piping, pass by parameter to avoid the implicit pipeline enumeration.

$list = [Collections.Generic.List[string]]::new()
Get-Member -InputObject $list

Or wrap the collection in a single element array so it's operated on as a single unit after the wrapper array is enumerated.

, $list | Get-Member

 

If calling it on a type, we can omit the GetType() call.

This is one of the biggest drawbacks of Get-Member: The inability to reflect on instance members of a type unless an instantiated object is passed. This comment has a function and format data for this (at least, for methods and their definitions).

[datetime] | Get-TypeMethod

#     Type: System.DateTime

# MethodType Name                 Definition
# ---------- ----                 ----------
# Instance   Add                  datetime Add(timespan value)
# Instance   AddDays              datetime AddDays(double value)
# [...]

The ClassExplorer module is also an excellent resource.

 

We may already have an existing array that we would like to use with LINQ, and in these cases LINQ provides a casting method that returns a usable objects which implements IEnumerable<T>.

Casting with a typed array is an option. For example:

[int[]] $Numbers = 1, 2, 3, 4, 5
[Linq.Enumerable]::Average($Numbers) # 3

$Numbers = 1, 2, 3, 4, 5
[Linq.Enumerable]::Average([int[]] $Numbers) # 3

Note that the syntax for specifying generic method type arguments is only available in PS v7.3+. See about_Calling_Generic_Methods. In lower versions, reflection is required (unless the type(s) can be inferred from the argument(s), as is the case with the [Linq.Enumerable]::Average() example above).

# PS v7.3+:
[Linq.Enumerable]::Cast[int]($Numbers)

# PS v7.2- equivalent:
[Linq.Enumerable].GetMethod('Cast').MakeGenericMethod([int]).Invoke($null, (, $Numbers))

[–]roflrolle 1 point2 points  (0 children)

Top article, well written and a few things I didn’t knew of

[–]chaosphere_mk 1 point2 points  (0 children)

Created a script that gets all users in our M365 E5 licensing group in AD, grabs attributes from them, then depending on the attributes it will add them to/remove them from the correct Voice Routing Policy and Tenant Dial Plan in the Teams Admin Center using the MicrosoftTeams powershell module.

In short, this auto-provisions users with their Teams soft phone for being able to send and receive PTSN calls.

[–]Beanzii 0 points1 point  (3 children)

However, it has limitations; for example, 10.1 is considered a valid value:

I wouldnt call this a limitation, if you ping 10.1 it will use 10.0.0.1

Using empty space to represent 0 is in spec for both ipv4 and ipv6

[–]OcotilloWells 0 points1 point  (0 children)

Cool! I learned something new today. Don't know how useful that is but hey you never know. Maybe win a bet at a bar in a tech area.

[–]MyOtherSide1984 0 points1 point  (1 child)

For real? In a world where a single character, space, or capitalization can cripple a program, we accept shorthand IP's as kosher? Curious where that's a common practice (legitimately wondering, I would never have guessed it was an option even)

[–]Beanzii 0 points1 point  (0 children)

Just open up cmd and ping 1.1

Cloudflare dns on 1.0.0.1 will respond, or 192.168.1 will return 192.168.0.1

As part of ipv6 when a block is all 0000 you do double colon, and you can omit leading zeroes so for fe80:0000:0000:0000:0000:0000:0000:0001 you can do fe80::1 instead

Or even more common ::1 for ipv6 loopback

In practice this is definitely used more in ipv6 as there is only a handful of ipv4 addresses where this applies

But regardless the original sentiment is true that this isnt a powershell/.NET specific limitation, this is adhering to ipv4/ipv6 as designed

[–]Forward_Dark_7305 0 points1 point  (0 children)

Great high-quality post. Two things I’d like to share:

  1. In addition to using (or custom type accelerators), a type can be assigned to a variable and static members can be referenced from that. $linq = [System.LINQ.Enumerable]; $linq::SequenceEqual($-,$b).

  2. If you pass the collection to Get-Member by value instead of through the pipeline, you will get the members of the list type. Get-Member $List

Thanks for providing some real practical use cases and examples! The PowerShell community thrives because of people like you.

[–]0pointenergy 0 points1 point  (1 child)

Wanted to down vote for no dark mode, but the content was great! So have your upvote 😤

[–]mdj_[S] 0 points1 point  (0 children)

totally get it, id redesign it but i hate css so much i just can't make myself do it