MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Management.Automation;8using System.Management.Automation.Internal;9using System.Management.Automation.Provider;10 11using Dbg = System.Management.Automation;12 13namespace Microsoft.PowerShell.Commands14{15 #region CoreCommandBase16 17 /// <summary>18 /// The base command for the core commands.19 /// </summary>20 public abstract class CoreCommandBase : PSCmdlet, IDynamicParameters21 {22 #region Tracer23 24 /// <summary>25 /// An instance of the PSTraceSource class used for trace output26 /// using "NavigationCommands" as the category.27 /// </summary>28 [Dbg.TraceSource("NavigationCommands", "The namespace navigation tracer")]29 internal static readonly Dbg.PSTraceSource tracer = Dbg.PSTraceSource.GetTracer("NavigationCommands", "The namespace navigation tracer");30 31 #endregion Tracer32 33 #region Protected members34 35 /// <summary>36 /// The context for the command that is passed to the core command providers.37 /// </summary>38 internal virtual CmdletProviderContext CmdletProviderContext39 {40 get41 {42 CmdletProviderContext coreCommandContext = new(this);43 44 coreCommandContext.Force = Force;45 46 Collection<string> includeFilter =47 SessionStateUtilities.ConvertArrayToCollection<string>(Include);48 49 Collection<string> excludeFilter =50 SessionStateUtilities.ConvertArrayToCollection<string>(Exclude);51 52 coreCommandContext.SetFilters(includeFilter, excludeFilter, Filter);53 coreCommandContext.SuppressWildcardExpansion = SuppressWildcardExpansion;54 coreCommandContext.DynamicParameters = RetrievedDynamicParameters;55 stopContextCollection.Add(coreCommandContext);56 57 return coreCommandContext;58 }59 }60 61 internal virtual SwitchParameter SuppressWildcardExpansion62 {63 get => _suppressWildcardExpansion;64 set => _suppressWildcardExpansion = value;65 }66 67 private bool _suppressWildcardExpansion;68 69 /// <summary>70 /// A virtual method for retrieving the dynamic parameters for a cmdlet. Derived cmdlets71 /// that require dynamic parameters should override this method and return the72 /// dynamic parameter object.73 /// </summary>74 /// <param name="context">75 /// The context under which the command is running.76 /// </param>77 /// <returns>78 /// An object representing the dynamic parameters for the cmdlet or null if there79 /// are none.80 /// </returns>81 internal virtual object GetDynamicParameters(CmdletProviderContext context) => null;82 83 /// <summary>84 /// Called by the base implementation that checks the SupportShouldProcess provider85 /// capability. This virtual method gives the86 /// derived cmdlet a chance query the CmdletProvider capabilities to determine87 /// if the provider supports ShouldProcess.88 /// </summary>89 /// <value></value>90 protected virtual bool ProviderSupportsShouldProcess => true;91 92 /// <summary>93 /// A helper for derived classes to call to determine if the paths specified94 /// are for a provider that supports ShouldProcess.95 /// </summary>96 /// <param name="paths">97 /// The paths to check to see if the providers support ShouldProcess.98 /// </param>99 /// <returns>100 /// If the paths are to different providers, and any don't support101 /// ShouldProcess, then the return value is false. If they all102 /// support ShouldProcess then the return value is true.103 /// </returns>104 protected bool DoesProviderSupportShouldProcess(string[] paths)105 {106 // If no paths are specified, then default to true as the paths107 // may be getting piped in.108 bool result = true;109 110 if (paths != null)111 {112 foreach (string path in paths)113 {114 ProviderInfo provider = null;115 PSDriveInfo drive = null;116 117 // I don't really care about the returned path, just the provider name118 SessionState.Path.GetUnresolvedProviderPathFromPSPath(119 path,120 this.CmdletProviderContext,121 out provider,122 out drive);123 124 // Check the provider's capabilities125 126 if (!CmdletProviderManagementIntrinsics.CheckProviderCapabilities(127 ProviderCapabilities.ShouldProcess,128 provider))129 {130 result = false;131 break;132 }133 }134 }135 136 return result;137 }138 139 /// <summary>140 /// The dynamic parameters which have already been retrieved from the provider141 /// and bound by the command processor.142 /// </summary>143 protected internal object RetrievedDynamicParameters => _dynamicParameters;144 /// <summary>145 /// The dynamic parameters for the command. They are retrieved using the146 /// GetDynamicParameters virtual method.147 /// </summary>148 private object _dynamicParameters;149 150 #endregion Protected members151 152 #region Public members153 154 /// <summary>155 /// Stops the processing of the provider by using the156 /// CmdletProviderContext to tunnel the stop message to157 /// the provider instance.158 /// </summary>159 protected override void StopProcessing()160 {161 foreach (CmdletProviderContext stopContext in stopContextCollection)162 {163 stopContext.StopProcessing();164 }165 }166 167 internal Collection<CmdletProviderContext> stopContextCollection =168 new();169 170 /// <summary>171 /// Gets or sets the filter property.172 /// </summary>173 /// <remarks>174 /// This is meant to be overridden by derived classes if175 /// they support the Filter parameter. This property is on176 /// the base class to simplify the creation of the CmdletProviderContext.177 /// </remarks>178 public virtual string Filter { get; set; }179 180 /// <summary>181 /// Gets or sets the include property.182 /// </summary>183 /// <remarks>184 /// This is meant to be overridden by derived classes if185 /// they support the Include parameter. This property is on186 /// the base class to simplify the creation of the CmdletProviderContext.187 /// </remarks>188 public virtual string[] Include189 {190 get;191 set;192 } = Array.Empty<string>();193 194 /// <summary>195 /// Gets or sets the exclude property.196 /// </summary>197 /// <remarks>198 /// This is meant to be overridden by derived classes if199 /// they support the Exclude parameter. This property is on200 /// the base class to simplify the creation of the CmdletProviderContext.201 /// </remarks>202 public virtual string[] Exclude203 {204 get;205 set;206 } = Array.Empty<string>();207 208 /// <summary>209 /// Gets or sets the force property.210 /// </summary>211 /// <remarks>212 /// Gives the provider guidance on how vigorous it should be about performing213 /// the operation. If true, the provider should do everything possible to perform214 /// the operation. If false, the provider should attempt the operation but allow215 /// even simple errors to terminate the operation.216 /// For example, if the user tries to copy a file to a path that already exists and217 /// the destination is read-only, if force is true, the provider should copy over218 /// the existing read-only file. If force is false, the provider should write an error.219 ///220 /// This is meant to be overridden by derived classes if221 /// they support the Force parameter. This property is on222 /// the base class to simplify the creation of the CmdletProviderContext.223 /// </remarks>224 public virtual SwitchParameter Force225 {226 get => _force;227 set => _force = value;228 }229 230 private bool _force;231 232 /// <summary>233 /// Retrieves the dynamic parameters for the command from234 /// the provider.235 /// </summary>236 public object GetDynamicParameters()237 {238 // Don't stream errors or Write* to the pipeline.239 CmdletProviderContext context = CmdletProviderContext;240 context.PassThru = false;241 242 try243 {244 _dynamicParameters = GetDynamicParameters(context);245 }246 catch (ItemNotFoundException)247 {248 _dynamicParameters = null;249 }250 catch (ProviderNotFoundException)251 {252 _dynamicParameters = null;253 }254 catch (DriveNotFoundException)255 {256 _dynamicParameters = null;257 }258 259 return _dynamicParameters;260 }261 262 /// <summary>263 /// Determines if the cmdlet and CmdletProvider supports ShouldProcess.264 /// </summary>265 public bool SupportsShouldProcess => ProviderSupportsShouldProcess;266 267 #endregion Public members268 }269 270 #endregion CoreCommandBase271 272 #region CoreCommandWithCredentialsBase273 274 /// <summary>275 /// The base class for core commands to extend when they require credentials276 /// to be passed as parameters.277 /// </summary>278 public class CoreCommandWithCredentialsBase : CoreCommandBase279 {280 #region Parameters281 282 /// <summary>283 /// Gets or sets the credential parameter.284 /// </summary>285 [Parameter(ValueFromPipelineByPropertyName = true)]286 [Credential]287 public PSCredential Credential { get; set; }288 289 #endregion Parameters290 291 #region parameter data292 293 #endregion parameter data294 295 #region Protected members296 297 /// <summary>298 /// The context for the command that is passed to the core command providers.299 /// </summary>300 internal override CmdletProviderContext CmdletProviderContext301 {302 get303 {304 CmdletProviderContext coreCommandContext = new(this, Credential);305 coreCommandContext.Force = Force;306 307 Collection<string> includeFilter =308 SessionStateUtilities.ConvertArrayToCollection<string>(Include);309 310 Collection<string> excludeFilter =311 SessionStateUtilities.ConvertArrayToCollection<string>(Exclude);312 313 coreCommandContext.SetFilters(includeFilter, excludeFilter, Filter);314 coreCommandContext.SuppressWildcardExpansion = SuppressWildcardExpansion;315 coreCommandContext.DynamicParameters = RetrievedDynamicParameters;316 stopContextCollection.Add(coreCommandContext);317 318 return coreCommandContext;319 }320 }321 322 #endregion Protected members323 }324 325 #endregion CoreCommandWithCredentialsBase326 327 #region GetLocationCommand328 329 /// <summary>330 /// The get-location command class.331 /// This command does things like list the contents of a container, get332 /// an item at a given path, get the current working directory, etc.333 /// </summary>334 /// <remarks>335 /// </remarks>336 [Cmdlet(VerbsCommon.Get, "Location", DefaultParameterSetName = LocationParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096495")]337 [OutputType(typeof(PathInfo), ParameterSetName = new string[] { LocationParameterSet })]338 [OutputType(typeof(PathInfoStack), ParameterSetName = new string[] { StackParameterSet })]339 public class GetLocationCommand : DriveMatchingCoreCommandBase340 {341 private const string LocationParameterSet = "Location";342 private const string StackParameterSet = "Stack";343 344 #region Command parameters345 346 #region Location parameter set parameters347 348 /// <summary>349 /// Gets or sets the provider from which to get the current location.350 /// </summary>351 [Parameter(ParameterSetName = LocationParameterSet, ValueFromPipelineByPropertyName = true)]352 public string[] PSProvider353 {354 get => _provider;355 set => _provider = value ?? Array.Empty<string>();356 }357 358 /// <summary>359 /// Gets or sets the drive from which to get the current location.360 /// </summary>361 [Parameter(ParameterSetName = LocationParameterSet, ValueFromPipelineByPropertyName = true)]362 public string[] PSDrive { get; set; }363 364 #endregion Location parameter set parameters365 366 #region Stack parameter set parameters367 368 /// <summary>369 /// Gets or sets the Stack switch parameter which is used370 /// to disambiguate parameter sets.371 /// </summary>372 /// <value></value>373 [Parameter(ParameterSetName = StackParameterSet)]374 public SwitchParameter Stack375 {376 get => _stackSwitch;377 set => _stackSwitch = value;378 }379 380 private bool _stackSwitch;381 382 /// <summary>383 /// Gets or sets the stack ID for the location stack that will384 /// be retrieved.385 /// </summary>386 [Parameter(ParameterSetName = StackParameterSet, ValueFromPipelineByPropertyName = true)]387 public string[] StackName388 {389 get => _stackNames;390 391 set => _stackNames = value;392 }393 394 #endregion Stack parameter set parameters395 396 #endregion Command parameters397 398 #region command data399 400 #region Location parameter set data401 402 /// <summary>403 /// The name of the provider from which to return the current location.404 /// </summary>405 private string[] _provider = Array.Empty<string>();406 407 #endregion Location parameter set data408 409 #region Stack parameter set data410 411 /// <summary>412 /// The name of the location stack from which to return the stack.413 /// </summary>414 private string[] _stackNames;415 416 #endregion Stack parameter set data417 418 #endregion command data419 420 #region command code421 422 /// <summary>423 /// The main execution method for the get-location command. Depending on424 /// the parameter set that is specified, the command can do many things.425 /// -locationSet gets the current working directory as a Monad path426 /// -stackSet gets the directory stack of directories that have been427 /// pushed by the push-location command.428 /// </summary>429 protected override void ProcessRecord()430 {431 // It is OK to use a switch for string comparison here because we432 // want a case sensitive comparison in the current culture.433 switch (ParameterSetName)434 {435 case LocationParameterSet:436 PathInfo result = null;437 438 if (PSDrive != null && PSDrive.Length > 0)439 {440 foreach (string drive in PSDrive)441 {442 List<PSDriveInfo> foundDrives = null;443 try444 {445 foundDrives = GetMatchingDrives(drive, PSProvider, null);446 }447 catch (DriveNotFoundException e)448 {449 ErrorRecord errorRecord =450 new(451 e,452 "GetLocationNoMatchingDrive",453 ErrorCategory.ObjectNotFound,454 drive);455 WriteError(errorRecord);456 continue;457 }458 catch (ProviderNotFoundException e)459 {460 ErrorRecord errorRecord =461 new(462 e,463 "GetLocationNoMatchingProvider",464 ErrorCategory.ObjectNotFound,465 PSProvider);466 WriteError(errorRecord);467 continue;468 }469 catch (ArgumentException argException)470 {471 ErrorRecord errorRecord =472 new(473 argException,474 "GetLocationNoMatchingDrive",475 ErrorCategory.ObjectNotFound,476 drive);477 WriteError(errorRecord);478 continue;479 }480 481 // Get the current location for a specific drive and provider482 483 foreach (PSDriveInfo workingDrive in foundDrives)484 {485 try486 {487 string path =488 LocationGlobber.GetDriveQualifiedPath(489 workingDrive.CurrentLocation,490 workingDrive);491 492 result = new PathInfo(workingDrive, workingDrive.Provider, path, SessionState);493 494 WriteObject(result);495 }496 catch (ProviderNotFoundException providerNotFound)497 {498 WriteError(499 new ErrorRecord(500 providerNotFound.ErrorRecord,501 providerNotFound));502 continue;503 }504 }505 }506 }507 // If the drive wasn't specified but the provider was508 else if ((PSDrive == null || PSDrive.Length == 0) &&509 (PSProvider != null && PSProvider.Length > 0))510 {511 foreach (string providerName in PSProvider)512 {513 bool providerContainsWildcard = WildcardPattern.ContainsWildcardCharacters(providerName);514 if (!providerContainsWildcard)515 {516 // Since the Provider was specified and doesn't contain517 // wildcard characters, make sure it exists.518 519 try520 {521 SessionState.Provider.GetOne(providerName);522 }523 catch (ProviderNotFoundException e)524 {525 ErrorRecord errorRecord =526 new(527 e,528 "GetLocationNoMatchingProvider",529 ErrorCategory.ObjectNotFound,530 providerName);531 WriteError(errorRecord);532 continue;533 }534 }535 536 // Match the providers537 538 foreach (ProviderInfo providerInfo in SessionState.Provider.GetAll())539 {540 if (providerInfo.IsMatch(providerName))541 {542 try543 {544 WriteObject(SessionState.Path.CurrentProviderLocation(providerInfo.FullName));545 }546 catch (ProviderNotFoundException providerNotFound)547 {548 WriteError(549 new ErrorRecord(550 providerNotFound.ErrorRecord,551 providerNotFound));552 continue;553 }554 catch (DriveNotFoundException driveNotFound)555 {556 if (providerContainsWildcard)557 {558 // NTRAID#Windows Out Of Band Releases-923607-2005/11/02-JeffJon559 // This exception is ignored, because it just means we didn't find560 // an active drive for the provider.561 continue;562 }563 else564 {565 WriteError(566 new ErrorRecord(567 driveNotFound.ErrorRecord,568 driveNotFound));569 }570 }571 }572 }573 }574 }575 else576 {577 // Get the current working directory using the core command API.578 WriteObject(SessionState.Path.CurrentLocation);579 }580 581 break;582 583 case StackParameterSet:584 if (_stackNames != null)585 {586 foreach (string stackName in _stackNames)587 {588 try589 {590 // Get the directory stack. This is similar to the "dirs" command591 WriteObject(SessionState.Path.LocationStack(stackName), false);592 }593 catch (PSArgumentException argException)594 {595 WriteError(596 new ErrorRecord(597 argException.ErrorRecord,598 argException));599 continue;600 }601 }602 }603 else604 {605 try606 {607 WriteObject(SessionState.Path.LocationStack(null), false);608 }609 catch (PSArgumentException argException)610 {611 WriteError(612 new ErrorRecord(613 argException.ErrorRecord,614 argException));615 }616 }617 618 break;619 620 default:621 Dbg.Diagnostics.Assert(false, string.Create(System.Globalization.CultureInfo.InvariantCulture, $"One of the predefined parameter sets should have been specified, instead we got: {ParameterSetName}"));622 break;623 }624 }625 626 #endregion command code627 }628 #endregion GetLocationCommand629 630 #region SetLocationCommand631 632 /// <summary>633 /// The core command for setting/changing location.634 /// This is the equivalent of cd command.635 /// </summary>636 [Cmdlet(VerbsCommon.Set, "Location", DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2097049")]637 [OutputType(typeof(PathInfo), typeof(PathInfoStack))]638 public class SetLocationCommand : CoreCommandBase639 {640 #region Command parameters641 private const string PathParameterSet = "Path";642 private const string LiteralPathParameterSet = "LiteralPath";643 private const string StackParameterSet = "Stack";644 645 /// <summary>646 /// Gets or sets the path property.647 /// </summary>648 [Parameter(Position = 0, ParameterSetName = PathParameterSet,649 ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]650 public string Path651 {652 get => _path;653 set => _path = value;654 }655 656 /// <summary>657 /// Gets or sets the path property, when bound from the pipeline.658 /// </summary>659 [Parameter(ParameterSetName = LiteralPathParameterSet,660 Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]661 [Alias("PSPath", "LP")]662 public string LiteralPath663 {664 get => _path;665 set666 {667 _path = value;668 base.SuppressWildcardExpansion = true;669 }670 }671 672 /// <summary>673 /// Gets or sets the parameter -passThru which states output from674 /// the command should be placed in the pipeline.675 /// </summary>676 [Parameter]677 public SwitchParameter PassThru678 {679 get => _passThrough;680 set => _passThrough = value;681 }682 683 /// <summary>684 /// Gets or sets the StackName parameter which determines which location stack685 /// to use for the push. If the parameter is missing or empty the default686 /// location stack is used.687 /// </summary>688 [Parameter(ParameterSetName = StackParameterSet, ValueFromPipelineByPropertyName = true)]689 public string StackName { get; set; }690 691 #endregion Command parameters692 693 #region Command data694 695 /// <summary>696 /// The filter used when doing a dir.697 /// </summary>698 private string _path = string.Empty;699 700 /// <summary>701 /// Determines if output should be passed through for702 /// set-location.703 /// </summary>704 private bool _passThrough;705 706 #endregion Command data707 708 #region Command code709 710 /// <summary>711 /// The functional part of the code that does the changing of the current712 /// working directory.713 /// </summary>714 protected override void ProcessRecord()715 {716 object result = null;717 718 switch (ParameterSetName)719 {720 case PathParameterSet:721 case LiteralPathParameterSet:722 try723 {724 // Change the current working directory725 if (string.IsNullOrEmpty(Path))726 {727 // If user just typed 'cd', go to FileSystem provider home directory728 Path = SessionState.Internal.GetSingleProvider(Commands.FileSystemProvider.ProviderName).Home;729 }730 731 result = SessionState.Path.SetLocation(Path, CmdletProviderContext, ParameterSetName == LiteralPathParameterSet);732 }733 catch (PSNotSupportedException notSupported)734 {735 WriteError(736 new ErrorRecord(737 notSupported.ErrorRecord,738 notSupported));739 }740 catch (DriveNotFoundException driveNotFound)741 {742 WriteError(743 new ErrorRecord(744 driveNotFound.ErrorRecord,745 driveNotFound));746 }747 catch (ProviderNotFoundException providerNotFound)748 {749 WriteError(750 new ErrorRecord(751 providerNotFound.ErrorRecord,752 providerNotFound));753 }754 catch (ItemNotFoundException pathNotFound)755 {756 WriteError(757 new ErrorRecord(758 pathNotFound.ErrorRecord,759 pathNotFound));760 }761 catch (PSArgumentException argException)762 {763 WriteError(764 new ErrorRecord(765 argException.ErrorRecord,766 argException));767 }768 769 break;770 771 case StackParameterSet:772 773 try774 {775 // Change the default location stack776 result = SessionState.Path.SetDefaultLocationStack(StackName);777 }778 catch (ItemNotFoundException itemNotFound)779 {780 WriteError(781 new ErrorRecord(782 itemNotFound.ErrorRecord,783 itemNotFound));784 }785 786 break;787 788 default:789 Dbg.Diagnostics.Assert(790 false,791 "One of the specified parameter sets should have been called");792 break;793 }794 795 if (_passThrough && result != null)796 {797 WriteObject(result);798 }799 }800 801 #endregion Command code802 }803 804 #endregion SetLocationCommand805 806 #region PushLocationCommand807 808 /// <summary>809 /// The core command for setting/changing location and pushing it onto a location stack.810 /// This is the equivalent of the pushd command.811 /// </summary>812 [Cmdlet(VerbsCommon.Push, "Location", DefaultParameterSetName = PathParameterSet, SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2097105")]813 public class PushLocationCommand : CoreCommandBase814 {815 #region Command parameters816 private const string PathParameterSet = "Path";817 private const string LiteralPathParameterSet = "LiteralPath";818 819 /// <summary>820 /// Gets or sets the path property.821 /// </summary>822 [Parameter(Position = 0, ParameterSetName = PathParameterSet,823 ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]824 public string Path825 {826 get => _path;827 set => _path = value;828 }829 830 /// <summary>831 /// Gets or sets the literal path parameter to the command.832 /// </summary>833 [Parameter(ParameterSetName = LiteralPathParameterSet,834 ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)]835 [Alias("PSPath", "LP")]836 public string LiteralPath837 {838 get => _path;839 set840 {841 base.SuppressWildcardExpansion = true;842 _path = value;843 }844 }845 846 /// <summary>847 /// Gets or sets the parameter -passThru which states output from848 /// the command should be placed in the pipeline.849 /// </summary>850 [Parameter]851 public SwitchParameter PassThru852 {853 get => _passThrough;854 set => _passThrough = value;855 }856 857 /// <summary>858 /// Gets or sets the StackName parameter which determines which location stack859 /// to use for the push. If the parameter is missing or empty the default860 /// location stack is used.861 /// </summary>862 [Parameter(ValueFromPipelineByPropertyName = true)]863 public string StackName864 {865 get => _stackName;866 set => _stackName = value;867 }868 869 #endregion Command parameters870 871 #region Command data872 873 /// <summary>874 /// The filter used when doing a dir.875 /// </summary>876 private string _path = string.Empty;877 878 /// <summary>879 /// Determines if output should be passed through for880 /// push-location.881 /// </summary>882 private bool _passThrough;883 884 /// <summary>885 /// The ID of the stack to use for the pop.886 /// </summary>887 private string _stackName;888 889 #endregion Command data890 891 #region Command code892 893 /// <summary>894 /// The functional part of the code that does the changing of the current895 /// working directory and pushes the container onto the stack.896 /// </summary>897 protected override void ProcessRecord()898 {899 // Push the current working directory onto the900 // working directory stack901 SessionState.Path.PushCurrentLocation(_stackName);902 903 if (Path != null)904 {905 try906 {907 // Now change the directory to the one specified908 // in the command909 PathInfo result = SessionState.Path.SetLocation(Path, CmdletProviderContext);910 911 if (PassThru)912 {913 WriteObject(result);914 }915 }916 catch (PSNotSupportedException notSupported)917 {918 WriteError(919 new ErrorRecord(920 notSupported.ErrorRecord,921 notSupported));922 return;923 }924 catch (DriveNotFoundException driveNotFound)925 {926 WriteError(927 new ErrorRecord(928 driveNotFound.ErrorRecord,929 driveNotFound));930 return;931 }932 catch (ProviderNotFoundException providerNotFound)933 {934 WriteError(935 new ErrorRecord(936 providerNotFound.ErrorRecord,937 providerNotFound));938 return;939 }940 catch (ItemNotFoundException pathNotFound)941 {942 WriteError(943 new ErrorRecord(944 pathNotFound.ErrorRecord,945 pathNotFound));946 return;947 }948 catch (PSArgumentException argException)949 {950 WriteError(951 new ErrorRecord(952 argException.ErrorRecord,953 argException));954 return;955 }956 }957 }958 959 #endregion Command code960 }961 962 #endregion PushLocationCommand963 964 #region PopLocationCommand965 966 /// <summary>967 /// The core command for pop-location. This is the equivalent of the popd command.968 /// It pops a container from the stack and sets the current location to that container.969 /// </summary>970 [Cmdlet(VerbsCommon.Pop, "Location", SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096907")]971 public class PopLocationCommand : CoreCommandBase972 {973 #region Command parameters974 975 /// <summary>976 /// Gets or sets the parameter -passThru which states output from977 /// the command should be placed in the pipeline.978 /// </summary>979 [Parameter]980 public SwitchParameter PassThru981 {982 get => _passThrough;983 set => _passThrough = value;984 }985 986 /// <summary>987 /// Gets or sets the StackName parameter which determines which location stack988 /// to use for the pop. If the parameter is missing or empty the default989 /// location stack is used.990 /// </summary>991 [Parameter(ValueFromPipelineByPropertyName = true)]992 public string StackName993 {994 get => _stackName;995 set => _stackName = value;996 }997 998 #endregion Command parameters999 1000 #region Command data1001 1002 /// <summary>1003 /// Determines if output should be passed through for1004 /// pop-location.1005 /// </summary>1006 private bool _passThrough;1007 1008 /// <summary>1009 /// The ID of the stack to use for the pop.1010 /// </summary>1011 private string _stackName;1012 1013 #endregion Command data1014 1015 #region Command code1016 1017 /// <summary>1018 /// Gets the top container from the location stack and sets the1019 /// location to it.1020 /// </summary>1021 protected override void ProcessRecord()1022 {1023 try1024 {1025 // Pop the top of the location stack.1026 1027 PathInfo result = SessionState.Path.PopLocation(_stackName);1028 1029 if (PassThru)1030 {1031 WriteObject(result);1032 }1033 }1034 catch (DriveNotFoundException driveNotFound)1035 {1036 WriteError(1037 new ErrorRecord(1038 driveNotFound.ErrorRecord,1039 driveNotFound));1040 return;1041 }1042 catch (ProviderNotFoundException providerNotFound)1043 {1044 WriteError(1045 new ErrorRecord(1046 providerNotFound.ErrorRecord,1047 providerNotFound));1048 return;1049 }1050 catch (PSArgumentException argException)1051 {1052 WriteError(1053 new ErrorRecord(1054 argException.ErrorRecord,1055 argException));1056 return;1057 }1058 catch (ItemNotFoundException itemNotFound)1059 {1060 WriteError(1061 new ErrorRecord(1062 itemNotFound.ErrorRecord,1063 itemNotFound));1064 return;1065 }1066 }1067 1068 #endregion Command code1069 }1070 1071 #endregion PopLocationCommand1072 1073 #region Drive commands1074 1075 #region NewPSDriveCommand1076 1077 /// <summary>1078 /// Mounts a drive in PowerShell runspace.1079 /// </summary>1080 [Cmdlet(VerbsCommon.New, "PSDrive", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low,1081 SupportsTransactions = true, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096815")]1082 public class NewPSDriveCommand : CoreCommandWithCredentialsBase1083 {1084 #region Command parameters1085 1086 /// <summary>1087 /// Gets or sets the name of the drive.1088 /// </summary>1089 [Parameter(Position = 0, Mandatory = true, ValueFromPipelineByPropertyName = true)]1090 public string Name1091 {1092 get => _name;1093 set => _name = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value));1094 }1095 1096 /// <summary>1097 /// Gets or sets the provider ID.1098 /// </summary>1099 [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)]1100 public string PSProvider1101 {1102 get => _provider;1103 set => _provider = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value));1104 }1105 1106 /// <summary>1107 /// Gets or sets the root of the drive. This path should be1108 /// a namespace specific path.1109 /// </summary>1110 [Parameter(Position = 2, Mandatory = true, ValueFromPipelineByPropertyName = true)]1111 [AllowEmptyString]1112 public string Root1113 {1114 get => _root;1115 set => _root = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value));1116 }1117 1118 /// <summary>1119 /// Gets or sets the description of the drive.1120 /// </summary>1121 [Parameter(ValueFromPipelineByPropertyName = true)]1122 public string Description1123 {1124 get => _description;1125 set => _description = value ?? throw PSTraceSource.NewArgumentNullException(nameof(value));1126 }1127 1128 /// <summary>1129 /// Gets or sets the scope identifier for the drive being created.1130 /// </summary>1131 [Parameter(ValueFromPipelineByPropertyName = true)]1132 [ArgumentCompleter(typeof(ScopeArgumentCompleter))]1133 public string Scope { get; set; }1134 1135#if !UNIX1136 /// <summary>1137 /// Gets or sets the Persist Switch parameter.1138 /// If this switch parameter is set then the created PSDrive1139 /// would be persisted across PowerShell sessions.1140 /// </summary>1141 [Parameter(ValueFromPipelineByPropertyName = true)]1142 public SwitchParameter Persist1143 {1144 get => _persist;1145 set => _persist = value;1146 }1147 1148 private bool _persist = false;1149#endif1150 /// <summary>1151 /// Gets the dynamic parameters for the new-psdrive cmdlet.1152 /// </summary>1153 /// <param name="context">1154 /// The context under which the command is running.1155 /// </param>1156 /// <returns>1157 /// An object representing the dynamic parameters for the cmdlet or null if there1158 /// are none.1159 /// </returns>1160 internal override object GetDynamicParameters(CmdletProviderContext context)1161 {1162 return SessionState.Drive.NewDriveDynamicParameters(PSProvider, context);1163 }1164 1165 /// <summary>1166 /// New-psdrive always supports ShouldProcess.1167 /// </summary>1168 /// <value></value>1169 protected override bool ProviderSupportsShouldProcess => true;1170 1171 #endregion Command parameters1172 1173 #region Command data1174 1175 /// <summary>1176 /// The name of the drive.1177 /// </summary>1178 private string _name;1179 1180 /// <summary>1181 /// The provider ID for the drive.1182 /// </summary>1183 private string _provider;1184 1185 /// <summary>1186 /// The namespace specific path of the root of the drive.1187 /// </summary>1188 private string _root;1189 1190 /// <summary>1191 /// A description for the drive.1192 /// </summary>1193 private string _description;1194 1195 #endregion Command data1196 1197 #region Command code1198 1199 /// <summary>1200 /// Adds a new drive to the Monad namespace.