【问题标题】:Remove Class from Memory in PowerShell在 PowerShell 中从内存中删除类
【发布时间】:2017-03-16 15:18:14
【问题描述】:

我创建了一个名为“Application”的类并将其加载到我的主脚本中:

Import-Module -NAME "C:\PowerShell_Scripts\Class\Application.ps1" -GLOBAL -FORCE;

但是,如果我更改类文件并在 PowerShell ISE 中运行代码,则不会应用任何更改。即使我使用了 -FORCE,就好像该类仍在内存中。

我也尝试在加载模块之前删除它,但同样的问题发生了:

Remove-Module "Application" -ErrorAction Ignore -FORCE;
Import-Module -NAME "C:\PowerShell_Scripts\Class\Application.ps1" -GLOBAL -FORCE;

如果我在我的主脚本中更改了单个字符,那么它会重新加载类!但是我不应该修改主脚本来强制 PowerShell 重新加载类,这看起来很傻。

有没有办法从内存中删除 Application 类(如果存在)?

注意:仅包含函数的文件是工作文件。这仅适用于类导入。

添加:在控制台中,如果我运行 Remove-Module 命令,它会成功运行,但我仍然可以使用以下命令创建新对象:

$appDetails = [Application]::new($applicationID);

对我来说没有意义......

主脚本:

# Application Details
# -----------------
  #ID
  $applicationID     = 1;

############################################
#
# Load Supporting Scripts
#
############################################

try
{
    Remove-Module "Application" -ErrorAction Ignore -FORCE;
    Remove-Module "Common" -ErrorAction Ignore -FORCE;
    Remove-Module "ServerData" -ErrorAction Ignore -FORCE;

    Import-Module -NAME "C:\PowerShell_Scripts\Common.ps1" -GLOBAL -FORCE;
    Import-Module -NAME "C:\PowerShell_Scripts\ServerData.ps1" -GLOBAL -FORCE;
    Import-Module -NAME "C:\PowerShell_Scripts\Class\Application.ps1" -GLOBAL -FORCE;
}
catch
{
    Write-Host "`nError: Cannot load required PowerShell scripts. Ensure C:\PowerShell_Scripts\ exists and has the required files." -ForegroundColor Red;

    EXIT;
}

############################################
#
# Load the SharePoint Snapin Module.
#
############################################

LoadSharePointModule;
############################################
#
# Display component details to user.
#
############################################

#Create object of "Application" to get app details based on the ID.
$appDetails = [Application]::new($applicationID);

Write-Host "Ending ......";

应用类文件

Class Application
{
    #Class Properties
    [STRING] $appName;

    [INT32] $appID;
    [INT32] $versionMajor;
    [INT32] $versionOS;
    [INT32] $versionCentraAdmin;
    [INT32] $versionMain;
    [INT32] $versionGUI;
    [INT32] $versionWorkflow;
    [INT32] $versionForm;
    [INT32] $versionVS;
    [INT32] $versionOther;
    [INT32] $versionFull;

    [OBJECT] $spDevSite;
    [OBJECT] $versionList;

    #Constructor: Setup class properties.
    Application ([INT32] $appID)
    {
        Write-Host "`nGathering application details ..." -ForegroundColor Yellow;

        try
        {
            #Get the SharePoint Developer site Object.
            $this.spDevSite = Get-SPWeb -ErrorAction Stop $GLOBAL:spDevURL;
        }
        catch
        {
            Write-Host "`nUnable to connect to SharePoint Developer site!: $($GLOBAL:spDevURL)";

            #EXIT;
        }

        #Assign class property.
        $this.appID = $appID;
    }

}

我特意设置了 $GLOBAL:spDevURL; 的 URL;以便构造函数在此测试中失败。正常失败并显示

Write-Host "`nUnable to connect to SharePoint Developer site!: $($GLOBAL:spDevURL)";

但如果我对此行进行更改并运行脚本,则不会应用更改。

【问题讨论】:

  • 如果您运行包含Import 命令的脚本两次,是否会发生同样的事情?我注意到第一次运行时的行为与您相同,但再次运行脚本后,它似乎更新了
  • 不,如果我对 Application 类文件进行更改,然后运行主脚本 100 次,它将永远不会显示更改。但是,如果我在主脚本的任何地方都有一个字符(如注释),那么它会刷新并正确加载新类。
  • 无法在会话中重新加载课程 - 请参阅 stackoverflow.com/a/36812564/1368849
  • 是的,看起来不错。更改为 $appDetails = New-Object -ErrorAction Stop Application($applicationID) 效果很好。

标签: class powershell


【解决方案1】:

已知问题

PowerShell 5.0 和 5.1 中有一个已知问题可以解释此行为。 The issue was acknowledged DongBo Wang 于 2016 年 11 月在 PowerShell 6 团队中发表。他写道:

"模块分析结果以模块文件路径为key,以PSModuleInfo对象为值存储在缓存中。缓存条目没有根据模块文件的LastWriteTime正确失效,因此缓存值相同被重复使用了。”

换句话说,PowerShell 5.0、5.1 和 6.0 在不应该的时候将类的旧副本保留(并使用)在内存中。

意义

如果您不对此问题进行补偿,则此问题会导致使用 PowerShell 类进行开发时出现相当大的问题。我写了a test,其中涵盖了大约 100 个类重载很重要的场景。模糊地说,在这些场景中的大约 17 个场景中,PowerShell 5.0 和 5.1 不会在应该重新加载该类时。这意味着跨编辑使用相同的会话创建解释器将缓存相同或相似类的重复副本的真正可能性。这使得行为不可预测,并导致无法解决的奇怪结果。

解决方法

我发现您仍然可以使用 PowerShell 类进行高效开发。当项目涉及的 PowerShell 类的源代码被 PowerShell 解释器可能认为已更改时,您只需在新的 PowerShell 会话中执行每个测试运行。执行此操作的习惯方法是通过调用 powershell.exe 从 PowerShell 控制台调用您的测试命令:

powershell.exe -Command { Invoke-Pester }

如果您进行了严格的单元测试,那么这并不是一个非常低效的测试-编辑-测试循环。如果您需要单步执行代码,则每次进行编辑时都需要启动一个新的 ISE 副本。

通过此解决方法,我发现此错误对生产力的影响是可控的。我完全使用此解决方法开发了thisthis。这些项目中的每一个都涉及大量涉及 PowerShell 类的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-25
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2017-05-18
    • 2011-11-07
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多