从自定义提供程序的c#代码中加载Powershell模块
本文关键字:代码 加载 Powershell 模块 自定义 程序 | 更新日期: 2023-09-27 18:14:29
我一直在研究一个非常具体的功能"需要",以绑定到我正在用c#编写的自定义提供程序。
基本上,我开始寻找一种方法来复制
A:
B:
etc函数是在PowerShell加载时定义的所以不用输入
CD A:
你可以只做前面提到的
A:
我首先尝试让我的提供者将函数注入运行空间,但似乎我完全错过了如何让它工作的时间,所以我走了另一条路线。
基本上我有一个非常简单的PSM1文件usecolons。PSM1
function Use-ColonsForPSDrives
{
[CmdletBinding()] Param()
Write-Verbose "Looping Through Installed PowerShell Providers"
Get-PSProvider | % `
{
Write-Verbose "Found $($_.Name) checking its drives"
$_.Drives | ? { (Get-Command | ? Name -eq "$($_.Name):") -eq $null } | `
{
Write-Verbose "Setting up: `"function $($_.Name):() {Set-Location $($_.Name):}`""
if ($Verbose)
{
. Invoke-Expression -Command "function $($_.Name):() {Set-Location $($_.Name):}"
}
else
{
. Invoke-Expression -Command "function $($_.Name):() {Set-Location $($_.Name):}" -ErrorAction SilentlyContinue
}
Write-Verbose "Finished with drive $($_.Name)"
}
}
# Cert and WSMan do not show up as providers until you try to naviagte to their drives
# As a result we will add their functions manually but we will check if they are already set anyways
if ((Get-Command | ? Name -eq "Cert:") -eq $null) { . Invoke-Expression -Command "function Cert:() {Set-Location Cert:}" }
if ((Get-Command | ? Name -eq "WSMan:") -eq $null) { . Invoke-Expression -Command "function WSMan:() {Set-Location WSMan:}" }
}
. Use-ColonsForPSDrives
简单来说,它循环遍历所有加载的提供商,然后遍历每个提供商的所有驱动器,然后检查Function:驱动器是否包含与{DriveName}:格式匹配的函数,如果没有找到,则创建一个。
psd1文件无非是导出所有函数
这是存储在%ProgramFiles%'WindowsPowerShell'Modules路径下的自己的文件夹
最后我有个人资料。Ps1在%windir%'system32'windowspowershell'v1.0目录下,只做
Remove-Module UseColons -ErrorAction SilentlyContinue
Import-Module UseColons
所以当我加载PowerShell或ISE时如果我想通过变量输入dir我可以调用
Variable:
或者如果我需要切换回注册表
HKLM:
HKCU:
当你与多个供应商一起工作时,当你切换时,一遍又一遍地输入CD,这很烦人。
现在的问题,我仍在开发实际的PowerShell提供程序,这是最初的打算。但是当我调试它时,UseColons模块在visual studio转过来加载新的提供程序之前加载,所以如果我手动删除并再次导入该模块,它会做它的事情,并且我为我的提供程序提供了所有的驱动函数。
我想知道在那冗长的解释之后,我怎样才能:
我不想把它从我的标准配置文件中删除,因为当我不在新的提供商上工作时,它非常有用,只是在管理方面使用powershell。
希望有人能给我一些想法或指出我在一些好的更深入的潜水powershell提供程序文档和如何操作的方向。
您可以通过覆盖NewDrive
方法,在每次向提供程序添加新驱动器时动态创建一个新函数,如下所示:
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
InvokeCommand.InvokeScript($"New-Item -Path 'Function:''' -Name 'global:{drive.Name}:' -Value {{ Set-Location $MyInvocation.MyCommand.Name }}");
return drive;
}
这样,您的提供程序驱动器具有与内置文件系统驱动器相同的功能:
Get-Item "Function:'C:" | select Name, ScriptBlock
将返回:
Name ScriptBlock
---- -----------
C: Set-Location $MyInvocation.MyCommand.Name
您可以在RemoveDrive
中添加类似的命令来再次删除该功能。
当然,这只适用于您自己的提供程序中的驱动器。如果您想为其他提供程序执行此操作,可以运行以下命令:
Get-PSDrive | ForEach-Object { New-Item -Path "Function:''" -Name "global:$($_.Name):" -Value { Set-Location $MyInvocation.MyCommand.Name } -ErrorAction Ignore }
如果命令已经存在,则为-ErrorAction Ignore
在您的模块清单(.psd1
)中,您有一个DLL作为RootModule?
这是一个可怕的黑客,并且对将来创建的驱动器没有帮助,但是…
在你的模块清单中,代替YourProvider.dll作为RootModule,使用Dummy。Psm1代替(可以是一个空文件)。然后,对于NestedModules,使用@( 'YourProvider.dll', 'UseColons' )
。这允许UseColons模块在 YourProvider.dll之后加载。(Dummy是最后一个)