Class 从PowerShell中的内存中删除类

Class 从PowerShell中的内存中删除类,class,powershell,Class,Powershell,我创建了一个名为“Application”的类,并将其加载到我的主脚本中: Import-Module -NAME "C:\PowerShell_Scripts\Class\Application.ps1" -GLOBAL -FORCE; 但是,如果我仅对类文件进行更改并在PowerShell ISE中运行代码,则不会应用任何更改。即使我使用了-FORCE,这个类几乎仍然在内存中 我还尝试在加载模块之前删除该模块,但同样的问题也发生了: Remove-Module "Application"

我创建了一个名为“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重新加载类,这看起来很愚蠢

如果存在应用程序类,是否有方法将其从内存中删除

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

添加:在控制台中,如果我运行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)";
但是,如果我对此行进行更改并运行脚本,则不会应用更改。

已知问题 PowerShell 5.0和5.1中有一个已知问题可以解释这种行为。由PowerShell 6团队于2016年11月发布。他写道:

模块分析结果存储在缓存中,以模块文件路径为键,PSModuleInfo对象为值。缓存项未根据模块文件的LastWriteTime正确地失效,因此重复使用了相同的缓存值

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

启示 如果您不对此进行补偿,则此问题会给使用PowerShell类的开发带来相当大的问题。我写的这篇文章涵盖了大约100个类重新加载很重要的场景。模糊地说,在这些场景中,大约有17种情况下,PowerShell 5.0和5.1没有在应该的时候重新加载类。这意味着在编辑过程中使用相同的会话会使解释器很可能缓存相同或类似类的重复副本。这使得行为不可预测,并导致无法解决的奇怪结果

变通办法 我发现您仍然可以使用PowerShell类进行高效的开发。当一个项目涉及PufS壳类的时候,你只需要在一个新的PoSeBar会话中执行每一个测试运行,PoS壳解释器可以考虑改变它的来源。执行此操作的常规方法是通过调用
PowerShell.exe
,从PowerShell控制台调用测试命令:

powershell.exe -Command { Invoke-Pester }
如果您有严格的单元测试,那么这并不是一个非常低效的测试编辑测试周期。如果需要单步执行代码,则每次进行编辑时都需要启动ISE的新副本


有了这个解决方法,我发现这个bug对生产力的影响是可控的。我开发并完全使用了这种变通方法。每个项目都涉及大量涉及PowerShell类的代码。

如果您两次运行包含
Import
命令的脚本,是否会发生同样的情况?我注意到与第一次运行时相同的行为,但再次运行脚本后,它似乎会更新,如果我对应用程序类文件进行更改,然后运行主脚本100次,它将永远不会显示更改。但是,如果我在主脚本中的任何位置都有一个字符(如注释),那么它将刷新并正确加载新类。可能的重复字符不能在会话中重新加载一个类-请看是的,看起来是正确的。更改为$appDetails=New Object-ErrorAction停止应用程序($applicationID)效果良好。