Netscoot.Shared/Common/PathInputTransform.ps1
|
# Pipeline-input gate for the MUTATING move cmdlets. # # The movers accept their target as a [string] path bound ByValue from the pipeline. We also want to # accept a Get-ChildItem/Get-Item item (System.IO.FileSystemInfo) by taking its .FullName - but we # must NOT bind arbitrary objects' like-named properties. The old design used # ValueFromPipelineByPropertyName + an [Alias('FullName','PSPath','Path')], which made read-only # audit outputs (Test-SolutionConsistency.Project, Get-SolutionInventory/Test-UnityMetaIntegrity.Path) # silently bind row-by-row into the mutators and attempt moves. That is the hazard this closes. # # This ArgumentTransformationAttribute positively defines acceptable input: a path string passes # through, a FileSystemInfo becomes its FullName, and ANY other object type throws a clear error so # a report/result object piped into a mover fails loudly instead of binding. # # Defined as a compiled .NET type via Add-Type (not a PowerShell `class`): a PowerShell class is # only resolvable as a type literal within its own module scope, but this attribute is referenced in # param blocks across three sibling engine modules (Core/Native/Unity). A real .NET type registered # in the AppDomain is visible to all of them. Guarded so re-importing the module (-Force) is a no-op. if (-not ('Netscoot.PathInputTransformAttribute' -as [type])) { Add-Type -TypeDefinition @' using System; using System.IO; using System.Management.Automation; namespace Netscoot { // Accept a path string or a Get-Item/Get-ChildItem item; reject everything else. [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] public sealed class PathInputTransformAttribute : ArgumentTransformationAttribute { public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) { object item = inputData; PSObject pso = item as PSObject; if (pso != null) { item = pso.BaseObject; } // A path string binds as-is (named, positional, or ByValue from the pipeline). if (item is string) { return item; } // A Get-Item/Get-ChildItem result (FileInfo/DirectoryInfo) binds via its full path. FileSystemInfo fsi = item as FileSystemInfo; if (fsi != null) { return fsi.FullName; } string actual = (item == null) ? "null" : item.GetType().FullName; throw new ArgumentTransformationMetadataException( "Unsupported pipeline input: expected a path string or a file/directory item " + "(System.IO.FileSystemInfo from Get-ChildItem/Get-Item), but got [" + actual + "]. " + "Pipe a path string or a Get-Item result - not a report/result object such as the " + "output of Test-SolutionConsistency, Get-SolutionInventory, or Test-UnityMetaIntegrity."); } } } '@ } |