Я пишу рекурсивную функцию и хотел бы добавить режим отладки с некоторой информацией о вызывающем абоненте (функции) вместе с ScriptLineNumber.
В PowerShell 7 я могу сделать что-то вроде:
MyScript.ps1
[CmdletBinding()]param()
function MyFunction($Depth = 0) {
if ($DebugPreference -in 'Stop', 'Continue', 'Inquire') {
$Caller = (Get-PSCallStack)[1]
Write-Debug "Caller: $($Caller.FunctionName), Line: $($Caller.ScriptLineNumber)"
}
Write-Host 'Current depth:' $Depth
if ($Depth -lt 1) { MyFunction ($Depth + 1) }
}
MyFunction
.\MyScript.ps1 -Debug
DEBUG: Caller: <ScriptBlock>, Line: 11
Current depth: 0
DEBUG: Caller: MyFunction, Line: 8
Current depth: 1
Как это сделать в Windows PowerShell 5.1?
Мне не хватает знаний C#, но я думаю, что ответ скрыт в этом коде C#, но я понятия не имею, откуда взялся Context.Debugger.GetCallStack()...
Ваш код дал те же результаты как в версии 5.1, так и в версии 7.4.5. Если у вас это не так, возможно, у вас что-то не так с 5.1.
@Darin, @MathiasR.Jessen, упс, в моем сценарии была опечатка: Get-CallStack вместо Get-PSCallStack (спасибо за ваш отзыв).
@iRon Откуда Profiler? Get-CallStack требует объекта попадания bp от трассировщика в качестве обязательного аргумента параметра, поэтому опубликованный вами код никогда не будет работать, если мы заменим Get-PSCallStack на Get-CallStack. Если вы имеете в виду другой модуль, сообщите нам, какой :)





Прежде чем ответить, я должен отметить, что Get-PSCallStack доступен в Windows PowerShell 5.1 и с тех пор не менялся, поэтому это упражнение, скорее всего, совершенно бесполезно.
Мне не хватает знаний C#, но я думаю, что ответ скрыт в этом коде C#, но я понятия не имею, откуда взялся
Context.Debugger.GetCallStack()...
Context является защищенным членом PSCmdlet (точнее, его классом-предком InternalCommand), поэтому вы можете вызвать его из метода экземпляра, объявленного производным типом (например, классом GetPSCallStackCommand).
Поскольку у нас нет доступа к непубличному члену изнутри PSScriptCmdlet, нам понадобится немного магии отражения:
function Get-PSScriptCallStack {
[CmdletBinding()]
param()
$nonPublicInstanceFlags = [System.Reflection.BindingFlags]'Instance,NonPublic'
$member_psCmdletContext = $PSCmdlet.GetType().GetMembers($nonPublicInstanceFlags).Where({ $_.Name -eq 'Context' })[0]
$contextInstance = $member_psCmdletContext.GetValue($PSCmdlet, @())
$member_contextDebugger = $contextInstance.GetType().GetMembers($nonPublicInstanceFlags).Where({ $_.Name -eq 'Debugger' })[0]
$debuggerInstance = $member_contextDebugger.GetValue($contextInstance, @())
# Debugger.GetCallStack() is public
$debuggerInstance.GetCallStack()
}
В чем именно заключается ваш вопрос?
Get-PSCallStackуже доступен в 5.1...