diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs index 4ee258575f..182cf59d99 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CommonUtils.cs @@ -1,16 +1,22 @@ using System; using System.Collections; using System.Diagnostics; +using System.Globalization; using System.Runtime.InteropServices; using System.Text; using System.Resources; using System.Reflection; +#if CORECLR +using System.ComponentModel; +#else +using System.Threading; +#endif + namespace Microsoft.PowerShell.Commands.Diagnostics.Common { internal static class CommonUtilities { -#if !CORECLR // // StringArrayToString helper converts a string array into a comma-separated string. // Note this has only limited use, individual strings cannot have commas. @@ -29,6 +35,34 @@ namespace Microsoft.PowerShell.Commands.Diagnostics.Common return ret; } +#if CORECLR + private const string LibraryLoadDllName = "api-ms-win-core-libraryloader-l1-2-0.dll"; + private const string LocalizationDllName = "api-ms-win-core-localization-l1-2-1.dll"; + private const string SysInfoDllName = "api-ms-win-core-sysinfo-l1-2-1.dll"; + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct OSVERSIONINFOEX + { + 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; + } + + [DllImport(SysInfoDllName, CharSet = CharSet.Unicode, SetLastError = true)] + internal static extern bool GetVersionEx(ref OSVERSIONINFOEX osVerEx); +#else + private const string LibraryLoadDllName = "kernel32.dll"; + private const string LocalizationDllName = "kernel32.dll"; +#endif private const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; private const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; @@ -36,25 +70,25 @@ namespace Microsoft.PowerShell.Commands.Diagnostics.Common private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; private const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800; - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(LocalizationDllName, SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpBuffer, uint nSize, IntPtr Arguments); - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DllImport(LibraryLoadDllName, SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr LoadLibraryEx( [MarshalAs(UnmanagedType.LPWStr)] string lpFileName, IntPtr hFile, uint dwFlags ); - [DllImport("kernel32.dll")] + [DllImport(LibraryLoadDllName)] private static extern bool FreeLibrary(IntPtr hModule); - [DllImport("kernel32.dll", EntryPoint = "GetUserDefaultLangID", CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DllImport(LocalizationDllName, EntryPoint = "GetUserDefaultLangID", CallingConvention = CallingConvention.Winapi, SetLastError = true)] private static extern ushort GetUserDefaultLangID(); @@ -111,7 +145,6 @@ namespace Microsoft.PowerShell.Commands.Diagnostics.Common } return formatError; } -#endif public static ResourceManager GetResourceManager() { diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs new file mode 100644 index 0000000000..858e535cc9 --- /dev/null +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/CoreCLR/Stubs.cs @@ -0,0 +1,252 @@ + +#if CORECLR +using System.ComponentModel; +using Microsoft.PowerShell.CoreClr.Stubs; + +namespace System.Diagnostics +{ + /// + /// Indicates whether the performance counter category can have multiple instances. + /// + /// 1 + public enum PerformanceCounterCategoryType + { + /// + /// The instance functionality for the performance counter category is unknown. + /// + Unknown = -1, + + /// + /// The performance counter category can have only a single instance. + /// + SingleInstance, + + /// + /// The performance counter category can have multiple instances. + /// + MultiInstance + } + + /// + /// Specifies the formula used to calculate the + /// method for a instance. + /// + /// 2 + public enum PerformanceCounterType + { + /// + /// An instantaneous counter that shows the most recently observed value. + /// Used, for example, to maintain a simple count of items or operations. + /// + NumberOfItems32 = 65536, + + /// + /// An instantaneous counter that shows the most recently observed value. + /// Used, for example, to maintain a simple count of a very large number + /// of items or operations. It is the same as NumberOfItems32 except that + /// it uses larger fields to accommodate larger values. + /// + NumberOfItems64 = 65792, + + /// + /// An instantaneous counter that shows the most recently observed value + /// in hexadecimal format. Used, for example, to maintain a simple count + /// of items or operations. + NumberOfItemsHEX32 = 0, + + /// + /// An instantaneous counter that shows the most recently observed value. + /// Used, for example, to maintain a simple count of a very large number + /// of items or operations. It is the same as NumberOfItemsHEX32 except + /// that it uses larger fields to accommodate larger values. + /// + NumberOfItemsHEX64 = 256, + + /// + /// A difference counter that shows the average number of operations completed + /// during each second of the sample interval. Counters of this type measure + /// time in ticks of the system clock. + RateOfCountsPerSecond32 = 272696320, + + /// + /// A difference counter that shows the average number of operations completed + /// during each second of the sample interval. Counters of this type measure + /// time in ticks of the system clock. This counter type is the same as the + /// RateOfCountsPerSecond32 type, but it uses larger fields to accommodate + /// larger values to track a high-volume number of items or operations per + /// second, such as a byte-transmission rate. + /// + RateOfCountsPerSecond64 = 272696576, + + /// + /// An average counter designed to monitor the average length of a queue + /// to a resource over time. It shows the difference between the queue + /// lengths observed during the last two sample intervals divided by the + /// duration of the interval. This type of counter is typically used to + /// track the number of items that are queued or waiting. + /// + CountPerTimeInterval32 = 4523008, + + /// + /// An average counter that monitors the average length of a queue to a + /// resource over time. Counters of this type display the difference + /// between the queue lengths observed during the last two sample intervals, + /// divided by the duration of the interval. This counter type is the same + /// as CountPerTimeInterval32 except that it uses larger fields to + /// accommodate larger values. This type of counter is typically used + /// to track a high-volume or very large number of items that are queued or waiting. + /// + CountPerTimeInterval64 = 4523264, + + /// + /// An instantaneous percentage counter that shows the ratio of a subset + /// to its set as a percentage. For example, it compares the number of bytes + /// in use on a disk to the total number of bytes on the disk. + /// Counters of this type display the current percentage only, not an average + /// over time. + /// + RawFraction = 537003008, + + /// + /// A base counter that stores the denominator of a counter that presents a + /// general arithmetic fraction. Check that this value is greater than zero + /// before using it as the denominator in a RawFraction value calculation. + /// + RawBase = 1073939459, + + /// + /// An average counter that measures the time it takes, on average, to + /// complete a process or operation. Counters of this type display a + /// ratio of the total elapsed time of the sample interval to the number + /// of processes or operations completed during that time. This counter + /// type measures time in ticks of the system clock. + /// + AverageTimer32 = 805438464, + + /// + /// A base counter that is used in the calculation of time or count averages, + /// such as AverageTimer32 and AverageCount64. Stores the denominator for + /// calculating a counter to present "time per operation" or "count per operation". + /// + AverageBase = 1073939458, + + /// + /// An average counter that shows how many items are processed, on average, + /// during an operation. Counters of this type display a ratio of the items + /// processed to the number of operations completed. The ratio is calculated + /// by comparing the number of items processed during the last interval to + /// the number of operations completed during the last interval. + /// + AverageCount64 = 1073874176, + + /// + /// A percentage counter that shows the average ratio of hits to all + /// operations during the last two sample intervals. + /// + SampleFraction = 549585920, + + /// + /// An average counter that shows the average number of operations completed + /// in one second. When a counter of this type samples the data, each sampling + /// interrupt returns one or zero. The counter data is the number of ones that + /// were sampled. It measures time in units of ticks of the system performance timer. + /// + SampleCounter = 4260864, + + /// + /// A base counter that stores the number of sampling interrupts taken + /// and is used as a denominator in the sampling fraction. The sampling + /// fraction is the number of samples that were 1 (or true) for a sample + /// interrupt. Check that this value is greater than zero before using + /// it as the denominator in a calculation of SampleFraction. + /// + SampleBase = 1073939457, + + /// + /// A percentage counter that shows the average time that a component is + /// active as a percentage of the total sample time. + /// + CounterTimer = 541132032, + + /// + /// A percentage counter that displays the average percentage of active + /// time observed during sample interval. The value of these counters is + /// calculated by monitoring the percentage of time that the service was + /// inactive and then subtracting that value from 100 percent. + /// + CounterTimerInverse = 557909248, + + /// A percentage counter that shows the active time of a component + /// as a percentage of the total elapsed time of the sample interval. + /// It measures time in units of 100 nanoseconds (ns). Counters of this + /// type are designed to measure the activity of one component at a time. + /// + Timer100Ns = 542180608, + + /// + /// A percentage counter that shows the average percentage of active time + /// observed during the sample interval. + /// + Timer100NsInverse = 558957824, + + /// + /// A difference timer that shows the total time between when the component + /// or process started and the time when this value is calculated. + /// + ElapsedTime = 807666944, + + /// + /// A percentage counter that displays the active time of one or more + /// components as a percentage of the total time of the sample interval. + /// Because the numerator records the active time of components operating + /// simultaneously, the resulting percentage can exceed 100 percent. + /// + CounterMultiTimer = 574686464, + + /// + /// A percentage counter that shows the active time of one or more components + /// as a percentage of the total time of the sample interval. It derives + /// the active time by measuring the time that the components were not + /// active and subtracting the result from 100 percent by the number of + /// objects monitored. + /// + CounterMultiTimerInverse = 591463680, + + /// + /// A percentage counter that shows the active time of one or more components + /// as a percentage of the total time of the sample interval. It measures + /// time in 100 nanosecond (ns) units. + CounterMultiTimer100Ns = 575735040, + + /// + /// A percentage counter that shows the active time of one or more components + /// as a percentage of the total time of the sample interval. Counters of + /// this type measure time in 100 nanosecond (ns) units. They derive the + /// active time by measuring the time that the components were not active + /// and subtracting the result from multiplying 100 percent by the number + /// of objects monitored. + CounterMultiTimer100NsInverse = 592512256, + + /// + /// A base counter that indicates the number of items sampled. It is used + /// as the denominator in the calculations to get an average among the + /// items sampled when taking timings of multiple, but similar items. + /// Used with CounterMultiTimer, CounterMultiTimerInverse, CounterMultiTimer100Ns, + /// and CounterMultiTimer100NsInverse. + CounterMultiBase = 1107494144, + + /// + /// A difference counter that shows the change in the measured attribute + /// between the two most recent sample intervals. + /// + CounterDelta32 = 4195328, + + /// + /// A difference counter that shows the change in the measured attribute + /// between the two most recent sample intervals. It is the same as the + /// CounterDelta32 counter type except that is uses larger fields to + /// accomodate larger values. + CounterDelta64 = 4195584 + } +} +#endif diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs index 6240ef6504..2c03987ab1 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/ExportCounterCommand.cs @@ -1,6 +1,6 @@ // // Copyright (c) 2008 Microsoft Corporation. All rights reserved. -// +// using System; @@ -30,7 +30,7 @@ using Microsoft.PowerShell.Commands.Diagnostics.Common; namespace Microsoft.PowerShell.Commands { - /// + /// /// Class that implements the Get-Counter cmdlet. /// [Cmdlet(VerbsData.Export, "Counter", DefaultParameterSetName = "ExportCounterSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=138337")] @@ -38,7 +38,7 @@ namespace Microsoft.PowerShell.Commands { // // Path parameter - // + // [Parameter( Mandatory = true, Position = 0, @@ -58,7 +58,7 @@ namespace Microsoft.PowerShell.Commands // // Format parameter. // Valid strings are "blg", "csv", "tsv" (case-insensitive). - // + // [Parameter( Mandatory = false, ValueFromPipeline = false, @@ -77,7 +77,7 @@ namespace Microsoft.PowerShell.Commands // // MaxSize parameter // Maximum output file size, in megabytes. - // + // [Parameter( HelpMessageBaseName = "GetEventResources")] public UInt32 MaxSize @@ -90,7 +90,7 @@ namespace Microsoft.PowerShell.Commands // // InputObject parameter - // + // [Parameter( Mandatory = true, ValueFromPipeline = true, @@ -152,23 +152,30 @@ namespace Microsoft.PowerShell.Commands { _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager(); +#if CORECLR + // PowerShell Core requires at least Windows 7, + // so no version test is needed + _pdhHelper = new PdhHelper(false); +#else // // Determine the OS version: this cmdlet requires Windows 7 // because it uses new Pdh functionality. // - if (System.Environment.OSVersion.Version.Major < 6 || - (System.Environment.OSVersion.Version.Major == 6 && System.Environment.OSVersion.Version.Minor < 1)) + Version osVersion = System.Environment.OSVersion.Version; + if (osVersion.Major < 6 || + (osVersion.Major == 6 && osVersion.Minor < 1)) { string msg = _resourceMgr.GetString("ExportCtrWin7Required"); Exception exc = new Exception(msg); ThrowTerminatingError(new ErrorRecord(exc, "ExportCtrWin7Required", ErrorCategory.NotImplemented, null)); } - _pdhHelper = new PdhHelper(System.Environment.OSVersion.Version.Major < 6); + _pdhHelper = new PdhHelper(osVersion.Major < 6); +#endif // // Validate the Format and CounterSamples arguments - // + // ValidateFormat(); if (Circular.IsPresent && _maxSize == 0) @@ -200,9 +207,9 @@ namespace Microsoft.PowerShell.Commands } - /// + /// /// Handle Control-C - /// + /// protected override void StopProcessing() { _stopping = true; @@ -214,7 +221,7 @@ namespace Microsoft.PowerShell.Commands // This is the main entry point for the cmdlet. // When counter data comes from the pipeline, this gets invoked for each pipelined object. // When it's passed in as an argument, ProcessRecord() is called once for the entire _counterSampleSets array. - // + // protected override void ProcessRecord() { Debug.Assert(_counterSampleSets.Length != 0 && _counterSampleSets[0] != null); @@ -225,7 +232,7 @@ namespace Microsoft.PowerShell.Commands if (!_queryInitialized) { - if (_format.ToLower(CultureInfo.InvariantCulture).Equals("blg")) + if (_format.ToLowerInvariant().Equals("blg")) { res = _pdhHelper.AddRelogCounters(_counterSampleSets[0]); } @@ -303,7 +310,7 @@ namespace Microsoft.PowerShell.Commands // private void ValidateFormat() { - switch (_format.ToLower(CultureInfo.InvariantCulture)) + switch (_format.ToLowerInvariant()) { case "blg": _outputFormat = PdhLogFileType.PDH_LOG_TYPE_BINARY; diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs index 827d6407f7..d89bf55fa1 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/GetCounterCommand.cs @@ -1,6 +1,6 @@ // // Copyright (c) 2008 Microsoft Corporation. All rights reserved. -// +// using System; @@ -30,15 +30,15 @@ using Microsoft.PowerShell.Commands.Diagnostics.Common; namespace Microsoft.PowerShell.Commands { - /// + /// /// Class that implements the Get-Counter cmdlet. - /// + /// [Cmdlet(VerbsCommon.Get, "Counter", DefaultParameterSetName = "GetCounterSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=138335")] public sealed class GetCounterCommand : PSCmdlet { // // ListSet parameter - // + // [Parameter( Position = 0, Mandatory = true, @@ -62,7 +62,7 @@ namespace Microsoft.PowerShell.Commands // // Counter parameter - // + // [Parameter( Position = 0, ParameterSetName = "GetCounterSet", @@ -175,8 +175,8 @@ namespace Microsoft.PowerShell.Commands private EventWaitHandle _cancelEventArrived = new EventWaitHandle(false, EventResetMode.ManualReset); - // Culture identifier(s) - private const int FrenchCultureId = 0x040C; + // Culture identifier(s) + private const string FrenchCultureId = "fr-FR"; // The localized Pdh resource strings might use Unicode characters that are different from // what the user can type with the keyboard to represent a special character. // @@ -184,8 +184,8 @@ namespace Microsoft.PowerShell.Commands // in the resource strings. // // With this dictionary, we can add special mapping if we find other special cases in the future. - private readonly Dictionary>> _cultureAndSpecialCharacterMap = - new Dictionary>>() + private readonly Dictionary>> _cultureAndSpecialCharacterMap = + new Dictionary>>() { { FrenchCultureId, new List>() @@ -207,7 +207,14 @@ namespace Microsoft.PowerShell.Commands { _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager(); +#if CORECLR + // PowerShell Core requires at least Windows 7, + // so no version test is needed + _pdhHelper = new PdhHelper(false); +#else _pdhHelper = new PdhHelper(System.Environment.OSVersion.Version.Major < 6); +#endif + uint res = _pdhHelper.ConnectToDataSource(); if (res != 0) { @@ -237,9 +244,9 @@ namespace Microsoft.PowerShell.Commands } - // + // // Handle Control-C - // + // protected override void StopProcessing() { _cancelEventArrived.Set(); @@ -249,7 +256,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessRecord() override. // This is the main entry point for the cmdlet. - // + // protected override void ProcessRecord() { try @@ -286,7 +293,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessListSet() does the work to process ListSet parameter set. - // + // private void ProcessListSet() { if (_computerName.Length == 0) @@ -317,11 +324,11 @@ namespace Microsoft.PowerShell.Commands return; } - CultureInfo culture = Thread.CurrentThread.CurrentUICulture; + CultureInfo culture = GetCurrentCulture(); List> characterReplacementList = null; StringCollection validPaths = new StringCollection(); - _cultureAndSpecialCharacterMap.TryGetValue(culture.LCID, out characterReplacementList); + _cultureAndSpecialCharacterMap.TryGetValue(culture.Name, out characterReplacementList); foreach (string pattern in _listSet) { @@ -417,23 +424,23 @@ namespace Microsoft.PowerShell.Commands // // ProcessGetCounter() // Does the work to process GetCounterSet parameter set. - // + // private void ProcessGetCounter() { // 1. Combine machine names with paths, if needed, to construct full paths // 2. Translate default paths into current locale // 3. Expand wildcards and validate the paths and write errors for any invalid paths // 4. OpenQuery/ AddCounters - // 5. Skip the first reading + // 5. Skip the first reading - CultureInfo culture = Thread.CurrentThread.CurrentUICulture; + CultureInfo culture = GetCurrentCulture(); List> characterReplacementList = null; List paths = CombineMachinesAndCounterPaths(); uint res = 0; if (!_defaultCounters) { - _cultureAndSpecialCharacterMap.TryGetValue(culture.LCID, out characterReplacementList); + _cultureAndSpecialCharacterMap.TryGetValue(culture.Name, out characterReplacementList); } @@ -552,7 +559,12 @@ namespace Microsoft.PowerShell.Commands break; } +#if CORECLR + // CoreCLR has no overload of WaitOne with (interval, exitContext) + bool cancelled = _cancelEventArrived.WaitOne((int)_sampleInterval * 1000); +#else bool cancelled = _cancelEventArrived.WaitOne((int)_sampleInterval * 1000, true); +#endif if (cancelled) { break; @@ -584,7 +596,7 @@ namespace Microsoft.PowerShell.Commands // CombineMachinesAndCounterPaths() helper. // For paths that do not contain machine names, creates a path for each machine in machineNames. // Paths already containing a machine name will be preserved. - // + // private List CombineMachinesAndCounterPaths() { List retColl = new List(); @@ -622,9 +634,9 @@ namespace Microsoft.PowerShell.Commands // // WriteSampleSetObject() helper. - // In addition to writing the PerformanceCounterSampleSet object, + // In addition to writing the PerformanceCounterSampleSet object, // it writes a single error if one of the samples has an invalid (non-zero) status. - // + // private void WriteSampleSetObject(PerformanceCounterSampleSet set) { foreach (PerformanceCounterSample sample in set.CounterSamples) @@ -639,6 +651,15 @@ namespace Microsoft.PowerShell.Commands } WriteObject(set); } + + private static CultureInfo GetCurrentCulture() + { +#if CORECLR + return CultureInfo.CurrentCulture; +#else + return Thread.CurrentThread.CurrentUICulture; +#endif + } } } diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs index 60c6301547..ebecc990e6 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/ImportCounterCommand.cs @@ -1,6 +1,6 @@ // // Copyright (c) 2008 Microsoft Corporation. All rights reserved. -// +// using System; @@ -30,7 +30,7 @@ using Microsoft.PowerShell.Commands.Diagnostics.Common; namespace Microsoft.PowerShell.Commands { - /// + /// /// Class that implements the Get-Counter cmdlet. /// [Cmdlet(VerbsData.Import, "Counter", DefaultParameterSetName = "GetCounterSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=138338")] @@ -38,7 +38,7 @@ namespace Microsoft.PowerShell.Commands { // // Path parameter - // + // [Parameter( Position = 0, Mandatory = true, @@ -65,7 +65,7 @@ namespace Microsoft.PowerShell.Commands // // ListSet parameter - // + // [Parameter( Mandatory = true, ParameterSetName = "ListSetSet", @@ -119,7 +119,7 @@ namespace Microsoft.PowerShell.Commands // // Counter parameter - // + // [Parameter( Mandatory = false, ParameterSetName = "GetCounterSet", @@ -189,7 +189,13 @@ namespace Microsoft.PowerShell.Commands protected override void BeginProcessing() { _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager(); +#if CORECLR + // PowerShell Core requires at least Windows 7, + // so no version test is needed + _pdhHelper = new PdhHelper(false); +#else _pdhHelper = new PdhHelper(System.Environment.OSVersion.Version.Major < 6); +#endif } // @@ -199,7 +205,7 @@ namespace Microsoft.PowerShell.Commands { // // Resolve and validate the Path argument: present for all parametersets. - // + // if (!ResolveFilePaths()) { return; @@ -229,9 +235,9 @@ namespace Microsoft.PowerShell.Commands } - // + // // Handle Control-C - // + // protected override void StopProcessing() { _stopping = true; @@ -242,7 +248,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessRecord() override. // This is the main entry point for the cmdlet. - // + // protected override void ProcessRecord() { AccumulatePipelineFileNames(); @@ -251,7 +257,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessSummary(). // Does the work to process Summary parameter set. - // + // private void ProcessSummary() { uint res = _pdhHelper.ConnectToDataSource(_resolvedPaths); @@ -276,7 +282,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessListSet(). // Does the work to process ListSet parameter set. - // + // private void ProcessListSet() { uint res = _pdhHelper.ConnectToDataSource(_resolvedPaths); @@ -373,7 +379,7 @@ namespace Microsoft.PowerShell.Commands // // ProcessGetCounter() // Does the work to process GetCounterSet parameter set. - // + // private void ProcessGetCounter() { // Validate StartTime-EndTime, if present @@ -556,7 +562,7 @@ namespace Microsoft.PowerShell.Commands // Returns a string collection of resolved file paths. // Writes non-terminating errors for invalid paths // and returns an empty collection. - // + // private bool ResolveFilePaths() { StringCollection retColl = new StringCollection(); @@ -607,7 +613,7 @@ namespace Microsoft.PowerShell.Commands continue; } - _resolvedPaths.Add(pi.ProviderPath.ToLower(CultureInfo.InvariantCulture)); + _resolvedPaths.Add(pi.ProviderPath.ToLowerInvariant()); } } @@ -635,9 +641,9 @@ namespace Microsoft.PowerShell.Commands // // WriteSampleSetObject() helper. - // In addition to writing the PerformanceCounterSampleSet object, + // In addition to writing the PerformanceCounterSampleSet object, // it writes a single error if one of the samples has an invalid (non-zero) status. - // The only exception is the first set, where we allow for the formatted value to be 0 - + // The only exception is the first set, where we allow for the formatted value to be 0 - // this is expected for CSV and TSV files. private void WriteSampleSetObject(PerformanceCounterSampleSet set, bool firstSet) diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs index 25afd98927..bf22d16a81 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhHelper.cs @@ -976,7 +976,7 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative // Marshal.PtrToStructure will allocate managed memory for the object, // so the unmanaged ptr can be freed safely // - pCounterPathElements = (PDH_COUNTER_PATH_ELEMENTS)Marshal.PtrToStructure(structPtr, typeof(PDH_COUNTER_PATH_ELEMENTS)); + pCounterPathElements = Marshal.PtrToStructure(structPtr); } } finally @@ -1011,12 +1011,12 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative } // Check if the path is local and assert if not: - string machineNameMassaged = pathElts.MachineName.ToLower(CultureInfo.InvariantCulture); + string machineNameMassaged = pathElts.MachineName.ToLowerInvariant(); machineNameMassaged = machineNameMassaged.TrimStart('\\'); - Debug.Assert(machineNameMassaged == System.Environment.MachineName.ToLower(CultureInfo.InvariantCulture)); + Debug.Assert(machineNameMassaged == System.Environment.MachineName.ToLowerInvariant()); - string lowerEngCtrName = pathElts.CounterName.ToLower(CultureInfo.InvariantCulture); - string lowerEngObjectName = pathElts.ObjectName.ToLower(CultureInfo.InvariantCulture); + string lowerEngCtrName = pathElts.CounterName.ToLowerInvariant(); + string lowerEngObjectName = pathElts.ObjectName.ToLowerInvariant(); // Get the registry index RegistryKey rootKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"); @@ -1029,7 +1029,7 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative for (uint enumIndex = 1; enumIndex < regCounters.Length; enumIndex++) { string regString = regCounters[enumIndex]; - if (regString.ToLower(CultureInfo.InvariantCulture) == lowerEngCtrName) + if (regString.ToLowerInvariant() == lowerEngCtrName) { try { @@ -1040,7 +1040,7 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative return (uint)PdhResults.PDH_INVALID_PATH; } } - else if (regString.ToLower(CultureInfo.InvariantCulture) == lowerEngObjectName) + else if (regString.ToLowerInvariant() == lowerEngObjectName) { try { @@ -1195,12 +1195,12 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative res = ParsePath(counterPath, ref pathElts); if (res == 0 && pathElts.InstanceName != null) { - chi.InstanceName = pathElts.InstanceName.ToLower(CultureInfo.InvariantCulture); + chi.InstanceName = pathElts.InstanceName.ToLowerInvariant(); } - if (!_consumerPathToHandleAndInstanceMap.ContainsKey(counterPath.ToLower(CultureInfo.InvariantCulture))) + if (!_consumerPathToHandleAndInstanceMap.ContainsKey(counterPath.ToLowerInvariant())) { - _consumerPathToHandleAndInstanceMap.Add(counterPath.ToLower(CultureInfo.InvariantCulture), chi); + _consumerPathToHandleAndInstanceMap.Add(counterPath.ToLowerInvariant(), chi); } bAtLeastOneAdded = true; @@ -1236,9 +1236,9 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative continue; } - string lowerCaseMachine = pathElts.MachineName.ToLower(CultureInfo.InvariantCulture); - string lowerCaseObject = pathElts.ObjectName.ToLower(CultureInfo.InvariantCulture); - string lowerCaseCounter = pathElts.CounterName.ToLower(CultureInfo.InvariantCulture); + string lowerCaseMachine = pathElts.MachineName.ToLowerInvariant(); + string lowerCaseObject = pathElts.ObjectName.ToLowerInvariant(); + string lowerCaseCounter = pathElts.CounterName.ToLowerInvariant(); string lcPathMinusInstance = @"\\" + lowerCaseMachine + @"\" + lowerCaseObject + @"\" + lowerCaseCounter; @@ -1311,12 +1311,12 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative if (pathElts.InstanceName != null) { - chi.InstanceName = pathElts.InstanceName.ToLower(CultureInfo.InvariantCulture); + chi.InstanceName = pathElts.InstanceName.ToLowerInvariant(); } - if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLower(CultureInfo.InvariantCulture))) + if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLowerInvariant())) { - _reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLower(CultureInfo.InvariantCulture), chi); + _reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLowerInvariant(), chi); //Console.WriteLine ("added map path:" + sample.Path ); } } @@ -1370,12 +1370,12 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative chi.hCounter = counterHandle; if (pathElts.InstanceName != null) { - chi.InstanceName = pathElts.InstanceName.ToLower(CultureInfo.InvariantCulture); + chi.InstanceName = pathElts.InstanceName.ToLowerInvariant(); } - if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLower(CultureInfo.InvariantCulture))) + if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(sample.Path.ToLowerInvariant())) { - _reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLower(CultureInfo.InvariantCulture), chi); + _reloggerPathToHandleAndInstanceMap.Add(sample.Path.ToLowerInvariant(), chi); } } @@ -1756,7 +1756,7 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative bUnknownPath = false; - string lcPath = sample.Path.ToLower(CultureInfo.InvariantCulture); + string lcPath = sample.Path.ToLowerInvariant(); if (!_reloggerPathToHandleAndInstanceMap.ContainsKey(lcPath)) { diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs index 7337d65903..3a122d8cec 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/PdhSafeHandle.cs @@ -4,7 +4,10 @@ using System; using System.Runtime.InteropServices; + +#if !CORECLR using System.Runtime.ConstrainedExecution; +#endif namespace Microsoft.Powershell.Commands.GetCounter.PdhNative { @@ -21,7 +24,9 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative } +#if !CORECLR // ReliabilityContract not supported on CoreCLR [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] +#endif protected override bool ReleaseHandle() { return (PdhHelper.PdhCloseLog(handle, 0) == 0); @@ -44,7 +49,9 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative } +#if !CORECLR // ReliabilityContract not supported on CoreCLR [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] +#endif protected override bool ReleaseHandle() { return (PdhHelper.PdhCloseQuery(handle) == 0); @@ -64,7 +71,9 @@ namespace Microsoft.Powershell.Commands.GetCounter.PdhNative } +#if !CORECLR // ReliabilityContract not supported on CoreCLR [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] +#endif protected override bool ReleaseHandle() { return (PdhHelper.PdhCloseLog(handle, 0) == 0); diff --git a/src/Microsoft.PowerShell.Commands.Diagnostics/project.json b/src/Microsoft.PowerShell.Commands.Diagnostics/project.json index a772d0d34f..04729e5c9b 100644 --- a/src/Microsoft.PowerShell.Commands.Diagnostics/project.json +++ b/src/Microsoft.PowerShell.Commands.Diagnostics/project.json @@ -45,16 +45,7 @@ "define": [ "CORECLR" ], "compile": { "excludeFiles": [ - "PdhSafeHandle.cs", "GetEventSnapin.cs", - "CounterSample.cs", - "CounterSet.cs", - "PdhHelper.cs", - "ExportCounterCommand.cs", - "GetCounterCommand.cs", - "ImportCounterCommand.cs", - "CounterFileInfo.cs", - "gen/GetEventResources.cs" ] } @@ -64,7 +55,10 @@ "net451": { "buildOptions": { "compile": { - "excludeFiles": [ "gen/GetEventResources.cs" ] + "excludeFiles": [ + "CoreCLR/Stubs.cs", + "gen/GetEventResources.cs" + ] }, "debugType": "full" } diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml new file mode 100644 index 0000000000..dfac01d1cb --- /dev/null +++ b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Diagnostics.format.ps1xml @@ -0,0 +1,79 @@ + + + + + + + + Counter + + Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet + + + + + + 25 + left + + + + left + 100 + + + + + + + + Timestamp + + + Readings + + + + + + + + Counter + + Microsoft.PowerShell.Commands.GetCounter.CounterFileInfo + + + + + 30 + left + + + 30 + left + + + 30 + left + + + + + + + + OldestRecord + + + NewestRecord + + + SampleCount + + + + + + + + diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml new file mode 100644 index 0000000000..32de7568aa --- /dev/null +++ b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Event.format.ps1xml @@ -0,0 +1,121 @@ + + + + + Default + + System.Diagnostics.Eventing.Reader.EventLogRecord + + + ProviderName + + + + + + 25 + + + 8 + right + + + 16 + + + + + + + + + TimeCreated + + + Id + + + LevelDisplayName + + + Message + + + + + + + + + Default + + System.Diagnostics.Eventing.Reader.EventLogConfiguration + + + + + + + 9 + + + + 18 + right + + + + 11 + right + + + + + + + + LogMode + + + MaximumSizeInBytes + + + RecordCount + + + LogName + + + + + + + + Default + + System.Diagnostics.Eventing.Reader.ProviderMetadata + + + + + + + Name + + + LogLinks + + + Opcodes + + + Tasks + + + + + + + + + diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml new file mode 100644 index 0000000000..bebbb9ea51 --- /dev/null +++ b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/GetEvent.types.ps1xml @@ -0,0 +1,139 @@ + + + + + + System.Diagnostics.Eventing.Reader.EventLogConfiguration + + + PSStandardMembers + + + DefaultDisplayPropertySet + + LogName + MaximumSizeInBytes + RecordCount + LogMode + + + + + + + + System.Diagnostics.Eventing.Reader.EventLogRecord + + + PSStandardMembers + + + DefaultDisplayPropertySet + + TimeCreated + ProviderName + Id + Message + + + + + + + + System.Diagnostics.Eventing.Reader.ProviderMetadata + + + ProviderName + Name + + + PSStandardMembers + + + DefaultDisplayPropertySet + + Name + LogLinks + + + + + + + + Microsoft.PowerShell.Commands.GetCounter.CounterSet + + + Counter + Paths + + + + + Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSample + + + PSStandardMembers + + + DefaultDisplayPropertySet + + Path + InstanceName + CookedValue + + + + + + + + Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet + + + PSStandardMembers + + + DefaultDisplayPropertySet + + Timestamp + Readings + + + + + + + + Microsoft.PowerShell.Commands.GetCounter.PerformanceCounterSampleSet + + + Readings + + $strPaths = "" + foreach ($ctr in $this.CounterSamples) + { + $strPaths += ($ctr.Path + " :" + "`n") + $strPaths += ($ctr.CookedValue.ToString() + "`n`n") + } + return $strPaths + + + + + diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 index eb03f078d2..a394a1931c 100644 --- a/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 +++ b/src/Modules/Windows-Core/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1 @@ -5,9 +5,9 @@ CompanyName="Microsoft Corporation" Copyright="© Microsoft Corporation. All rights reserved." ModuleVersion="3.0.0.0" PowerShellVersion="3.0" -CmdletsToExport="Get-WinEvent", "New-WinEvent" +CmdletsToExport="Get-WinEvent", "New-WinEvent", "Get-Counter", "Import-Counter", "Export-Counter" NestedModules="Microsoft.PowerShell.Commands.Diagnostics.dll" -TypesToProcess="..\..\GetEvent.types.ps1xml" -FormatsToProcess="..\..\Event.format.ps1xml" +TypesToProcess="GetEvent.types.ps1xml" +FormatsToProcess="Event.format.ps1xml", "Diagnostics.format.ps1xml" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=390783' -} \ No newline at end of file +}