Functions/GenXdev.FileSystem/PSGenXdevCmdlet.Utilities.cs
// ################################################################################
// Part of PowerShell module : GenXdev.FileSystem // Original cmdlet filename : PSGenXdevCmdlet.Utilities.cs // Original author : René Vaessen / GenXdev // Version : 1.304.2025 // ################################################################################ // Copyright (c) René Vaessen / GenXdev // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ################################################################################ using System.Collections; using System.Collections.Concurrent; using System.Collections.ObjectModel; using System.Diagnostics; using System.Management; using System.Management.Automation; using System.Runtime.InteropServices; using Microsoft.PowerShell.Commands; public abstract partial class PSGenXdevCmdlet : PSCmdlet { /// <summary> /// Normalizes paths by removing long path prefixes for non-filesystem use. /// </summary> /// <param name="path">The path to normalize.</param> /// <returns>The normalized path.</returns> protected string NormalizePathForNonFileSystemUse(string path) { // force paths internally to have backslashes path = path.Replace("/", "\\"); // path references user home directory? if (path == "~" || path.StartsWith("~\\")) { string home = this.SessionState.Path.GetResolvedPSPathFromPSPath("~")[0].Path; path = path == "~" ? home : Path.Combine(home, path.Substring(2)); } // check for unc long path prefix if (path.StartsWith(@"\\?\UNC\", StringComparison.InvariantCultureIgnoreCase)) { // remove prefix and adjust string result = @"\\" + path.Substring(8); return result; } // check for local long path prefix if (path.StartsWith(@"\\?\")) { // remove prefix string result = path.Substring(4); return result; } // check for alternate unc prefix if (path.StartsWith(@"\??\UNC\", StringComparison.InvariantCultureIgnoreCase)) { // remove prefix and adjust string result = @"\\" + path.Substring(8); return result; } // check for alternate local prefix if (path.StartsWith(@"\??\")) { // remove prefix string result = path.Substring(4); return result; } // return unchanged if no prefix return path; } /// <summary> /// Gets the number of physical cores for default parallelism /// </summary> /// count of physical cores.</returns> public int GetCoreCount() { // initialize core count accumulator int totalPhysicalCores = 0; // query WMI for accurate physical core counts per processor using (var searcher = new ManagementObjectSearcher("SELECT NumberOfCores FROM Win32_Processor")) { // iterate through each processor and sum physical cores // handles multi-socket systems correctly foreach (var item in searcher.Get()) { totalPhysicalCores += Convert.ToInt32(item["NumberOfCores"]); } } // return total physical cores across all processors return totalPhysicalCores; } /// <summary> /// Gets available RAM in bytes for resource calculations /// </summary> /// bytes of RAM.</returns> protected long GetFreeRamInBytes() { try { // Use direct Windows API call for better performance if (NativeMethods.GlobalMemoryStatusEx(out MEMORYSTATUSEX memStatus)) { return (long)memStatus.ullAvailPhys; } } catch { // Fall back to managed approach if P/Invoke fails } // Fallback: Use GC for approximate available memory // This is less accurate but has no external dependencies try { GC.Collect(0, GCCollectionMode.Optimized); long totalMemory = GC.GetTotalMemory(false); // Estimate available memory based on process working set using (var process = Process.GetCurrentProcess()) { long workingSet = process.WorkingSet64; long maxWorkingSet = process.MaxWorkingSet.ToInt64(); // Conservative estimate: assume we can use up to 80% of remaining working set return (long)((maxWorkingSet - workingSet) * 0.8); } } catch { // Ultimate fallback: return conservative estimate return 1024 * 1024 * 512; // 512 MB } } /// <summary> /// Memory status structure for Windows API calls. /// </summary> [StructLayout(LayoutKind.Sequential)] private struct MEMORYSTATUSEX { public uint dwLength; public uint dwMemoryLoad; public ulong ullTotalPhys; public ulong ullAvailPhys; public ulong ullTotalPageFile; public ulong ullAvailPageFile; public ulong ullTotalVirtual; public ulong ullAvailVirtual; public ulong ullAvailExtendedVirtual; public MEMORYSTATUSEX() { dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>(); dwMemoryLoad = 0; ullTotalPhys = 0; ullAvailPhys = 0; ullTotalPageFile = 0; ullAvailPageFile = 0; ullTotalVirtual = 0; ullAvailVirtual = 0; ullAvailExtendedVirtual = 0; } } /// <summary> /// Native Windows API methods for memory information. /// </summary> private static class NativeMethods { [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GlobalMemoryStatusEx(out MEMORYSTATUSEX lpBuffer); } } |