Я пишу рекурсивную функцию и хотел бы добавить режим отладки с некоторой информацией о вызывающем абоненте (функции) вместе с 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...