Why is a plus operator required in some Powershell type names? - powershell

Why is it that, in Powershell, the System.DayOfWeek enum can be referred to like [System.DayOfWeek], whereas the System.Environment.SpecialFolder enum must be referred to like [System.Environment+SpecialFolder] (note the plus character)?
My guess is because SpecialFolder is part of the static Environment class and DayOfWeek is sitting directly in the System namespace, but I'm having trouble finding any information on this. Normally static members would use the "static member operator", but that doesn't work in this case, nor does anything else I try except the mysterious plus character...
[System.DayOfWeek] # returns enum type
[enum]::GetValues([System.DayOfWeek]) # returns enum values
[enum]::GetValues([System.Environment.SpecialFolder]) # exception: unable to find type
[enum]::GetValues([System.Environment]::SpecialFolder) # exception: value cannot be null
[enum]::GetValues([System.Environment+SpecialFolder]) # returns enum values
System.Environment.SpecialFolder is definitely a type, and in C# both enums work the same way:
Enum.GetValues(typeof(System.Environment.SpecialFolder)) // works fine
Enum.GetValues(typeof(System.DayOfWeek)) // also works
I'd really like to understand why there's a distinction in Powershell and the reasoning behind this behaviour. Does anyone know why this is the case?

System.Environment.SpecialFolder is definitely a type
Type SpecialFolder, which is nested inside type Environment, is located in namespace System:
C# references that type as a full type name as in the quoted passage; that is, it uses . not only to separate the namespace from the containing type's name, but also to separate the latter from its nested type's name.
By contrast, PowerShell uses a .NET reflection method, Type.GetType(), to obtain a reference to the type at runtime:
That method uses a language-agnostic notation to identify types, as specified in documentation topic Specifying fully qualified type names.Tip of the hat to PetSerAl.
In that notation, it is + that is used to separate a nested type from its containing type (not ., as in C#).
That is, a PowerShell type literal ([...]) such as:
[System.Environment+SpecialFolder]
is effectively the same as taking the content between [ and ], System.Environment+SpecialFolder, and passing it as a string argument to Type.GetType, namely (expressed in PowerShell syntax):
[Type]::GetType('System.Environment+SpecialFolder')
Note that PowerShell offers convenient extensions (simplifications) to .NET's language-agnostic type notation, notably the ability to use PowerShell's type accelerators (such as [regex] for [System.Text.RegularExpressions.Regex]), the ability to omit the System. prefix from namespaces (e.g. [Collections.Generic.List`1[string]] instead of [System.Collections.Generic.List`1[string]]), and not having to specify the generic arity (e.g. `1) when a list of type argument is passed (e.g. [Collections.Generic.List[string]] instead of [Collections.Generic.List`1[string]] - see this answer) for more information.

Related

How to reference PSCredential.Empty in powershell script

