Function returns bad values

Welcome Forums General PowerShell Q&A Function returns bad values

This topic contains 2 replies, has 3 voices, and was last updated by

 
Participant
1 week, 1 day ago.

  • Author
    Posts
  • #127467

    Participant
    Points: 6
    Rank: Member

    I have programmed for years in other languages... new to PowerShell.

    I have written a function that takes two strings as parameters.

    The function should return a string value (which could be just "").

    When I attempt to return the string and assign it to a variable, the variable suddenly contains the wrong values, and not the string that was assigned to the return variable on the line before the return.

    I cannot reproduce it creating a simple function.

    However... while writing this, I may have gotten closer to the cause (just by trying to explain myself).

    I have another function I wrote that does logging for me.  The function takes two required parameters (int, and string).  The integer is the debug level (whether or not to log it) and the string is "what to log".

    I instantiate the logger using something like (where outPFn is the full path/filename.ext to the log file):

    . "$($scriptpath)\rrLogger.ps1" -outPFn $outPFn -masterlvl 2

    Then the logger code looks like:

    # ———————————————————-
    param ([string] $outPFn, [int] $masterlvl)

    if(-not($outPFn)) { Throw ". /rrLogger... You must supply a value for -outPFn" }
    if(-not($masterlvl)) { $masterlvl=2 }

    function rrlog
    {
    Param ([int] $dbg, $msg)

    if ($dbg -le $masterlvl)
    {
    $lstmp=$(get-date -f 'yyyyMMdd_HHmmss')
    $outStr="$($lstmp): $($msg)"
    Write-Output "$($outStr)"
    Add-Content $outPFn "$($outStr)"
    }
    }
    # ———————————————————-

    So, a typical call to the logger looks something like:

    rrlog 2 "(L# 139):   theDriverWeWant: '$($theDriverWeWant)'"

    Which would produce a line in the log file something like:

    20181130_123654: (L# 139):   theDriverWeWant: "

    Without attempting to paste the entire (right now ugly) code here, the code looks something like:

    # ———————————————————-
    function GetDriver([string]$RegKey, [string]$oracle_home) {

    rrlog 2 "(L# 102):   RegKey: '$($RegKey)'"
    $theDriverWeWant="some string"
    return $theDriverWeWant
    }
    $theDriverWeWant = GetDriver $RegKey $oracle_home
    # ———————————————————-

    After running that, $theDriverWeWant contains something like:

    '20181130_123654: (L# 102):   RegKey:       hklm:\software\....'

    Rather than:

    'some string'

    How do I do logging with my function and still return the actual value of $theDriverWeWant, and not the total collection of all of the $outStr's I wrote to my log file?

    Or, maybe I should ask "How should I be doing logging?"

    Or, should I go back to the languages I actually know? 🙂

    Thanks in advance!!

  • #127573

    Keymaster
    Points: 1,673
    Helping HandTeam Member
    Rank: Community Hero

    Yeah, programming for years in other languages is a good way to head down the wrong path with PowerShell, unfortunately. :). Also, it'd help if you formatted your code blocks – they're a bit easier to follow that way. PowerShell isn't a programming language; it's a shell, and it behaves as a shell more than a programming language. But it LOOKS like a programming language, so it's a little misleading.

    PowerShell functions don't "return values." When you use return or Write-Output, they emit an object to the pipeline, and they're perfectly happy to emit multiple objects (that's actually the whole point of PowerShell). Also, since Write-Output is the default command, functions can emit a lot of output without you realizing they're doing it – as in the case of your rrlog command.

    The return keyword, outside of a v5 class, is actually incredibly misleading. Don't use it.

    For this:

    
    function GetDriver([string]$RegKey, [string]$oracle_home) {
    
    rrlog 2 "(L# 102):   RegKey: '$($RegKey)'"
    $theDriverWeWant="some string"
    return $theDriverWeWant
    }
    $theDriverWeWant = GetDriver $RegKey $oracle_home

    Any output rrlog produces will be dumped as output of your function.

    You're also doing some stuff that involves scope, and I'm not sure if it's intentional or not. I'd expect $theDriverWeWant to contain "some string" after running that as above, prefixed by any output produced by rrlog.

    If you want to suppress the output of rrlog:

    
    function GetDriver([string]$RegKey, [string]$oracle_home) {
    
    rrlog 2 "(L# 102):   RegKey: '$($RegKey)'" | Out-Null
    $theDriverWeWant="some string"
    return $theDriverWeWant
    }
    $theDriverWeWant = GetDriver $RegKey $oracle_home

    Now, I'd expect $theDriverWeWant to ONLY contain "some string".

  • #127594

    Participant
    Points: 265
    Helping Hand
    Rank: Contributor

    Just to add a little to what Don mentions, I'd probably point out that while piping to Out-Null is a perfectly good solution, be careful not to overuse it. The tricky part there is that it needs a pipeline created. If you're just adding it on the end of an existing pipeline, there's no real issue.

    However, instantiating a pipeline takes a small amount of processing time, which can be avoided pretty easily when you don't need it; just swap | Out-Null for > $null. This removes the dependency on a pipeline instance, and will speed up your commands appreciably — especially if you're creating advanced functions or need to run your function many times over in a loop or some similar instance.

You must be logged in to reply to this topic.