#if CORECLR
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace System.Management.Automation
{
#region Reflection and Type related extensions
#region Enums
[Flags]
internal enum MemberTypes
{
Constructor = 0x01,
Event = 0x02,
Field = 0x04,
Method = 0x08,
Property = 0x10,
All = 0xbf,
}
#endregion Enums
///
/// The type extension methods within this partial class are only used for CoreCLR powershell.
///
/// * If you want to add an extension method that will be used by both FullCLR and CoreCLR powershell, please
/// add it to the 'PSTypeExtensions' partial class in 'ExtensionMethods.cs'.
/// * If you want to add an extension method that will be used only by CoreCLR powershell, please add it here.
///
internal static partial class PSTypeExtensions
{
#region Miscs
internal static bool IsSubclassOf(this Type targetType, Type type)
{
return targetType.GetTypeInfo().IsSubclassOf(type);
}
#endregion Miscs
#region Interface
internal static Type GetInterface(this Type type, string name)
{
// The search is case-sensitive, as it's in the full CLR version
return GetInterface(type, name, false);
}
internal static Type GetInterface(this Type type, string name, bool ignoreCase)
{
var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
return type.GetTypeInfo().ImplementedInterfaces.FirstOrDefault(
implementedInterface => String.Equals(name, implementedInterface.Name, stringComparison));
}
#endregion Interface
#region Member
internal static MemberInfo[] GetMember(this Type type, string name, MemberTypes memberType, BindingFlags bindingAttr)
{
if (bindingAttr == 0)
{
return new MemberInfo[0];
}
var members = new List();
if ((memberType & MemberTypes.Field) != 0)
{
var fields = type.GetFields(name, bindingAttr);
if (fields != null)
{
for (int i = 0; i < fields.Length; i++)
{
members.Add(fields[i]);
}
}
}
if ((memberType & MemberTypes.Property) != 0)
{
var properties = type.GetProperties(name, bindingAttr);
if (properties != null)
{
for (int i = 0; i < properties.Length; i++)
{
members.Add(properties[i]);
}
}
}
return members.ToArray();
}
#endregion Member
#region Field
internal static FieldInfo[] GetFields(this Type type, string name, BindingFlags bindingFlags)
{
return GetFields(type, name, bindingFlags, false);
}
///
/// GetFields
///
internal static FieldInfo[] GetFields(this Type type, string name, BindingFlags bindingFlags, bool isNameNull)
{
if (!isNameNull && (name == null || (name = name.Trim()) == ""))
{
throw new PSArgumentNullException("name");
}
if (bindingFlags == 0)
{
return null;
}
Type currentType = type;
StringComparison strCompare = (bindingFlags & BindingFlags.IgnoreCase) != 0
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
var fields = new List();
bool isInHierarchy = false;
do
{
TypeInfo currentTypeInfo = currentType.GetTypeInfo();
foreach (FieldInfo field in currentTypeInfo.DeclaredFields)
{
if (!isNameNull && !String.Equals(name, field.Name, strCompare))
{
continue;
}
if (((bindingFlags & BindingFlags.Instance) != 0 && !field.IsStatic) ||
((bindingFlags & BindingFlags.Static) != 0 && field.IsStatic))
{
if (isInHierarchy)
{
// Specify BindingFlags.FlattenHierarchy to include public and protected static members up the hierarchy;
// private static members in inherited classes are not included
if (!field.IsPublic && !(field.IsFamily && field.IsStatic))
{
continue;
}
}
if ((bindingFlags & BindingFlags.Public) != 0 && field.IsPublic)
{
fields.Add(field);
continue;
}
if ((bindingFlags & BindingFlags.NonPublic) != 0 && !field.IsPublic)
{
fields.Add(field);
}
}
}
if ((bindingFlags & BindingFlags.FlattenHierarchy) != 0 && (bindingFlags & BindingFlags.DeclaredOnly) == 0)
{
isInHierarchy = true;
currentType = currentTypeInfo.BaseType;
}
else
{
currentType = null;
}
} while (currentType != null);
return fields.ToArray();
}
#endregion Field
#region Property
internal static PropertyInfo[] GetProperties(this Type type, string name, BindingFlags bindingFlags)
{
return GetProperties(type, name, bindingFlags, false);
}
///
/// GetProperty
///
internal static PropertyInfo[] GetProperties(this Type type, string name, BindingFlags bindingFlags, bool isNameNull)
{
if (!isNameNull && (name == null || (name = name.Trim()) == ""))
{
throw new PSArgumentNullException("name");
}
if (bindingFlags == 0)
{
return null;
}
Type currentType = type;
StringComparison strCompare = (bindingFlags & BindingFlags.IgnoreCase) != 0
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
var properties = new List();
bool isInHierarchy = false;
do
{
TypeInfo currentTypeInfo = currentType.GetTypeInfo();
foreach (PropertyInfo property in currentTypeInfo.DeclaredProperties)
{
if (!isNameNull && !String.Equals(name, property.Name, strCompare))
{
continue;
}
if (((bindingFlags & BindingFlags.Instance) != 0 && IsInstanceProperty(property)) ||
((bindingFlags & BindingFlags.Static) != 0 && IsStaticProperty(property)))
{
if (isInHierarchy)
{
// Specify BindingFlags.FlattenHierarchy to include public and protected static members up the hierarchy;
// private static members in inherited classes are not included
if (!IsPublicProperty(property) && !(IsProtectedProperty(property) && IsStaticProperty(property)))
{
continue;
}
}
if ((bindingFlags & BindingFlags.Public) != 0 && IsPublicProperty(property))
{
properties.Add(property);
continue;
}
if ((bindingFlags & BindingFlags.NonPublic) != 0 && IsNonPublicProperty(property))
{
properties.Add(property);
continue;
}
}
}
if ((bindingFlags & BindingFlags.FlattenHierarchy) != 0 && (bindingFlags & BindingFlags.DeclaredOnly) == 0)
{
isInHierarchy = true;
currentType = currentTypeInfo.BaseType;
}
else
{
currentType = null;
}
} while (currentType != null);
return properties.ToArray();
}
#region Property Helper Methods
private static bool IsInstanceProperty(PropertyInfo property)
{
if (property.GetMethod != null && property.GetMethod.IsStatic)
{
return false;
}
if (property.SetMethod != null && property.SetMethod.IsStatic)
{
return false;
}
if (property.GetMethod == null && property.SetMethod == null)
{
return false;
}
return true;
}
private static bool IsStaticProperty(PropertyInfo property)
{
if (property.GetMethod != null && !property.GetMethod.IsStatic)
{
return false;
}
if (property.SetMethod != null && !property.SetMethod.IsStatic)
{
return false;
}
if (property.GetMethod == null && property.SetMethod == null)
{
return false;
}
return true;
}
private static bool IsPublicProperty(PropertyInfo property)
{
if ((property.GetMethod != null && property.GetMethod.IsPublic) || (property.SetMethod != null && property.SetMethod.IsPublic))
{
return true;
}
return false;
}
private static bool IsNonPublicProperty(PropertyInfo property)
{
if (property.GetMethod == null && property.SetMethod == null)
{
return false;
}
if (property.GetMethod != null && property.GetMethod.IsPublic)
{
return false;
}
if (property.SetMethod != null && property.SetMethod.IsPublic)
{
return false;
}
return true;
}
private static bool IsProtectedProperty(PropertyInfo property)
{
if (property.GetMethod == null && property.SetMethod == null)
{
return false;
}
if (property.GetMethod != null && !property.GetMethod.IsFamily)
{
return false;
}
if (property.SetMethod != null && !property.SetMethod.IsFamily)
{
return false;
}
return true;
}
#endregion Property Helper Methods
#endregion Property
#region Constructor
///
/// Search for a constructor that matches the specified bindingFlags and parameter types
///
internal static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, string binderNotUsed, Type[] types, string modifiersNotUsed)
{
if (binderNotUsed != null || modifiersNotUsed != null)
{
throw new ArgumentException("Parameters 'binder' and 'modifier' should not be used");
}
if (types == null || types.Any(element => element == null))
{
throw new ArgumentNullException("types");
}
ConstructorInfo[] results = GetConstructors(type, bindingFlags, null);
return results != null ? GetMatchingConstructor(results, types) : null;
}
internal static ConstructorInfo GetConstructor(this Type type, BindingFlags bindingFlags, string binderNotUsed,
CallingConventions callConvention, Type[] types, string modifiersNotUsed)
{
if (binderNotUsed != null || modifiersNotUsed != null)
{
throw new ArgumentException("Parameters 'binder' and 'modifier' should not be used");
}
if (types == null || types.Any(element => element == null))
{
throw new ArgumentNullException("types");
}
ConstructorInfo[] results = GetConstructors(type, bindingFlags, callConvention);
return results != null ? GetMatchingConstructor(results, types) : null;
}
///
/// Helper method - Get the matching constructor based on the parameter types
///
private static ConstructorInfo GetMatchingConstructor(ConstructorInfo[] constructors, Type[] types)
{
// Compare the parameter types in two passes.
// The first pass is to check if the parameter types are exactly the same,
// The second pass is to check if the parameter types is assignable from the given argument types.
var matchConstructors = new List();
bool inSecondPass = false;
do
{
// Use 'for' loop to avoid construct new ArrayEnumerator object
for (int constorIndex = 0; constorIndex < constructors.Length; constorIndex++)
{
var constor = constructors[constorIndex];
ParameterInfo[] parameters = constor.GetParameters();
if (types.Length == parameters.Length)
{
bool success = true;
for (int typeIndex = 0; typeIndex < types.Length; typeIndex++)
{
if (!IsParameterTypeMatching(parameters[typeIndex].ParameterType, types[typeIndex], inSecondPass))
{
success = false;
break;
}
}
if (success)
{
matchConstructors.Add(constor);
}
}
}
// Flip the 'inSecondPass' flag, so that we run another pass only if we're about
// to start the second pass and we didn't find anything from the first pass.
inSecondPass = !inSecondPass;
} while (matchConstructors.Count == 0 && inSecondPass);
if (matchConstructors.Count > 1)
{
throw new AmbiguousMatchException();
}
return matchConstructors.Count == 1 ? matchConstructors[0] : null;
}
///
/// Constructors defined in the current type
///
internal static ConstructorInfo[] GetConstructors(this Type type, BindingFlags bindingFlags, CallingConventions? callConvention)
{
if ((bindingFlags & BindingFlags.FlattenHierarchy) != 0)
{
throw new PSArgumentException("Invalid binding flags");
}
if (((bindingFlags & BindingFlags.Instance) != 0 && (bindingFlags & BindingFlags.Static) != 0) ||
((bindingFlags & BindingFlags.Instance) == 0 && (bindingFlags & BindingFlags.Static) == 0))
{
throw new PSArgumentException("Invalid binding flags");
}
// If bindingFlags is zero, return null.
if (bindingFlags == 0)
{
return null;
}
// If type is a generic parameter, return empty array
if (type.IsGenericParameter)
{
return new ConstructorInfo[0];
}
var ctors = new List();
foreach (ConstructorInfo ctor in type.GetTypeInfo().DeclaredConstructors)
{
/* CallingConventions is different on CoreCLR ...
* TODO -- find out how different and what problem it causes.
if (callConvention.HasValue && ctor.CallingConvention != callConvention.Value)
{
continue;
}
*/
if ((bindingFlags & BindingFlags.Instance) != 0 && ctor.IsStatic)
{
continue;
}
if ((bindingFlags & BindingFlags.Static) != 0 && !ctor.IsStatic)
{
continue;
}
if ((bindingFlags & BindingFlags.Public) != 0 && ctor.IsPublic)
{
ctors.Add(ctor);
continue;
}
if ((bindingFlags & BindingFlags.NonPublic) != 0 && !ctor.IsPublic)
{
ctors.Add(ctor);
continue;
}
}
return ctors.ToArray();
}
#endregion Constructor
#region Method
internal static MethodInfo GetMethod(this Type targetType, string name, BindingFlags bindingFlags, string binderNotUsed, Type[] types, string modifierNotUsed)
{
if (binderNotUsed != null || modifierNotUsed != null)
{
throw new ArgumentException("Parameters 'binderNotUsed' and 'modifier_NotUsed' should not be used.");
}
if (types == null || types.Any(element => element == null))
{
throw new ArgumentNullException("types");
}
MethodInfo[] methods = GetMethods(targetType, name, bindingFlags);
return methods != null ? GetMatchingMethod(methods, types) : null;
}
internal static MethodInfo GetMethod(this Type targetType, string name, BindingFlags bindingFlags, string binderNotUsed, CallingConventions callConvention, Type[] types, string modifierNotUsed)
{
if (binderNotUsed != null || modifierNotUsed != null)
{
throw new ArgumentException("Parameters 'binderNotUsed' and 'modifier_NotUsed' should not be used.");
}
if (types == null || types.Any(element => element == null))
{
throw new ArgumentNullException("types");
}
MethodInfo[] methods = GetMethods(targetType, name, bindingFlags, false, callConvention);
return methods != null ? GetMatchingMethod(methods, types) : null;
}
// Helper method
private static MethodInfo GetMatchingMethod(MethodInfo[] methods, Type[] types)
{
// Compare the parameter types in two passes.
// The first pass is to check if the parameter types are exactly the same,
// The second pass is to check if the parameter types is assignable from the given argument types.
var matchMethods = new List();
bool inSecondPass = false;
do
{
// Use for loop to avoid construct new ArrayEnumerator object
for (int methodIndex = 0; methodIndex < methods.Length; methodIndex++)
{
var method = methods[methodIndex];
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == types.Length)
{
bool success = true;
for (int typeIndex = 0; typeIndex < types.Length; typeIndex++)
{
if (!IsParameterTypeMatching(parameters[typeIndex].ParameterType, types[typeIndex], inSecondPass))
{
success = false;
break;
}
}
if (success)
{
matchMethods.Add(method);
}
}
}
// Flip the 'inSecondPass' flag, so that we run another pass only if we're about
// to start the second pass and we didn't find anything from the first pass.
inSecondPass = !inSecondPass;
} while (matchMethods.Count == 0 && inSecondPass);
if (matchMethods.Count > 1)
{
throw new AmbiguousMatchException();
}
return matchMethods.Count == 1 ? matchMethods[0] : null;
}
private static bool IsParameterTypeMatching(Type paramType, Type argType, bool inSecondPass)
{
return inSecondPass
? paramType.IsAssignableFrom(argType)
: paramType == argType;
}
internal static MethodInfo[] GetMethods(this Type type, string name, BindingFlags bindingFlags)
{
return GetMethods(type, name, bindingFlags, false, null);
}
internal static MethodInfo[] GetMethods(this Type type, string name, BindingFlags bindingFlags, bool isNameNull, CallingConventions? callConvention)
{
if (!isNameNull && (name == null || (name = name.Trim()) == ""))
{
throw new ArgumentNullException("name");
}
if (bindingFlags == 0)
{
return null;
}
Type currentType = type;
StringComparison strCompare = (bindingFlags & BindingFlags.IgnoreCase) != 0
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
var methods = new List();
bool isInHierarchy = false;
do
{
TypeInfo currentTypeInfo = currentType.GetTypeInfo();
foreach (MethodInfo method in currentTypeInfo.DeclaredMethods)
{
if (!isNameNull && !String.Equals(name, method.Name, strCompare))
{
continue;
}
if (callConvention.HasValue && method.CallingConvention != callConvention.Value)
{
continue;
}
if (((bindingFlags & BindingFlags.Instance) != 0 && !method.IsStatic) ||
((bindingFlags & BindingFlags.Static) != 0 && method.IsStatic))
{
if (isInHierarchy)
{
// Specify BindingFlags.FlattenHierarchy to include public and protected static members up the hierarchy;
// private static members in inherited classes are not included
if (!method.IsPublic && !(method.IsFamily && method.IsStatic))
{
continue;
}
}
if ((bindingFlags & BindingFlags.Public) != 0 && method.IsPublic)
{
methods.Add(method);
continue;
}
if ((bindingFlags & BindingFlags.NonPublic) != 0 && !method.IsPublic)
{
methods.Add(method);
}
}
}
if ((bindingFlags & BindingFlags.FlattenHierarchy) != 0 && (bindingFlags & BindingFlags.DeclaredOnly) == 0)
{
isInHierarchy = true;
currentType = currentTypeInfo.BaseType;
}
else
{
currentType = null;
}
} while (currentType != null);
return methods.ToArray();
}
#endregion Method
#region TypeCode
private static readonly Dictionary TypeCodeMap =
new Dictionary()
{
// 'DBNull = 2' is removed from 'System.TypeCode' in CoreCLR. We return
// '(TypeCode)2' for 'System.DBNull' to avoid any breaking changes.
{typeof(DBNull), (TypeCode)2},
{typeof(Boolean),TypeCode.Boolean},
{typeof(Char),TypeCode.Char},
{typeof(sbyte),TypeCode.SByte},
{typeof(byte), TypeCode.Byte},
{typeof(Int16),TypeCode.Int16},
{typeof(UInt16),TypeCode.UInt16},
{typeof(Int32),TypeCode.Int32},
{typeof(UInt32),TypeCode.UInt32},
{typeof(Int64),TypeCode.Int64},
{typeof(UInt64),TypeCode.UInt64},
{typeof(Single),TypeCode.Single},
{typeof(Double),TypeCode.Double},
{typeof(string),TypeCode.String},
{typeof(Decimal),TypeCode.Decimal},
{typeof(DateTime),TypeCode.DateTime},
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static TypeCode GetTypeCodeInCoreClr(Type type)
{
if (type == null)
return TypeCode.Empty;
if (TypeCodeMap.ContainsKey(type))
return TypeCodeMap[type];
if (type.GetTypeInfo().IsEnum)
return GetTypeCode(Enum.GetUnderlyingType(type));
return TypeCode.Object;
}
#endregion TypeCode
}
#endregion Reflection and Type related extensions
#region Environment Extensions
// TODO:CORECLR - Environment Extensions need serious work to refine.
internal enum EnvironmentVariableTarget
{
Process,
User,
Machine
}
internal static partial class Environment
{
#region Forward_To_System.Environment
#region Properties
public static int CurrentManagedThreadId
{
get
{
return System.Environment.CurrentManagedThreadId;
}
}
public static bool HasShutdownStarted
{
get
{
return System.Environment.HasShutdownStarted;
}
}
public static string NewLine
{
get
{
return System.Environment.NewLine;
}
}
public static int ProcessorCount
{
get
{
return System.Environment.ProcessorCount;
}
}
public static string StackTrace
{
get
{
return System.Environment.StackTrace;
}
}
public static int TickCount
{
get
{
return System.Environment.TickCount;
}
}
#endregion Properties
#region Methods
public static string ExpandEnvironmentVariables(string name)
{
return System.Environment.ExpandEnvironmentVariables(name);
}
public static void FailFast(string message)
{
System.Environment.FailFast(message);
}
public static void FailFast(string message, Exception exception)
{
System.Environment.FailFast(message, exception);
}
public static string GetEnvironmentVariable(string variable)
{
string value = System.Environment.GetEnvironmentVariable(variable);
// Porting note: if not otherwise defined, map Windows environment
// variables to their corresponding Linux counterparts
if (!Platform.IsWindows && String.IsNullOrEmpty(value))
{
switch (variable)
{
case "OS":
return "Linux";
case "COMPUTERNAME":
return System.Environment.GetEnvironmentVariable("HOSTNAME");
case "USERNAME":
return System.Environment.GetEnvironmentVariable("USER");
case "HOMEPATH":
case "USERPROFILE":
return System.Environment.GetEnvironmentVariable("HOME");
case "TMP":
case "TEMP":
return System.Environment.GetEnvironmentVariable("TMPDIR");
default:
break;
}
}
return value;
}
public static IDictionary GetEnvironmentVariables()
{
return System.Environment.GetEnvironmentVariables();
}
public static void SetEnvironmentVariable(string variable, string value)
{
System.Environment.SetEnvironmentVariable(variable, value);
}
#endregion Methods
#endregion Forward_To_System.Environment
private const int MaxMachineNameLength = 256;
private static string[] commandLineArgs = new string[0];
public static string[] GetCommandLineArgs()
{
return commandLineArgs;
}
#region EnvironmentVariable_Extensions
///
/// The code is mostly copied from the .NET implementation.
/// The only difference is how resource string is retrieved.
/// We use the same resource string as in .NET implementation.
///
public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
{
if (target == EnvironmentVariableTarget.Process)
{
return GetEnvironmentVariables();
}
#if LINUX
return null;
#else
if( target == EnvironmentVariableTarget.Machine)
{
using (RegistryKey environmentKey =
Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false))
{
return GetRegistryKeyNameValuePairs(environmentKey);
}
}
else // target == EnvironmentVariableTarget.User
{
using (RegistryKey environmentKey =
Registry.CurrentUser.OpenSubKey("Environment", false))
{
return GetRegistryKeyNameValuePairs(environmentKey);
}
}
#endif
}
///
/// The code is mostly copied from the .NET implementation.
/// The only difference is how resource string is retrieved.
/// We use the same resource string as in .NET implementation.
///
internal static IDictionary GetRegistryKeyNameValuePairs(RegistryKey registryKey)
{
Hashtable table = new Hashtable(20);
if (registryKey != null)
{
string[] names = registryKey.GetValueNames();
foreach (string name in names)
{
string value = registryKey.GetValue(name, "").ToString();
table.Add(name, value);
}
}
return table;
}
///
/// The code is mostly copied from the .NET implementation.
/// The only difference is how resource string is retrieved.
/// We use the same resource string as in .NET implementation.
///
public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target)
{
if (variable == null)
{
throw new ArgumentNullException("variable");
}
if (target == EnvironmentVariableTarget.Process)
{
return System.Environment.GetEnvironmentVariable(variable);
}
#if LINUX
return null;
#else
if (target == EnvironmentVariableTarget.Machine)
{
using (RegistryKey environmentKey =
Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Session Manager\Environment", false))
{
if (environmentKey == null) { return null; }
string value = environmentKey.GetValue(variable) as string;
return value;
}
}
else // target == EnvironmentVariableTarget.User
{
using (RegistryKey environmentKey = Registry.CurrentUser.OpenSubKey("Environment", false))
{
if (environmentKey == null) { return null; }
string value = environmentKey.GetValue(variable) as string;
return value;
}
}
#endif
}
#endregion EnvironmentVariable_Extensions
#region Property_Extensions
internal static string WinGetUserDomainName()
{
StringBuilder domainName = new StringBuilder(1024);
uint domainNameLen = (uint)domainName.Capacity;
byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen);
if (ret == 1)
{
string samName = domainName.ToString();
int index = samName.IndexOf('\\');
if (index != -1)
{
return samName.Substring(0, index);
}
}
else
{
int errorCode = Marshal.GetLastWin32Error();
throw new InvalidOperationException(Win32Native.GetMessage(errorCode));
}
// Cannot use LookupAccountNameW to get DomainName because 'GetUserName' is not available in CSS and thus we cannot get the account.
throw new InvalidOperationException(CoreClrStubResources.CannotGetDomainName);
}
///
/// UserDomainName
///
public static string UserDomainName
{
get
{
if (Platform.IsWindows)
{
return WinGetUserDomainName();
}
else
{
return Platform.NonWindowsGetDomainName();
}
}
}
internal static string WinGetUserName()
{
StringBuilder domainName = new StringBuilder(1024);
uint domainNameLen = (uint)domainName.Capacity;
byte ret = Win32Native.GetUserNameEx(Win32Native.NameSamCompatible, domainName, ref domainNameLen);
if (ret == 1)
{
string samName = domainName.ToString();
int index = samName.IndexOf('\\');
if (index != -1)
{
return samName.Substring(index + 1);
}
}
return string.Empty;
}
///
/// UserName
///
public static string UserName
{
get
{
if (Platform.IsWindows)
{
return WinGetUserName();
}
else
{
return Platform.NonWindowsGetUserName();
}
}
}
///
/// MachineName
///
public static string MachineName
{
get
{
return System.Environment.MachineName;
}
}
///
/// OSVersion
///
public static OperatingSystem OSVersion
{
get
{
if (m_os == null)
{
if (Platform.IsWindows)
{
m_os = WinOSVersion;
}
else
{
// TODO:PSL use P/Invoke to provide proper version
// Porting note: cannot put this in CorePsPlatform since
// System.Management.Automation.Environment only exists in CoreCLR
// builds of monad.
m_os = new Environment.OperatingSystem(new Version(1,0,0,0),"");
}
}
return m_os;
}
}
private static volatile OperatingSystem m_os;
///
/// Windows OSVersion implementation
///
private static OperatingSystem WinOSVersion
{
get
{
Win32Native.OSVERSIONINFOEX osviex = new Win32Native.OSVERSIONINFOEX();
osviex.OSVersionInfoSize = Marshal.SizeOf(osviex);
if (!Win32Native.GetVersionEx(ref osviex))
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode);
}
Version v = new Version(osviex.MajorVersion, osviex.MinorVersion, osviex.BuildNumber, (osviex.ServicePackMajor << 16) | osviex.ServicePackMinor);
return new OperatingSystem(v, osviex.CSDVersion);
}
}
#endregion Property_Extensions
#region SpecialFolder_Extensions
///
/// The code is copied from the .NET implementation.
///
public static string GetFolderPath(SpecialFolder folder)
{
return InternalGetFolderPath(folder);
}
///
/// The API set 'api-ms-win-shell-shellfolders-l1-1-0.dll' was removed from NanoServer, so we cannot depend on 'SHGetFolderPathW'
/// to get the special folder paths. Instead, we need to rely on the baisc environment variables to get the special folder paths.
///
///
/// The path to the specified system special folder, if that folder physically exists on your computer.
/// Otherwise, an empty string ("").
///
private static string InternalGetFolderPath(SpecialFolder folder)
{
if (!Platform.IsWindows)
{
return Platform.NonWindowsGetFolderPath(folder);
}
// The API 'SHGetFolderPath' is not available on OneCore, so we have to rely on environment variables
string folderPath = null;
string systemRoot = null;
string userProfile = null;
switch (folder)
{
case SpecialFolder.ProgramFiles:
folderPath = System.Environment.GetEnvironmentVariable("ProgramFiles");
if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; }
break;
case SpecialFolder.ProgramFilesX86:
folderPath = System.Environment.GetEnvironmentVariable("ProgramFiles(x86)");
if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; }
break;
case SpecialFolder.System:
systemRoot = System.Environment.GetEnvironmentVariable("SystemRoot");
if (systemRoot != null)
{
folderPath = System.IO.Path.Combine(systemRoot, "system32");
if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; }
}
break;
case SpecialFolder.SystemX86:
systemRoot = System.Environment.GetEnvironmentVariable("SystemRoot");
if (systemRoot != null)
{
folderPath = System.IO.Path.Combine(systemRoot, "SysWOW64");
if (!System.IO.Directory.Exists(folderPath)) { folderPath = null; }
}
break;
case SpecialFolder.MyDocuments: // same as SpecialFolder.Personal
userProfile = System.Environment.GetEnvironmentVariable("USERPROFILE");
if (userProfile != null)
{
folderPath = System.IO.Path.Combine(userProfile, "Documents");
// CSS doesn't include a Documents directory for each user, so we create one if needed.
if (!System.IO.Directory.Exists(folderPath)) { System.IO.Directory.CreateDirectory(folderPath); }
}
break;
case SpecialFolder.LocalApplicationData:
folderPath = System.Environment.GetEnvironmentVariable("LOCALAPPDATA");
// When powershell gets executed in SetupComplete.cmd during NanoSrever's first boot, 'LOCALAPPDATA' won't be set yet.
// In this case, we need to return an alternate path, so that module auto-loading can continue to work properly.
if (folderPath == null)
{
// It's guaranteed by NanoServer team that 'USERPROFILE' will be already set when SetupComplete.cmd runs.
// So we use the path '%USERPROFILE%\AppData\Local' as an alternative in this case, and also set the env
// variable %LOCALAPPDATA% to it, so that modules running in PS can depend on this env variable.
userProfile = System.Environment.GetEnvironmentVariable("USERPROFILE");
if (userProfile != null)
{
string alternatePath = System.IO.Path.Combine(userProfile, @"AppData\Local");
if (System.IO.Directory.Exists(alternatePath))
{
System.Environment.SetEnvironmentVariable("LOCALAPPDATA", alternatePath);
folderPath = alternatePath;
}
}
}
else if (!System.IO.Directory.Exists(folderPath))
{
folderPath = null;
}
break;
default:
throw new NotSupportedException();
}
return folderPath ?? string.Empty;
}
#endregion SpecialFolder_Extensions
#region NativeMethods
///
/// DllImport uses the ApiSet dll that is available on CSS, since this code
/// will only be included when building targeting CoreCLR.
///
internal static class Win32Native
{
internal const int NameSamCompatible = 2; // EXTENDED_NAME_FORMAT - NameSamCompatible
private const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
private const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
[DllImport("SspiCli.dll", CharSet = CharSet.Unicode, SetLastError = true)]
// Win32 return type is BOOLEAN (which is 1 byte and not BOOL which is 4bytes)
internal static extern byte GetUserNameEx(int format, [Out] StringBuilder domainName, ref uint domainNameLen);
[DllImport("api-ms-win-core-localization-l1-2-1.dll", CharSet = CharSet.Unicode)]
internal static extern int FormatMessage(int dwFlags, IntPtr lpSource, int dwMessageId,
int dwLanguageId, [Out]StringBuilder lpBuffer,
int nSize, IntPtr va_list_arguments);
[DllImport("api-ms-win-core-sysinfo-l1-2-1.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool GetVersionEx(ref OSVERSIONINFOEX osVerEx);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct OSVERSIONINFOEX
{
// The OSVersionInfoSize field must be set to Marshal.SizeOf(this)
public int OSVersionInfoSize;
public int MajorVersion;
public int MinorVersion;
public int BuildNumber;
public int PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string CSDVersion;
public ushort ServicePackMajor;
public ushort ServicePackMinor;
public short SuiteMask;
public byte ProductType;
public byte Reserved;
}
///
/// The code is mostly copied from the .NET implementation.
/// The only difference is how resource string is retrieved.
/// We use the same resource string as in .NET implementation.
///
internal static string GetMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(512);
int result = Win32Native.FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
if (result != 0)
{
return sb.ToString();
}
else
{
return string.Format(CultureInfo.CurrentCulture, CoreClrStubResources.UnknownErrorNumber, errorCode);
}
}
}
#endregion NativeMethods
#region NestedTypes
// Porting note: MyDocuments does not exist on .NET Core, but Personal does, and
// they both point to your "documents repository," which on linux, is just the
// home directory.
///
/// It only contains the values that get used in powershell
///
internal enum SpecialFolder
{
Personal = 0x05,
MyDocuments = 0x05,
LocalApplicationData = 0x1c,
ProgramFiles = 0x26,
ProgramFilesX86 = 0x2a,
System = 0x25,
SystemX86 = 0x29,
}
///
/// It only contains the properties that get used in powershell
///
internal sealed class OperatingSystem
{
private Version _version;
private string _servicePack;
private string _versionString;
internal OperatingSystem(Version version, string servicePack)
{
if (version == null)
throw new ArgumentNullException("version");
_version = version;
_servicePack = servicePack;
}
///
/// OS version
///
public Version Version
{
get { return _version; }
}
///
/// VersionString
///
public string VersionString
{
get
{
if (_versionString != null)
{
return _versionString;
}
// It's always 'VER_PLATFORM_WIN32_NT' for NanoServer and IoT
const string os = "Microsoft Windows NT ";
if (string.IsNullOrEmpty(_servicePack))
{
_versionString = os + _version.ToString();
}
else
{
_versionString = os + _version.ToString(3) + " " + _servicePack;
}
return _versionString;
}
}
}
#endregion NestedTypes
}
#endregion Environment Extensions
#region Non-generic collection extensions
///
/// Add the AttributeCollection type with stripped functionalities for powershell on CoreCLR.
/// The Adapter type has a protected abstract method 'PropertyAttributes' that returns an AttributeCollection
/// instance. Third party adapter may already implement this method and thus we cannot change the return
/// type for full powershell code. Therefore, we add the AttributeCollection type with minimal functionalities
/// so that the code also work with CoreCLR.
///
public class AttributeCollection : ICollection, IEnumerable
{
///
/// AttributeCollection
///
public static readonly AttributeCollection Empty = new AttributeCollection(null);
#region Constructors
///
/// AttributeCollection protected constructor
///
protected AttributeCollection()
{
}
///
/// AttributeCollection public constructor
///
///
public AttributeCollection(params Attribute[] attributes)
{
if (attributes == null)
{
attributes = new Attribute[0];
}
this._attributes = attributes;
for (int i = 0; i < attributes.Length; i++)
{
if (attributes[i] == null)
{
throw new ArgumentNullException("attributes");
}
}
}
#endregion Constructors
#region Methods
///
/// Copies the collection to an array, starting at the specified index.
///
///
///
public void CopyTo(Array array, int index)
{
Array.Copy(this.Attributes, 0, array, index, this.Attributes.Length);
}
///
/// Gets an enumerator for this collection.
///
///
public IEnumerator GetEnumerator()
{
return this.Attributes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion Methods
#region Properties
private readonly Attribute[] _attributes;
///
/// Gets the attribute collection.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
protected virtual Attribute[] Attributes
{
get
{
return this._attributes;
}
}
///
/// Gets the number of attributes.
///
public int Count
{
get
{
return this.Attributes.Length;
}
}
///
/// Gets the attribute with the specified index number.
///
///
///
public virtual Attribute this[int index]
{
get
{
return this.Attributes[index];
}
}
int ICollection.Count
{
get
{
return this.Count;
}
}
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
object ICollection.SyncRoot
{
get
{
return null;
}
}
#endregion Properties
}
#endregion Non-generic collection extensions
#region Misc extensions
///
/// Add the Pointer type with stripped functionalities for PowerShell on CoreCLR.
/// We need this type because if a method returns a pointer, we need to wrap it into an object.
///
public sealed class Pointer
{
private unsafe void* _ptr;
private Type _ptrType;
private Pointer()
{
}
#region Methods
///
/// Boxes the supplied unmanaged memory pointer and the type associated with that pointer into a managed Pointer wrapper object.
/// The value and the type are saved so they can be accessed from the native code during an invocation.
///
///
///
///
public static unsafe object Box(void* ptr, Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (!type.IsPointer)
{
throw new ArgumentException("Argument must be pointer", "ptr");
}
Pointer pointer = new Pointer();
pointer._ptr = ptr;
pointer._ptrType = type;
return pointer;
}
///
/// Returns the stored pointer.
///
///
///
public static unsafe void* Unbox(object ptr)
{
var pointer = ptr as Pointer;
if (pointer == null)
{
throw new ArgumentException("Argument must be pointer", "ptr");
}
return ((Pointer)ptr)._ptr;
}
#endregion Methods
}
internal static class ListExtensions
{
internal static void ForEach(this List list, Action action)
{
if (list == null)
{
throw new ArgumentNullException("list");
}
if (action == null)
{
throw new ArgumentNullException("action");
}
for (int i = 0; i < list.Count; i++)
{
action(list[i]);
}
}
}
internal static class X509StoreExtensions
{
///
/// X509Store.Close() is not in CoreCLR and it's supposed to be replaced by X509Store.Dispose().
/// However, X509Store.Dispose() is not supported until .NET 4.6. So we have to have this extension
/// method 'Close' for X509Store for OneCore powershell, so that it works for both Full/Core CLR.
///
internal static void Close(this System.Security.Cryptography.X509Certificates.X509Store x509Store)
{
x509Store.Dispose();
}
}
#endregion Misc extensions
}
namespace Microsoft.PowerShell.CoreCLR
{
using System.IO;
using System.Management.Automation;
///
/// AssemblyExtensions
///
public static class AssemblyExtensions
{
///
/// Load an assembly given its file path.
///
/// The path of the file that contains the manifest of the assembly.
/// The loaded assembly.
public static Assembly LoadFrom(string assemblyPath)
{
return ClrFacade.LoadFrom(assemblyPath);
}
///
/// Load an assembly given its byte stream
///
/// The byte stream of assembly
/// The loaded assembly
public static Assembly LoadFrom(Stream assembly)
{
return ClrFacade.LoadFrom(assembly);
}
}
}
#endif