I am trying to use empty credentials for anonymous access. How to I set a variable to empty credentials. I am trying to use PSCredential.Empty Property
Santiago Squarzon has provided the solution:
[pscredential]::Empty
is the PowerShell equivalent of C#'s PSCredential.Empty, i.e. access to the static Empty property of the System.Management.Automation.PSCredential type.
PowerShell's syntax for accessing .NET types and their - instance or static - member:
In order to refer to a .NET type by its literal name in PowerShell, you must specify it as a type literal, which is the type name enclosed in [...]
[pscredential] works as-is, even in the absence of a using namespace System.Management.Automation statement, because it happens to be a type accelerator, i.e. a frequently used type that you can access by a short, unqualified name (which can, but needn't be the same name as that of the type it references; e.g., [xml] is short for System.Xml.XmlDocument).
Generally, you either need a using namespace statement if you want to use the unqualified name only, or you need to use the namespace-qualified type name; e.g., [System.Management.Automation.PSCredential] or - given that the System. component is optional - [Management.Automation.PSCredential]
For a complete discussion of PowerShell's type literals, see this answer.
While instance members of .NET types are accessed with . (member-access operator), just like in C#, accessing static members requires a different operator: ::, the static member-access operator.
A distinct operator is necessary, because type literals are objects themselves, namely instances of System.Reflection.TypeInfo, so that using . accesses the latter's instance properties; e.g. [pscredential].FullName returns the type's namespace-qualified name.
Also note that, in keeping with PowerShell's general case-insensitive nature, neither type literals nor member names need be specified case-exactly.

how to assign MaxValue and MinValue to a variable in powershell

I tried these assignment statements below but none of them works.
$max_value = Integer.MaxValue
$max_value = Int32.MaxValue
$max_value = int.MaxValue
Santiago Squarzon provided the crucial pointer:
# Equivalent of the following C# code: int.MaxValue or System.Int32.MaxValue
[int]::MaxValue
[int] is a PowerShell type literal that refers to .NET's System.Int32 type, i.e. a signed, 32-bit integer.
:: is PowerShell's operator for accessing static type members (whereas . is used for instance members, as in C#).
Aside from requiring that literal type names be enclosed in [...], PowerShell's type literals have some non-obvious features:
Unlike in C#, case does not matter in PowerShell type literals. E.g., [system.io.fileinfo] can be used to refer to the System.IO.FileInfo type.
Analogous to C# providing short names for frequently used types - such as int for System.Int32 and string for System.String - PowerShell defines a range of short type names called type accelerators, listed in the conceptual about_Type_Accelerators help topic.
Case in point: as in C#, [int] refers to System.Int32, which you may therefore also reference as [System.Int32].
You can invoke .FullName on any given type literal to see the target type's full (namespace-qualified) name; e.g, [int].FullName returns string System.Int32. This relies on the fact that any type literal is itself an instance of the System.Type type.
Irrespective of type accelerators, you always have the option of omitting the System. component of a type's name, so that you may refer to System.Linq.Enumerable as just [Linq.Enumerable] instead of having to spell out [System.Linq.Enumerable], for instance.
In PowerShell version 5 and above (including PowerShell (Core) 7+), you may use a using namespace statement, which, analogous to C#'s using statement, allows you to refer to the types in the specified namespace by their mere name; e.g.:
# Important:
# * Must be at the *start* of a file.
# * The System. part may NOT be omitted in this case.
using namespace System.Linq
[Enumerable] # Short for: [System.Linq.Enumerable]
To learn more about type literals in PowerShell, including how to specify generic types, see the bottom section of this answer.

Reference .NET Generic Nested Type in Powershell Core

As the title suggests I am trying to reference a Nested Generic Type in Powershell Core.
I found that the + sign is used instead of the . for accessing a nested type in Powershell... but the syntax doesn't seem to work for "Nested Generic Types"... the compiler doesn't like the code an errors about the syntax.
Special use of plus (+) sign in Powershell
Has anyone been successful in getting this to work or is it a known limitation?
[System.Collections.Generic.Dictionary[[string], [int]]+Enumerator] GetEnumerator()
Daniel has provided the solution:
[System.Collections.Generic.Dictionary`2+Enumerator[string, int]]
returns the type of interest (note that the nested [...] around the individual generic type arguments, string and int, are optional).
That is, before being able to specify type arguments in order to construct a generic type, you must first specify its open form, which requires specifying the generic arity (the count of type arguments, <n>) in the form `<n> following the type name, namely `2 in the case of System.Collections.Generic.Dictionary<TKey,TValue> (expressed in C# notation), using the language-agnostic .NET API notation, as explained in this answer.
If no nested type (suffixed with +<typename>) is involved, specifying the arity is optional if all type arguments are specified; e.g., instead of [System.Collections.Generic.Dictionary`2[string, int]], [System.Collections.Generic.Dictionary[string, int]] is sufficient.
However, the enumerator type in question has no public constructor, so you cannot instantiate it directly; rather, it is the type returned when you call .GetEnumerator() on (a constructed form of) the enclosing type, [System.Collections.Generic.Dictionary`2]; verify with:
Get-Member -InputObject ([System.Collections.Generic.Dictionary[string, int]])::new().GetEnumerator()

Can't seem to use generic collection with a PowerShell class

I'm trying to invoke the List[T](IEnumerable) directly adding an item to the initial List like so, where T is a PowerShell class I've written (the below example uses the class name Thing:
$someObject = Get-Thing # returns a single object
$list = [List[Thing]]::new(#( $someObject ))
However, this yields an error suggesting it can't find the overload for this constructor:
Cannot find an overload for "List`1" and the argument count: "1".
Setting List[T] to the Object class works, however:
$someObject = Get-Thing
$list = [List[Object]]::new(#( $someObject ))
While this works, I'm unsure why I'm unable to use my PowerShell class as the type. My understanding is that only context-bound types and (by default) nested types are unable to be used with generics, but the following shows that my class is not a ContextBoundObject:
class Thing {
$Name
Thing($name) {
$this.Name = $name
}
}
$thing = [Thing]::new('Bender')
$thing -is [System.ContextBoundObject] # ==> False
I'm not certain if a PowerShell class would be a nested type of some sort, and about_Classes does not mention nested types.
I'm unsure why I'm unable to use my PowerShell class as the type
The array subexpression operator #() returns its results as [object[]] - a type which satisfies the argument type [IEnumerable[object]] - which is why it always works when you use [object] as the type parameter for the receiving collection type.
So, what to do about that?
If the array consists only of [Thing]'s, you can explicitly cast to a more specific collection type that implements [IEnumerable[Thing]]:
$list = [List[Thing]]::new([Thing[]]#( $someObject ))
To complement Mathias R. Jessen's helpful answer, which explains the problem well and offers an effective solution:
PowerShell's casts are not only syntactically more convenient, but also more flexible when it comes to on-demand type conversions.
Indeed, using a cast instead of calling a constructor, via the static ::new() method, does work:
using namespace System.Collections.Generic
class Thing { [string] $Name; Thing([string] $name) { $this.Name = $name } }
# Both of the following work:
# Single [Thing] instance.
$list = [List[Thing]] [Thing]::new('one')
# Multiple [Thing] instances, as an array, via the grouping operator, (...)
# #(...), the array subexpression operator, works too, but is unnecessary.
$list = [List[Thing]] ([Thing]::new('one'), [Thing]::new('two'))
PowerShell's automatic type conversions, as also used in casts:
Unfortunately, as of this writing the rules aren't documented, but a comment in the source-code provides a high-level overview, as does the (pretty low-level) ETS type converters documentation, which can be summarized as follows, in descending order of precedence:
First, engine-internal, fixed conversion rules may be applied (see source-code link above).
A notable internal rule concerns to-string conversions: while any .NET type supports it by an explicit call to its .ToString() method (inherited from the root of the object hierarchy, System.Object), PowerShell applies custom rules:
If a type has a culture-sensitive .ToString(<IFormatProvider>) overload, PowerShell passes the invariant culture deliberately, to achieve a culture-invariant representation, whereas a direct .ToString() call would yield a culture-sensitive representation - see this answer for details; e.g., in a culture where , is the decimal mark, [string] 1.2 returns '1.2' (period), whereas (1.2).ToString() returns '1,2' (comma).
Collections, including arrays, are stringified by concatenating their (stringified) elements with a space as the separator (by default, can be overridden with preference variable $OFS); e.g., [string] (1, 2) returns 1 2, whereas (1, 2).ToString() returns merely System.Object[].
Also, PowerShell converts freely:
between different number types (when possible).
between numbers and strings (in a culture-invariant manner, recognizing only . as the decimal mark when converting from a string).
and allows any data type to be converted to (interpreted as) as Boolean - see the bottom section of this answer for the rules.
Next, TypeConverter or (PSTypeConverter) classes that implement custom conversions for specific types are considered.
If the input type is a string ([string]), a static ::Parse() method is considered, if present: first, one with a culture-sensitive signature, ::Parse(<string>, <IFormatProvider>), in which case the invariant culture is passed, and, otherwise one with signature ::Parse(<string>).
Next, a single-argument constructor is considered, if the input type matches the argument's type or is convertible to it.
If an implicit or explicit conversion operator exists for conversion between the input and the target type.
Finally, if the input object implements the System.IConvertible interface and the target type is a supported-by-the-implementation primitive .NET type except [IntPtr] and [UIntPtr] or one of the following types: [datetime], [DBNull], [decimal].

Interaction with enum members in swift-based app

I'm beginning to teach myself swift and I'm going through examples of games at the moment. I've run across a line of code that I thought was peculiar
scene.scaleMode = .ResizeFill
In languages I'm used to (C / Java) the "." notation is used to reference some sort of structure/ object but I'm not exactly sure what this line of code does as there is no specified object explicitly before the "."
Information regarding clarification of this non-specified "." reference, or when/ how it can be used, would be great
P.S. I'm using sprite kit in Xcode
In Swift, as in the other languages you mentioned, '.' is a member access operator. The syntax you are referring to is a piece of shorthand that Swift allows because it is a type-safe language.
The compiler recognises that the property you are assigning to is of type SKSceneScaleMode and so the value you are assigning must be one of that type's enumerated values - so the enumeration name can be omitted.
To add to PaulW11's answer, what's happening here is only valid syntax for enums, and won't work with any other type (class, struct, method, function). Swift knows the type of the property that you are assigning to is an enum of type SKSceneScaleMode, so lets you refer to the enum member without having to explicitly give the type of the enum (ie SKSceneScaleMode.ResizeFill).
There are some situations where there will be ambiguity, and you will have to give the full name, this will be dependant on the context. For example, you may have two different enum types in scope, that both have a matching member name.
EDIT
Updating this answers as I incorrectly specified this was only applicable to enums, which is not true. There is a good blog post here which explains in more detail
http://ericasadun.com/2015/04/21/swift-occams-code-razor/