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.
Related
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.
I can use Get-Item with folders, files and registry keys, and the type of the object I get back will make sense; [System.IO.DirectoryInfo], [System.IO.FileInfo] or [Microsoft.Win32.RegistryKey].
But with registry properties, what using Get-ItemProperty returns is a [System.Management.Automation.PSCustomObject]. Is this because there is no dedicated type for registry property? That seems odd. But my Google-Fu is not turning anything up.
My use case is this, I am doing a series of Copy and Move tasks, with all four item types potentially getting copied or moved, and I want to implement an option to rename an existing destination rather than overwriting or failing. And exactly what the rename options are depends on the object type. And from a readability standpoint, PSCustom Object or a simple else for RegistryProperty is a bit ugly. So, looking for a way to get the property back as a type with a more obvious name, so when I look at the code again in 12 months it makes some sense.
Get-ItemProperty returns what is conceptually a registry value object: a property of a registry key that has a name and a - uh... - value (the named value object's data).
The .NET registry API has no type to represent such a value object - instead, it allows access via the registry key type's .GetValue($valueName) (to get a specific value object's data[1]) and .GetValueNames() methods (to get the list of all value names).
The PowerShell implementers apparently chose not to implement their own .NET type, and chose to use PowerShell's general-purpose, dynamic "property-bag" type, [pscustomobject][2] to model these value objects.
If you want to avoid the [pscustomobject] instances that Get-ItemProperty returns, you can use Get-Item instead, which returns a Microsoft.Win32.RegistryKey instance, i.e. an instance of the .NET type representing a key, on which you can invoke the methods mentioned above.
As an aside: If you're just interested in a given value object's data, you can use the PSv5+
Get-ItemPropertyValue cmdlet (e.g.
Get-ItemPropertyValue HKCU:\Console -Name LineWrap directly returns the [int] data of the targeted value).
[1] Additionally, as js2010's answer shows, the .GetValueKind() method returns an enum value that identifies a given value object's registry-specific data type. These types imply what .NET types are used to represent them, as returned by .GetValue(), but in some cases have no direct equivalent (ExpandString, MultiString, Unknown) and require additional work to interpret them correctly.
[2] It is possible - but wasn't done in this case - to assign (one or more) self-chosen type names to [pscustomobject] instances, which PowerShell reflects as the type name in Get-Member output (only the first, if there are multiple) and which it respects for ETS type definitions and format-data definitions. However, such pseudo types are not accessible as type literals; e.g.: $obj = [pscustomobject] #{ PSTypeName = 'MyType'; prop = 'foo' } allows you test for this type name with $obj.pstypenames -contains 'MyType', but not with $obj -is [MyType]. That said, you can base parameter declarations on them, via the [PSTypeName()] attribute.
There is a way to get the type of the properties:
$key = get-item hkcu:\key1
$key.GetValueKind('value1')
DWord
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()
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].
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.