private object GetNodeChildrenDynamicParameters(SHiPSDirectory node) { var script = Constants.ScriptBlockWithParam1.StringFormat(Constants.GetChildItemDynamicParameters); var parameters = PSScriptRunner.InvokeScriptBlock(null, node, _drive, script, PSScriptRunner.ReportErrors); return(parameters?.FirstOrDefault()); }
private static IEnumerable <IPathNode> ProcessResultsWithCache( ICollection <object> results, IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { //TODO: async vs cache //we could yield result right away but we need to save the all children in the meantime because //InvokeScript can be costly.So we need to cache the results first by completing the foreach before //returning to a caller. List <IPathNode> retval = new List <IPathNode>(); //clear the child node list, get ready to get the refreshed ones node.Children?.Clear(); foreach (var result in results.WhereNotNull()) { // Making sure to obey the StopProcessing. if (context.Stopping) { return(null); } node.AddAsChildNode(result, drive, retval); } // Mark the node visited once we sucessfully fetched data. node.ItemNavigated = true; return(retval); }
internal ContainerNodeService(SHiPSDrive drive, object container, SHiPSDirectory parent) { _drive = drive; _container = container as SHiPSDirectory; if (_container != null) { _container.Parent = parent; } }
internal LeafNodeService(object leafObject, SHiPSDrive drive, SHiPSDirectory parent) { _shipsLeaf = leafObject as SHiPSLeaf; _drive = drive; _contentHelper = new ContentHelper(_shipsLeaf, drive); if (_shipsLeaf != null) { _shipsLeaf.Parent = parent; } }
internal static IPathNode AddAsChildNode(this SHiPSDirectory parent, object child, SHiPSDrive drive, List <IPathNode> list) { var pNode = GetChildPNode(parent, child, drive, cache: true); if (pNode == null) { return(null); } //add to its child list parent.Children.GetOrCreateEntryIfDefault(pNode.Name, () => new List <IPathNode>()).Add(pNode); list.Add(pNode); return(pNode); }
internal static IPathNode GetChildPNode(this SHiPSDirectory parent, object child, SHiPSDrive drive, bool addNodeOnly, bool cache) { if (child == null || parent == null) { return(null); } var pNode = child.ToPathNode(drive, parent); if (pNode != null) { if (string.IsNullOrWhiteSpace(pNode.Name)) { //let the program continue by logging warning only because one bad node should not stop the navigation. drive.SHiPS.WriteWarning(Resources.Resource.NameWithNullOrEmpty.StringFormat(parent.Name)); // throw new InvalidDataException(Resources.Resource.NameWithNullOrEmpty.StringFormat(parent.Name)); return(null); } if (!cache) { return(pNode); } //warning if nodes have the same name because "directory" cannot be the same name var existNode = parent.Children.Get(pNode.Name); var first = existNode?.FirstOrDefault(); if (first != null) { if (addNodeOnly) { // replace the existing node parent.Children.RemoveSafe(pNode.Name); return(pNode); } if (first.GetNodeValue().IsCollection || (pNode is ContainerNodeService && !((ContainerNodeService)pNode).ContainerNode.IsLeaf)) { drive.SHiPS.WriteWarning( Resources.Resource.NodesWithSameName.StringFormat( parent.Name.EqualsIgnoreCase(drive.RootNode.Name) ? "root" : parent.Name, pNode.Name)); return(null); } } return(pNode); } return(null); }
private static IEnumerable <IPathNode> ProcessResultsWithNoCache( ICollection <object> results, IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { foreach (var result in results.WhereNotNull()) { // Making sure to obey the StopProcessing. if (context.Stopping) { yield break; } var cnode = node.GetChildPNode(result, drive, false, cache: false); if (cnode != null) { yield return(cnode); } } }
internal static bool NeedRefresh(this IProviderContext context, SHiPSDirectory node, SHiPSDrive drive) { var myInvocationInfo = GetMyInvocationInfo(context.CmdletProvider); var verbose = false; var debug = false; var force = false; var usedDynamicParameter = false; if (myInvocationInfo == null) { return(false); } var boundParameters = myInvocationInfo.BoundParameters; if (boundParameters.Any()) { object argument; if (boundParameters.TryGetValue("Force", out argument)) { force = ((SwitchParameter)argument).IsPresent; } if (!force && boundParameters.TryGetValue("Verbose", out argument)) { verbose = ((SwitchParameter)argument).IsPresent; } if (!verbose && !force && boundParameters.TryGetValue("Debug", out argument)) { debug = ((SwitchParameter)argument).IsPresent; } if (!verbose && !force && !debug) { usedDynamicParameter = UsingDynamicParameter(boundParameters, node, drive); } } // If a user specify -force, -debug -verbose -filter or dynamic parameters, we do not use cache. return(force || debug || verbose || usedDynamicParameter); }
private object GetNodeChildrenDynamicParameters(string methodName, SHiPSDirectory node) { var errors = new ConcurrentBag <ErrorRecord>(); var parameters = PSScriptRunner.CallPowerShellScript( node, null, _drive.PowerShellInstance, null, methodName, PSScriptRunner.output_DataAdded, (sender, e) => PSScriptRunner.error_DataAdded(sender, e, errors)); if (errors.WhereNotNull().Any()) { var error = errors.FirstOrDefault(); var message = Environment.NewLine; message += error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message; throw new InvalidDataException(message); } return(parameters != null?parameters.FirstOrDefault() : null); }
internal static IPathNode ToPathNode(this object input, SHiPSDrive drive, SHiPSDirectory parent) { if (input == null) { return(null); } if (input is SHiPSDirectory) { return(new ContainerNodeService(drive, input, parent)); } if (input is SHiPSLeaf) { return(new LeafNodeService(input)); } // get or create a psobject on input var psobject = PSObject.AsPSObject(input); if (psobject == null) { return(null); } if (psobject.ImmediateBaseObject is SHiPSDirectory) { return(new ContainerNodeService(drive, psobject.ImmediateBaseObject, parent)); } if (psobject.ImmediateBaseObject is SHiPSLeaf) { return(new LeafNodeService(psobject.ImmediateBaseObject)); } return(new PSObjectNodeService(psobject)); }
/// <summary> /// Invokes a PowerShell script block; Removes the existing child node list before adding new ones. /// </summary> /// <param name="context">A ProviderContext object contains information that a PowerShell provider needs.</param> /// <param name="node">ContainerNode object that is corresponding to the current path.</param> /// <param name="drive">Current drive that a user is in use.</param> /// <param name="script">PowerShell script to be run.</param> /// <param name="errorHandler">Action for handling error cases.</param> /// <param name="args">Arguments passed into the script block.</param> /// <returns></returns> internal static IEnumerable <IPathNode> InvokeScriptBlockAndBuildTree( IProviderContext context, SHiPSDirectory node, SHiPSDrive drive, string script, Action <string, IProviderContext, IEnumerable <ErrorRecord> > errorHandler, params string[] args) { var progressId = 1; var activityId = Resource.RetrievingData; int percentComplete = 1; var desciption = (Resource.FetchingData).StringFormat(node.Name ?? ""); int waittime = 1000; // 1s CancellationTokenSource cts = new CancellationTokenSource(); var progressTracker = new ProgressTracker(progressId, activityId, desciption, node.BuiltinProgress); try { ICollection <object> results = new List <object>(); var errors = new ConcurrentBag <ErrorRecord>(); var parameters = context.GetSHiPSParameters(); var usingDynamicParameter = parameters.BoundParameters.UsingDynamicParameter(node, drive); //PowerShell engine hangs if we call like this in default runspace //var task = Task.Factory.StartNew(() => //{ // results = node.GetChildItem(); //}, cts.Token); var task = Task.Factory.StartNew(() => { results = CallPowerShellScript( node, drive.PowerShellInstance, parameters, script, output_DataAdded, (sender, e) => error_DataAdded(sender, e, errors), args); }, cts.Token); var stop = task.Wait(waittime, cts.Token); if (!stop && !cts.Token.IsCancellationRequested && !context.Stopping) { progressTracker.Start(context); } while (!stop && !cts.IsCancellationRequested && !context.Stopping) { stop = task.Wait(waittime, cts.Token); progressTracker.Update(++percentComplete, context); } progressTracker.End(context); if (errors.Count > 0) { // Cleanup child items only if the user type '-force'. if (context.Force) { //remove the cached child nodes for the failed node node.Children?.Clear(); //remove the node from its parent's children list so that it won't show again when a user types dir -force node.Parent?.Children.RemoveSafe(node.Name); } // report the error if there are any errorHandler?.Invoke(node.Name, context, errors); //do not yield break here as we need to display the rest of outputs } if (results == null || !results.Any()) { // Just because result is null, it does not mean that the call fails because the command may // return nothing. context.WriteDebug(Resource.InvokeScriptReturnNull.StringFormat(node.Name, context.Path)); if (errors.Count == 0) { // do not mark the node visited if there is an error. e.g., if login to azure fails, // we should not cache so that a user can dir again once the cred resolved. node.ItemNavigated = true; } //clear the child node list as the current node has null or empty children (results) if (context.Force) { node.Children?.Clear(); } return(Enumerable.Empty <IPathNode>()); } // Add the node list to the cache if needed return((node.UseCache && !usingDynamicParameter) ? ProcessResultsWithCache(results, context, node, drive, addNodeOnly: false) : ProcessResultsWithNoCache(results, context, node, drive)); } finally { if (!cts.IsCancellationRequested) { cts.Cancel(); } cts.Dispose(); progressTracker.End(context); // We complete the call. Reset the node parameters. node.SHiPSProviderContext.Clear(); //stop the running script drive.PowerShellInstance.Stop(); } }
internal static bool UsingDynamicParameter(this Dictionary <string, object> boundParameters, SHiPSDirectory node, SHiPSDrive drive) { if (node.SHiPSProviderContext.DynamicParameters == null) { return(false); } var usingDynamicParameter = false; var filter = false; if (boundParameters != null && boundParameters.Any()) { var defaultParameters = drive.GetChildItemDefaultParameters; usingDynamicParameter = boundParameters.Keys.Any(each => !defaultParameters.ContainsIgnoreCase(each)); object argument; if (!usingDynamicParameter && boundParameters.TryGetValue("Filter", out argument)) { filter = !string.IsNullOrWhiteSpace((string)argument); } } return(usingDynamicParameter || filter); }
internal static ICollection <object> CallPowerShellScript( SHiPSDirectory node, IProviderContext context, System.Management.Automation.PowerShell powerShell, SHiPSParameters parameters, string methodName, EventHandler <DataAddedEventArgs> outputAction, EventHandler <DataAddedEventArgs> errorAction) { if (node == null) { throw new ArgumentNullException("node"); } try { powerShell.Clear(); var input = new PSDataCollection <object>(); input.Complete(); var output = new PSDataCollection <object>(); if (outputAction != null) { output.DataAdded += outputAction; } //register events if (errorAction != null) { powerShell.Streams.Error.DataAdded += errorAction; } // Calling the following throws 'Unable to cast object of type 'System.Management.Automation.Language.FunctionMemberAst' to // type 'System.Management.Automation.Language.FunctionDefinitionAst'. //output = node.GetChildItem(); //make script block powerShell.AddScript("[CmdletBinding()] param([object]$object) $object.{0}()".StringFormat(methodName)); powerShell.AddParameter("object", node); if (parameters != null) { if (parameters.Debug) { powerShell.AddParameter("debug"); } if (parameters.Verbose) { powerShell.AddParameter("verbose"); } } powerShell.Invoke(null, output, new PSInvocationSettings()); return(output.Count == 0 ? null : output); } finally { powerShell.Streams.Error.DataAdded -= errorAction; } }
internal ContainerNodeService(SHiPSDrive drive, object container) { _drive = drive; _container = container as SHiPSDirectory; }