powershell indentation
I'm writing a large script that deploys an application. This script is based on several nested function calls.
Is there any way to "ident" the output based on the depth?
For example, I have:
function myFn()
{
Write-Host "Start of myfn"
myFnNested()
Write-Host "End of myfn"
}
function myFnNested()
{
Write-Host "Start of myFnNested"
Write-Host "End of myFnNested"
}
Write-Host "Start of myscript"
Write-Host "End of myscript"
The output of the script will be :
Start of myscript Start of myfn Start of myfnNested End of myFnNested End of myFn End of myscript
What I want to achieve is this output :
Start of mysc开发者_开发知识库ript Start of myfn Start of myfnNested End of myFnNested End of myFn End of myscript
As I don't want to hardly code the number of spaces (since I does not know the depth level in complex script). How can I simply reach my goal ?
Maybe something like this?
function myFn()
{
Indent()
Write-Host "Start of myfn"
myFnNested()
Write-Host "End of myfn"
UnIndent()
}
function myFnNested()
{
Indent()
Write-Host "Start of myFnNested"
Write-Host "End of myFnNested"
UnIndent()
}
Write-Host "Start of myscript"
Write-Host "End of myscript"
You could use a wrapper function around write-host
which used $MyInvocation
to determine the stack depth to create a number of spaces to prefix the message.
Combine this with the -scope ‹n›
parameter of Get-Variable
to pull out each calling level… something like the showstack
function adapted from Windows PowerShell In Action (Payette, 1st Ed):
function ShowStack {
trap { continue; }
0..100 | Foreach-Object {
(Get-Variable -scope $_ 'MyInvocation').Value.PositionMessage -replace "`n"
}
}
You'll need the maximum value of $_
in the pipeline before Get-Variable
fails for scope count being too high.
Check out this script http://poshcode.org/scripts/3386.html
If you load up that Write-Verbose wrapper, you can set $WriteHostAutoIndent = $true
and then just call Write-Host and it will be indented based on stack depth. So given these functions as you defined them originally:
function myFn()
{
Write-Host "Start of myfn"
myFnNested
Write-Host "End of myfn"
}
function myFnNested()
{
Write-Host "Start of myFnNested"
Write-Host "End of myFnNested"
}
With no changes, you can just dot-source a script file with that Write-Host wrapper function in it:
C:\PS> . C:\Users\Jaykul\Documents\WindowsPowerShell\PoshCode\3386.ps1
And then merely set the preference variable before you call your function:
C:\PS> $WriteHostAutoIndent = $true
C:\PS> myFn
Start of myfn
Start of myFnNested
End of myFnNested
End of myfn
Beautiful indented output, like magic ;-)
You can use Console.CursorLeft to set its position. Be aware that write-output will reset any custom location, so you need to reset it after each output. Here is a sample:
$i = 0 function Indent() { [console]::CursorLeft += 2 $i = [console]::CursorLeft $i } function UnIndent() { if($i -gt 0) { $i -= 2 } [console]::CursorLeft = $i $i } function WriteIndent([string]$s) { [console]::CursorLeft += $i write-host $s # Reset indent, as write-host will set cursor to indent 0 [console]::CursorLeft += $i } function myFnNested() { $i = Indent WriteIndent "Start of myFnNested" WriteIndent "End of myFnNested" $i = UnIndent } function myFn() { $i = Indent WriteIndent "Start of myfn" myFnNested WriteIndent "End of myfn" $i = UnIndent } WriteIndent "Start of myscript" myFn WriteIndent "End of myscript"
Output:
PS C:\scripting> .\Indent-Output.ps1 Start of myscript Start of myfn Start of myFnNested End of myFnNested End of myfn End of myscript
Write a DEBUG function. Two arguments, one is a flag that takes Start, Stop, or Note; the other argument should be the debug text. (I'd use 1, -1, and 0 for the flag, then you can just add the flag to a Indent variable to set increment depth. Stupid but good enough for debugging.)
I used another line of thinking. I set a count variable that is incremented at the start of the function and then used the following code to pad the line I was writing:
write-host ($string).PadLeft( ($string).length + (2 * $count) )
This will indent two spaces for every recursion.
You can override Write-Host
to write your indents before calling the original with the '&' operator and the namespace. You might be able to derive the amount of indentation from the current stack scope, but a global variable gives you more control.
$global:writeHostIndent
function Write-Host
{
Microsoft.PowerShell.Utility\Write-Host (' ' * $global:writeHostIndent) -NoNewline
& 'Microsoft.PowerShell.Utility\Write-Host' $args
}
精彩评论