我希望在 PowerShell 中实现 PowerShell 提供程序。 我一直在想,如果我只是定义类型,然后将它们导入到我的会话(导入模块)中,我应该能够让它们可用。
例如,这
不起作用,但它沿着我想要实现的路径。 我显然错过了很多......有人知道这是否可能吗?
# EnvironmentProvider.ps1
$reference_assemblies = (
"System.Management.Automation, Version=1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
# "System.Configuration.Install, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
)
$source = @"
namespace Providers
{
using System.Management.Automation;
using System.Management.Automation.Provider;
[CmdletProvider("Environments", ProviderCapabilities.None)]
public class EnvironmentProvider : DriveCmdletProvider
{
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
return new EnvironmentDriveInfo(drive);
}
protected override object NewDriveDynamicParameters()
{
return base.NewDriveDynamicParameters();
}
}
public class EnvironmentDriveInfo : PSDriveInfo
{
public EnvironmentDriveInfo(PSDriveInfo driveInfo) : base(driveInfo)
{
}
}
}
"@
# -ea silentlycontinue in case its already loaded
#
add-type -referencedassemblies $referenced_assemblies -typedefinition $source -language CSharp -erroraction silentlycontinue
导入模块后,我尝试创建驱动器“环境”:
new-psdrive -psprovider Environments -name "Environments" -root ""
错误:
New-PSDrive : Cannot find a provider with the name 'Environments'.
假设提供程序确实有效,也许让它返回环境列表:开发、质量保证、登台、生产。
然后我希望能够通过以下方式重复使用它:
c:\adminlib>import-module .\EnvironmentProvider.ps1
c:\adminlib>environments:
environments:>ls
dev
qa
staging
production
environments:> cd production
environments\production> [execute actions against production]
environments\production:> cd dev
environments\dev:> [execute actions against dev, etc]
包含提供程序的程序集需要使用 Import-Module 导入(而不仅仅是包含添加类型声明的模块)。这可以通过两种方式完成:
选项1: 使用 Add-Type 的参数将运行时程序集构建为 .dll 文件并导入该文件。
选项2: 从内存导入运行时程序集。这就是我使用标准 msdn 示例的方法:
[appdomain]::CurrentDomain.GetAssemblies() | Where {$_.ExportedTypes -ne $null} | Where {($_.ExportedTypes | Select -ExpandProperty "Name") -contains "AccessDBProvider"} | Import-Module
将 where 过滤器中的提供商名称替换为您自己的名称。
干杯, 弗雷德
到目前为止,问题中代码的翻译对我有用。
class EnvironmentDriveInfo : System.Management.Automation.PSDriveInfo {
EnvironmentDriveInfo ([System.Management.Automation.PSDriveInfo] $driveInfo) : base($driveInfo) {}
}
[System.Management.Automation.Provider.CmdletProvider('Environments', [System.Management.Automation.Provider.ProviderCapabilities]::None)]
class EnvironmentProvider : System.Management.Automation.Provider.DriveCmdletProvider {
[System.Management.Automation.PSDriveInfo] NewDrive ([System.Management.Automation.PSDriveInfo] $drive) {
return [EnvironmentDriveInfo]::new($drive)
}
[Object] NewDriveDynamicParameters () {
return ([System.Management.Automation.Provider.DriveCmdletProvider]$this).NewDriveDynamicParameters()
}
}
$sessionStateProviderEntry = [System.Management.Automation.Runspaces.SessionStateProviderEntry]::new('Environments', [EnvironmentProvider], $null)
$pipelineType = [PowerShell].Assembly.GetType('System.Management.Automation.Runspaces.LocalPipeline')
$method = $pipelineType.GetMethod('GetExecutionContextFromTLS', [System.Reflection.BindingFlags]'Static,NonPublic')
$context = $method.Invoke($null, [System.Reflection.BindingFlags]'Static,NonPublic', $null, $null, (Get-Culture))
$internalType = [PowerShell].Assembly.GetType('System.Management.Automation.SessionStateInternal')
$constructor = $internalType.GetConstructor([System.Reflection.BindingFlags]'Instance,NonPublic', $null, $context.GetType(), $null)
$sessionStateInternal = $constructor.Invoke($context)
$method = $internalType.GetMethod('AddSessionStateEntry', [System.Reflection.BindingFlags]'Instance,NonPublic', $null, $sessionStateProviderEntry.GetType(), $null)
$method.Invoke($sessionStateInternal, $sessionStateProviderEntry)
New-PSDrive -Name Environments -PSProvider Environments -Root ''
New-PSDrive
完成且没有错误,尽管我不知道我会在真正的提供商那里遇到什么样的麻烦。当然,
using
语句可以使代码更具可读性。为了让事情简单明了,我没有在这里。