Почему функция PowerShell работает по-разному в зависимости от того, импортируется ли она из файла или из модуля PS?

Вопрос или проблема

У меня есть следующая функция PowerShell. Я исключил части функции, которые не имеют отношения к делу.

Function Add-TradeDetailElementBlocks
{
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$False, Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [Parameter(ValueFromPipeline=$False, Mandatory=$True)]
        [string]$DateFormat,

        [Parameter(ValueFromPipeline=$False, Mandatory=$True)]
        [string]$TradeImportXPath,

        [Parameter(ValueFromPipeline=$False, Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [System.Data.DataRow[]]$BlockList,

        [Parameter(ValueFromPipeline=$False, Mandatory=$True)]
        [int]$DealId
    )

    $Xml = New-Object -TypeName System.Xml.XmlDocument
    $File = Get-childItem -Path $Path
    $Xml.Load($File)

    $TradeImportNode = $Xml.SelectSingleNode($TradeImportXPath)

    $PriceMultiplier,$AmountMultiplier = Get-Multiplier $DealId

    foreach($Block in $BlockList)
    {

        $TradeDetailsElement = $Xml.CreateElement('tradeDetail')
        $TradeImportNode.AppendChild($TradeDetailsElement) | Out-Null

        $DatesElement = $Xml.CreateElement('dates')
        $TradeDetailsElement.AppendChild($DatesElement) | Out-Null
        $TradeDetailsElement.dates = Convert-DateToString -Date $Block.dates -Format $DateFormat

        $Block.price = ([double]$Block.price * $PriceMultiplier).ToString("N10")
        $Block.amount = ([double]$Block.amount * $AmountMultiplier).ToString("N6")

        if($Block.times -ne $Null)
        {
            $TimesElement = $Xml.CreateElement('times')
            $TradeDetailsElement.AppendChild($TimesElement) | Out-Null
            $TradeDetailsElement.times = [string]($Block.times)
        }

        :
        :

        $Xml.Save($Path)
    }
}

Эта функция читает значения из объекта строки данных (т.е. $Block) и записывает значения в XML-файл. Структура XML-файла в данном случае не имеет значения.

Если я сохраню эту функцию в файле PowerShell и импортирую файл в свой скрипт, используя точечную нотацию, я получаю ошибку на строке if($Block.times -ne $Null), потому что свойство times не существует в строке данных. Это можно ожидать.

Однако, если функция содержится в модуле, который импортируется в скрипт с помощью Import-Module, тот же код будет работать без проблем (даже если элемент times не существует в строке данных).

Что вызывает это различие в поведении?

Ответ или решение

Вопрос о том, почему функция PowerShell ведет себя по-разному в зависимости от того, импортируется ли она из файла или из модуля, можно объяснить несколькими ключевыми аспектами, связанными с областью видимости и контекстом выполнения.

Когда вы импортируете функцию из файла с помощью точечной нотации (. С:\путь\к\вашему\скрипту.ps1), она выполняется в контексте вызывающего скрипта, что означает, что все переменные и объекты, доступные в этом контексте, подвержены влиянию локальных настроек и данных. В вашем случае, если свойство times не существует в объекте DataRow, то условие if($Block.times -ne $Null) приводят к ошибке, поскольку PowerShell пытается получить доступ к этому отсутствующему свойству, что и вызывает сбой.

С другой стороны, когда функция содержится в модуле и импортируется с помощью Import-Module, она выполняется в своей собственной области видимости. Модули имеют своего рода изолированное окружение, в котором PowerShell интерпретирует отсутствие свойства times как несущественное. Это происходит благодаря тому, что PowerShell использует определенные механизмы обработки ошибок, позволяя обходить такие ситуации при работе с объектами. Поэтому, когда функция ищет свойство times, а его нет, PowerShell не выбрасывает исключение, а просто возвращает $null, что позволяет вашему коду продолжить выполняться.

Основные моменты, объясняющие различия в поведении:

  1. Область видимости (Scope):

    • Функции, загружаемые из файла, работают в контексте вызывающего скрипта.
    • Функции из модуля выполняются в своей изолированной области.
  2. Обработка отсутствующих свойств:

    • В контексте скрипта в случае отсутствия свойства PowerShell вызывает ошибку.
    • В модуле отсутствующее свойство игнорируется, что позволяет избегать сбоев.
  3. Безопасность и устойчивость к ошибкам:

    • Модули более устойчивы к ошибкам, и их код, как правило, более защищен от вызовов отсутствующих свойств или методов.

Для устранения различий и обеспечения надежности кода независимо от способа его импорта, вы можете внести изменения в вашу функцию, добавив предварительную проверку на наличие свойства times перед его использованием:

if ($Block.PSObject.Properties['times'] -and $Block.times -ne $Null) {
    $TimesElement = $Xml.CreateElement('times')
    $TradeDetailsElement.AppendChild($TimesElement) | Out-Null
    $TradeDetailsElement.times = [string]($Block.times)
}

Такой подход поможет избежать ошибочных ситуаций как в контексте файла, так и в модуле, что сделает ваш код более универсальным и надежным.

Оцените материал
Добавить комментарий

Капча загружается...