导入PSProtector生成的DLL后PowerShell Graph Cmdlet失效求助
症状
将包含Microsoft Graph Cmdlet的PowerShell脚本通过PSProtector编译为MyModule.dll后,导入该DLL并执行脚本时出现以下错误:
Microsoft.PowerShell.Core\Get-Command : The term 'Microsoft.Graph.Sites.private\Get-MgSite_List' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
直接导入原始PSM1/PS1文件时,Graph Cmdlet可正常执行;尝试添加模块清单(.psd1)未解决问题。
涉及代码示例
MyModule.ps1:
Function Install-PSGraphModule { Install-Module -Name Microsoft.Graph -Repository PSGallery -RequiredVersion 1.9.6 -SkipPublisherCheck -AllowClobber -Force -ErrorAction Stop } Function Get-AllSpoSites { Connect-MgGraph Get-MgSites -all }
MyScript.ps1:
Import-Module ".\MyModule.dll" -Global -DisableNameChecking -Force Install-PSGraphModule Get-AllSpoSites
原因分析
PSProtector将脚本编译为DLL时,会将代码封装在独立的模块作用域中。默认情况下,该作用域无法自动访问当前会话中已加载的全局模块(如Microsoft Graph),而直接导入PSM1文件时,函数运行在当前会话的作用域,能正常引用已加载的Cmdlet。
解决方案
1. 在函数内部显式导入Graph模块
修改原始脚本,在使用Graph Cmdlet的函数中添加显式导入模块的代码,确保编译后的DLL能在自身作用域内加载所需依赖:
修改后的MyModule.ps1:
Function Install-PSGraphModule { Install-Module -Name Microsoft.Graph -Repository PSGallery -RequiredVersion 1.9.6 -SkipPublisherCheck -AllowClobber -Force -ErrorAction Stop } Function Get-AllSpoSites { # 显式导入指定版本的Graph Sites模块,确保作用域内可访问 Import-Module Microsoft.Graph.Sites -RequiredVersion 1.9.6 -Force Connect-MgGraph Get-MgSites -All }
将修改后的脚本重新通过PSProtector编译为DLL,再执行测试。
2. 确保模块加载的全局作用域可见
如果需要在多个函数间共享Graph模块,可在导入DLL前先全局加载Microsoft Graph模块,或在函数中添加-Global参数导入:
# 在Get-AllSpoSites函数中使用-Global参数 Import-Module Microsoft.Graph.Sites -RequiredVersion 1.9.6 -Global -Force
3. 配置模块清单明确依赖
创建模块清单文件(MyModule.psd1),在其中声明对Microsoft Graph模块的依赖,将DLL和清单放在同一目录下,导入时直接导入目录而非DLL文件:
MyModule.psd1核心配置:
@{ RootModule = 'MyModule.dll' RequiredModules = @( @{ ModuleName = 'Microsoft.Graph' RequiredVersion = '1.9.6' } ) # 其他必要配置(如ModuleVersion、GUID等) }
修改MyScript.ps1的导入命令:
Import-Module ".\MyModule" -Global -DisableNameChecking -Force
4. 检查PSProtector编译选项
确认PSProtector的编译设置中是否有保留模块依赖、允许访问全局模块的选项,部分编译工具会提供作用域隔离的开关,调整为允许引用全局模块后重新编译。
内容的提问来源于stack exchange,提问作者Charles

