Answered Get script line number

  • Friday, January 11, 2013 4:26 PM
     
     

    Is there a way to capture the line number of a script, even if there is no error on that line?

    When writing long scripts, I am also writing output to a log file to show the progress through the script.  What I would like to be able to do is to include the line number of the script when an entry is made into the log file.  This would speed the process of debugging when I review the log file.  Then I could see an entry where my log file shows something out of order, but it did not generate any PowerShell error.  I could quickly jump to the point in my script if I had the line number.  Of course, it would also make it easier for someone else coming along afterwards who is not as familiar with my script as I am to quickly get to the section of code.

    Thanks for any pointers.


    .:|:.:|:. tim

All Replies

  • Friday, January 11, 2013 4:45 PM
    Moderator
     
     Answered Has Code

    Hi,

    Try


    (get-pscallstack)[0].Location

    Bill

  • Friday, January 11, 2013 6:04 PM
     
     
    Thank you, sir!  Just what I was looking for.

    .:|:.:|:. tim

  • Friday, January 11, 2013 8:11 PM
     
     

    But, I guess I am missing something in how it works.

    When I create a script within ISE and run it, it works just like I need.  But when I execute the exact same script from the PowerShell window, running the script by .\ the file name, nothing is returned.  Same if I execute it from the command window in ISE.  It only seems to work if I F5 the script in ISE.


    .:|:.:|:. tim

  • Friday, January 11, 2013 8:16 PM
    Moderator
     
     

    Works fine for me from a PowerShell console (not ISE).

    Bill

  • Friday, January 11, 2013 8:36 PM
     
      Has Code
    Here's the quick and dirty script I put together to test.  In my real code, my Write-Log function can be called by other functions, so I wanted to ensure that I get the line number of the my code that initiated everthing, so I grab the end of the stack.

    Function Write-Log ($content) { $stack = get-pscallstack $i = $stack.length $i-- $tmp = (get-pscallstack)[$i].Location -split " line " $lineNum = $tmp[1] Write-Host "$lineNum $(Get-Date -Format "HH:mm:ss") - $content" } Function Test ($content) { $content = $content + "more" Write-Log $content }

    write-log "stuff"

    test "stuff"

    It works exactly as I want it when I F5, but saving to a file and trying to execute returns no value.

    .:|:.:|:. tim

  • Friday, January 11, 2013 8:56 PM
    Moderator
     
      Has Code

    Hi,

    I see a mistake in your function. Since you're using $stack.Length, you need to decrement $i by 2 (Length property will be highest array index + 1). It works for me this way:


    Function Write-Log($content) {
      $stack = get-pscallstack
      $i = $stack.Length - 2
      $tmp = (get-pscallstack)[$i].Location -split " line "
      $lineNum = $tmp[1]
      Write-Host "$lineNum $(Get-Date -Format "HH:mm:ss") - $content"
    }
    

    I shortened it thus:


    Function Write-Log($content) {
      $n = (get-pscallstack).Length - 2
      $lineNum = ((get-pscallstack)[$n].Location -split " line ")[1]
      Write-Host "$lineNum $(Get-Date -Format "HH:mm:ss") - $content"
    }
    

    Bill

  • Friday, January 11, 2013 9:18 PM
     
      Has Code

    Thanks, Bill.  I was just finding the same thing by inserting a bunch of write-host statements to see what was actually happening.  But what is very strange is that the script actually returns different results when run from ISE versus run from the command line.  If I subtract 2 within ISE, it doesn't work correctly.  If I subtract 2 for running as a script from the command line, it works fine.  $stack.length actually returns different values when run in the different environments.  I can live this as I now have it working, but any idea why that difference exists?

    Here's the output (after I inserted your optimized code).  Basically I hit F5 in ISE and then go to a command prompt right after, so they are working from the exact same file.

    # Output from F5 within ISE
    4 15:13:11 - stuff
    10 15:13:11 - more stuff
    
    #Output from command line .\getline.ps1
    12 15:13:22 - stuff
    13 15:13:22 - more stuff

    BTW, thanks for cleaning up my code.  Always learning here and I really enjoy seeing how things can be done in a better manner.


    .:|:.:|:. tim

  • Friday, January 11, 2013 9:33 PM
    Moderator
     
     

    Try entering your script's name in the ISE, rather than pressing F5.

    Bill

  • Friday, January 11, 2013 10:12 PM
     
     

    Yes, that works, but it sort of defeats the purpose of F5. :)

    What is interesting is that when I press F5, ISE will put the name of the script into the PowerShell window, and it executes one way.  If I copy the name of the script that F5 placed into that window and execute it, it excutes differently.  Below - first is F5.  Second is cut/paste.

    PS C:\Windows\system32> C:\Users\tcerling\Documents\Scripts\getline.ps1
    4 15:53:45 - stuff
    10 15:53:45 - more stuff

    PS C:\Windows\system32>  C:\Users\tcerling\Documents\Scripts\getline.ps1
    12 15:53:56 - stuff
    13 15:53:56 - more stuff

    What I am beginning to think is happening is that ISE is executing it within the same scope it is running in, whereas when executed directly from the command line it creates a child scope. The reason I say this is that when I was putting in debug lines, I saw that within ISE, only the very last entry of the array returned from the Get-PsCallStack started with 'at <ScriptBlock>'. But, when executing it from the PowerShell window, the last two entries of the array started with 'at <ScriptBlock>', hence always having more entries in the returned array. When running from the command prompt, the last entry was 'at <ScriptBlock>, <No file>: line1'. The second to last entry was the same as the last entry while running in ISE, and that had the file name and proper line number.


    .:|:.:|:. tim

  • Friday, January 11, 2013 10:19 PM
    Moderator
     
     Answered
    What I am beginning to think is happening is that ISE is executing it within the same scope it is running in, whereas when executed directly from the command line it creates a child scope.

    Your analysis is correct.

    Bill