C# 如何在二进制PowerShell模块中扩展路径?

C# 如何在二进制PowerShell模块中扩展路径?,c#,powershell,C#,Powershell,我正在编写一个简单的二进制PowerShell模块示例: 使用制度; 使用系统、管理、自动化; 使用System.Management.Automation.Runspaces; 名称空间MyModule { [CmdletVerbsDiagnostic.Test,SampleCmdlet] [OutputTypeOfSystem.String] 公共类TestSampleCmdlet命令:PSCmdlet { [参数 强制=真, 位置=0, ValueFromPipeline=true, Va

我正在编写一个简单的二进制PowerShell模块示例:

使用制度; 使用系统、管理、自动化; 使用System.Management.Automation.Runspaces; 名称空间MyModule { [CmdletVerbsDiagnostic.Test,SampleCmdlet] [OutputTypeOfSystem.String] 公共类TestSampleCmdlet命令:PSCmdlet { [参数 强制=真, 位置=0, ValueFromPipeline=true, ValueFromPipelineByPropertyName=true] 公共字符串路径{get;set;} //当管道开始执行时,将为管道中的每个cmdlet调用此方法一次 受保护的覆盖void BeginProcessing { 写博斯宾!; } //将为此cmdlet的管道接收的每个输入调用此方法;如果未接收到任何输入,则不调用此方法 受保护的覆盖无效进程记录 { 写对象路径; WriteObject System.IO.Path.GetFullPathPath; } //此方法将在管道执行结束时调用一次;如果未收到任何输入,则不调用此方法 受保护的覆盖无效结束处理 { 写了一封信!; } } } 导入模块并运行代码时,GetFullPath始终返回相对于用户配置文件的路径,而不是实际的完整路径:

PS C:\Users\User\GitHub\MyModule\source\MyModule> Import-Module -Name .\bin\Debug\netstandard2.0\MyModule.dll
PS C:\Users\User\GitHub\MyModule\source\MyModule> cd \
PS C:\> Test-SampleCmdlet -Path .\Temp\
.\Temp\
C:\Users\User\Temp\
PS C:\>                                                                                                                                                                                                                                                                     
如何正确展开path参数?

.NET方法使用Environment.CurrentDirectory中反映的进程范围的当前目录,该目录与PowerShell的特定于运行空间的特定于线程的当前位置不同。[1]

您不能直接依赖System.IO.Path.GetFullPath,至少在不将运行空间的当前文件系统位置指定为可选的第二个basePath参数的情况下是如此,该参数仅在.NET Core/PowerShell[Core]6+中可用

要可靠地引用调用运行空间的当前文件系统位置,即使不同提供程序的位置恰好是当前位置[2],也可以在PowerShell[Core]6+/.NET中使用.CurrentProviderLocationFileSystem.ProviderPath,如下所示。Core Path是表示cmdlet的-Path参数的属性,即输入路径:

# Get the runspace's file-system location.
string currentDir = CurrentProviderLocation("FileSystem").ProviderPath;

# .NET Core ONLY: Resolve the given path to a full path as a native path.
#                 relative to the given base path.
string fullPath = System.IO.Path.GetFullPath(Path, currentDir);
在Windows PowerShell中,需要做更多工作:

# Get the runspace's file-system location as a native path.
string currentDir = CurrentProviderLocation("FileSystem").ProviderPath;

# Requires `using System.Text.RegularExpressions;`
# Strips a ".\" or "./" prefix from a relative path.
string relativePathWithoutPrefix = Regex.Replace(Path, @"^.[\\/]", "")

# Caveat: Combine() will not resolve any additional, *interior* . 
#         or .. components, should they be present in relativePathWithoutPrefix.
string fullPath = System.IO.Path.Combine(currentDir, relativePathWithoutPrefix);
这两种方法都将传递一个已经是完整路径的路径值

注:

即使运行空间的当前文件系统位置基于使用新PSDrive创建的仅PowerShell的驱动器,生成的路径也是通过本机文件系统路径设计的

这种方法意味着您的cmdlet只支持文件系统路径

有关如何更普遍地使用PS提供程序位置(包括通配符解析)的信息,请参阅

[1] 这种差异是PowerShell在单个进程中支持多个运行空间线程的一个不幸的副作用,所有这些线程都需要有自己的当前位置—有关背景信息,请参阅

[2] 例如,运行空间的当前位置可能是注册表位置,如HKCU:\Console。

.NET方法使用进程范围的当前目录,如Environment.CurrentDirectory中所反映的,它与PowerShell的特定于运行空间的特定于线程的当前位置不同。[1]

您不能直接依赖System.IO.Path.GetFullPath,至少在不将运行空间的当前文件系统位置指定为可选的第二个basePath参数的情况下是如此,该参数仅在.NET Core/PowerShell[Core]6+中可用

要可靠地引用调用运行空间的当前文件系统位置,即使不同提供程序的位置恰好是当前位置[2],也可以在PowerShell[Core]6+/.NET中使用.CurrentProviderLocationFileSystem.ProviderPath,如下所示。Core Path是表示cmdlet的-Path参数的属性,即输入路径:

# Get the runspace's file-system location.
string currentDir = CurrentProviderLocation("FileSystem").ProviderPath;

# .NET Core ONLY: Resolve the given path to a full path as a native path.
#                 relative to the given base path.
string fullPath = System.IO.Path.GetFullPath(Path, currentDir);
在Windows PowerShell中,需要做更多工作:

# Get the runspace's file-system location as a native path.
string currentDir = CurrentProviderLocation("FileSystem").ProviderPath;

# Requires `using System.Text.RegularExpressions;`
# Strips a ".\" or "./" prefix from a relative path.
string relativePathWithoutPrefix = Regex.Replace(Path, @"^.[\\/]", "")

# Caveat: Combine() will not resolve any additional, *interior* . 
#         or .. components, should they be present in relativePathWithoutPrefix.
string fullPath = System.IO.Path.Combine(currentDir, relativePathWithoutPrefix);
这两种方法都将传递一个已经是完整路径的路径值

注:

即使运行空间的当前文件系统位置基于使用新PSDrive创建的仅PowerShell的驱动器,生成的路径也是通过本机文件系统路径设计的

这种方法意味着您的cmdlet只支持文件系统路径

有关如何更普遍地使用PS提供程序位置(包括通配符解析)的信息,请参阅

[1] 这种差异是PowerShell在单个进程中支持多个运行空间线程的一个不幸的副作用,所有这些线程都需要有自己的当前位置—有关背景信息,请参阅


[2] 例如,运行空间的当前位置可能是注册表位置,例如HKCU:\Console。

当您显示Environment.CurrentDirectory或System.IO.Directory.GetCurrentDirectory时会得到什么?当您显示Environment.CurrentDirectory或System.IO.Directory.GetCurrentDirectory时会得到什么
?非常感谢您的详细回答。即使路径是绝对路径,它也可以工作,因为path.Combine函数管理它。可惜的是,System.Management.Automation中没有内置的东西来管理路径扩展。很高兴听到这个消息,@Chris。有,如中所示,但它总是使用运行空间当前位置下的任何提供程序,可能是也可能不是文件系统提供程序。啊,是的,就我而言,它将始终是文件系统,没有注册表或其他提供程序,因此我将坚持您的答案。非常感谢您提供的详细答案。即使路径是绝对路径,它也可以工作,因为path.Combine函数管理它。可惜的是,System.Management.Automation中没有内置的东西来管理路径扩展。很高兴听到这个消息,@Chris。有,如中所示,但它总是使用运行空间当前位置下的任何提供程序,可能是也可能不是文件系统提供程序。啊,是的,就我而言,它将始终是文件系统,没有注册表或其他提供程序,所以我将坚持您的答案。