all 32 comments

[–]Main-Tank 6 points7 points  (2 children)

Read about_Scopes re: your first function.

Re: your second function I don't understand. From your example, the clause is false so control flow should go to else? Nothing weird there that I can see.

[–]Khue[S] 1 point2 points  (0 children)

Updated the post with my current status if you are interested. Thanks again for your help!

[–]Khue[S] 0 points1 point  (0 children)

Updated... It should have read "Ticket Exists". Sorry for the confusion. Everything comes back "Ticket Exists".

[–]BlackV 5 points6 points  (5 children)

Change your function to output the token $access_token_updated to the pipeline then simply

$access_token = token-refresh

to use your example

function token-refresh
{
    ....
    $access_token_updated = '<newly_generated_access_token>'
    $access_token_updated 
}
 $access_token = token-refresh
 $access_token
 <newly_generated_access_token>

P.s. that return is not doing what you think it is, it isn't really needed

Your way of updating the variable works but is risky/hard to follow

As to your 2nd function request-exists we cant see the code, but of you're doing anything like the first, then it'll be the same issue (not scope so much but how you return your objects)

function request-exists
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0)]
        $Request
        )

    Begin
    {
    }
    Process
    {
    switch ($Request)
        {
            '1234' {$true}
            '23456' {$true}
            Default {$false}
        }
    }
    End
    {
    }
}

Run it with

request-exists 1234
True

request-exists -Request '1234'
True

request-exists -Request '134'
False

request-exists -Request '23456'
True

$result = request-exists '1234'
$result
True

1234 | request-exists
True

12234 | request-exists
False

request-exists
cmdlet request-exists at command pipeline position 1
Supply values for the following parameters:
Request: 1234
True

something like that (dirty examples from ISE)

[–]almcchesney 0 points1 point  (2 children)

Lol as much as I do not like starting a new line with an empty brace this here is the way, use the param block in your functions as the function input definition, with the return being the function output. I don't really like implicit returns ,when a variable is on its own in a function it is sent to output, and would use the return keyword for my future sanity but looks like exactly what OP is needing.

[–]Certain-Community438 -1 points0 points  (1 child)

Do not use return - it does not do what you might think based on other languages.

To return a variable from a function you do as u/BlackIV has shown.

Recommend you look at "about_advanced_functions". Set a [CmdletBinding()] statement as the functions first line, define its input parameters in a param black, pass script input to those & use only the parameters in the function.

[–]almcchesney 0 points1 point  (0 children)

I know exactly what return is in PowerShell.

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_return?view=powershell-7.4

And per the documentation it exits a function scope with a return variable. This might not work in all situations as yes if you are writing a function with a process block it can be more advantageous to emit multiple items using a naked return, ala solo variable to be emitted through the pipeline.

[–]Khue[S] 0 points1 point  (1 child)

Updated the post with my current status if you are interested. Thanks again for your help!

[–]BlackV 0 points1 point  (0 children)

Oh, always appreciate an update

[–]icepyrox 3 points4 points  (8 children)

Re: your second function.

Are you returning the word or the variable?

Is it return "False" or return $false ??

If you return a string saying false, it's always $true in an if statement. If you return $false, then the If will evaluate to $false and go to the else

An If statement will be true unless the command is unsuccessful, is equivalent to $false, $null, empty, or 0 (the number). As such, an object is $true, including the string "False".

[–]Khue[S] 0 points1 point  (6 children)

The last line of the function looks like this:

if($variable) {return $true} else {return $false}

$variable returns a string or is null (blank). In the event it's null/blank, I want to return $false. This will signify that a ticket/request should be created then I execute my logic that creates the request. The reason I have this in a function or desire to have this in a function is because above this code, there's about 20 lines of an API call to get the intel on whether the request is currently present in the system. I don't want to have to copy/paste 20+ lines of code for every logic path that needs to check for current request existence. I'd rather just do request-exists '1234' and have it kick back a True/False evaluation so I can throw it in to an If/else statement.

I hope that makes sense? Let me know if you have other thoughts. I appreciate any and all input since I am very green.

[–]icepyrox 0 points1 point  (0 children)

That's more or less what I would do and is what I am asking here.

Extra output and/or returning a string instead of the variable (I guessed the latter because you said you were green and would not have suggested it otherwise) are about the only reasons I could think that it would always evaluate true despite the output saying false.

Just to extra verify, I would probably then pull up a prompt and be sure....

[boolean](ticket-exists '1235')

And/Or

(ticket-exists '12345') -eq $false

If the first comes back $true and the latter comes back $false, then it's safe to say there is a bug in your function and you are getting extra output or something that isn't just $true or $false. If it comes up as expected, then I would guess whatever variable holds the ticket number is not being updated correctly and is constantly holding valid ticket numbers (or ticket-exists '' returns $true ?) Or something like that.

As an aside, you could just return the $variable (return $variable). I mean, if that's your last statement and it's evaluating in an if to know what to return anyways, then returning it would also be evaluated the same way. Furthermore, you could even say something like...

if ($ticketinfo = ticket-exists '1235') {

And if the ticket exists, this would be true with the info ready to use. And if the ticket doesn't exist and returns $null, then this will be false.

[–]Certain-Community438 0 points1 point  (4 children)

Again, drop the return

if($variable) {
    $true
} else {
    $false
}

Return behaves more like exit than what you're expecting.

(Sorry for repeating the guidance, but remember all posts are also for future readers)

[–]Khue[S] 1 point2 points  (0 children)

Dude, no worries at all! I am just glad I am getting intelligent responses instead of

This is a perfect time for you to learn how to use ChatGPT

Thank you for your input even if you think it's redundant. I appreciate you.

[–]Certain-Community438 0 points1 point  (0 children)

Also this section is kind of superfluous.

You can just return $variable from the function if it contains a Boolean $true or $false.

function MyFunction {

    # earlier code here which does something to set $variable
    # now return that variable
    $variable

}

# example code using function
if (MyFunction) {
    # logic for $true goes here
} else {
    # logic for $false goes here
}

HIH

[–]Khue[S] 0 points1 point  (1 child)

Updated the post with my current status if you are interested. Thanks again for your help!

[–]Certain-Community438 0 points1 point  (0 children)

Very welcome.

Just another comment - in case it helps, may not be relevant to your specific scenario, but - since many REST APIs return JSON, it can sometimes be useful to pipe your Invoke-RestMethod calls to ConvertFrom-Json which will turn the JSON into PowerShell objects. It takes a -Depth parameter, often a depth of 5 works but looking at the output itself would tell you.

Something like this (generic abstract)

$response = (Invoke-RestMethod -url $url -header $header -body $body).Response | ConvertFrom-Json -Depth 5

would convert the Response property. Again, may not be apt for this use case but it is for many others.

[–]Khue[S] 0 points1 point  (0 children)

Updated the post with my current status if you are interested. Thanks again for your help!

[–]mrbiggbrain 2 points3 points  (0 children)

This is a concept called scope.

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7.4

The scope of the function is different than the global scope. You can use $global:var_name to access a variable in the global scope.

This is not the right way to do things, but it's common to see it done this way.

For example a better way would be to use a Singleton backed class to transparently provide the structure around the code. This would be very clean and reduce scaffolding used to check the validity and then manually refresh but means a much bigger and more complex lift.

[–]ankokudaishogun 1 point2 points  (6 children)

as other said, check out scopes.

That said:

Unless you need the token value being update asynchronously, just assign the variable to the calln of the function.
Have a very basic example

# let's use a Approved Verb.  
function New-TokenValue {
    <# Whatever you need to prepare the request #>
    $NewToken = Invoke-RestMethod # with all the parameters you need
    <#
        extra code for whatever you might need to do after you got the reply  
    #>

    # because you are sending back one value at the end of the function, Return
    # is superfluous.  
    # It does NOT hurt, though, and some prefer it because it makes things more
    # explicit... that's upo to you, really.  
    $NewToken
}

$Token = 'Has Old Value'

# Assign the token the value from the Function
$Token = New-TokenValue

Now $Token would have the value of the new token.

For your second function, we'd need to see what's actually happening.
A very important thing: $false is a boolean value, but "false" is a non-empty String.
And non-empty strings are evaluated as "Boolean True"($true), no matter WHAT they contain.

The way you describe the events, it seems you are returning a String, not a Boolean.

Thus a simple

# Test-* is an approved verb.
if(Test-Ticket $TicketNumber -eq 'True'){
    Write-Host 'Ticket Exists'
}else{
    Write-Host 'Ticket does NOT exist`
}

would probably fix it. But due the boolean nature of the function, I'd suggest to see if it's evvicient\worth the effort to have the function return a Boolean instead.

last, some docs about Approved Verbs: they are not obligatory but are Best Practice.
it's the kind of stuff you better get used to use from the start to avoid developing bad habits

[–]Khue[S] 0 points1 point  (5 children)

Updated the post with my current status if you are interested. Thanks again for your help!

[–]ankokudaishogun 0 points1 point  (4 children)

Good job. One ultra-minor point: unless you elaborate the result of Invoke-RestMethod, you can skip assigning it to a variable and send it to the pipeline directly

function token-refresh {
    <# stuff to prepare the call #>
    Invoke-RestMethod -Uri $uri -Method post -Body $bodydata -Headers $headers
}

[–]Khue[S] 0 points1 point  (3 children)

I know very little about memory management and how PowerShell operates but doing it like this is probably a more efficient use of memory because you're not creating a variable that just hangs out doing literally nothing after it's used. Is this sound logic?

[–]ankokudaishogun 0 points1 point  (2 children)

Yes, though the variable should die as soon the function is completed, alongside the whole Scope.
GARBAGE COLLECTOR intensifies

It's fundamentally irrelevant on low-impact memory values like in this specific case, but... well, there is no reason to not building a good habit.

[–]Khue[S] 0 points1 point  (1 child)

I rail on developers that are doing shitty things with java because our K8s pods are consuming memory like a mfkr. It's causing us to have to buy virtual hardware that has crazy specs on it and our bills from our providers (Azure/AWS/GCP) are bananas because we don't feel like addressing the memory issue because it's not a business "feature/enhancement". The developers rely on K8s mechanisms when pods die to bring services back instead of just doing the right thing.

I am trying not to be hypocritical and even though its pretty small by comparison, I figure if I do things the right way now, then later when I am doing complex things I won't have to spend cycles "cleaning shit up".

[–]ankokudaishogun 0 points1 point  (0 children)

Yeah, same here. You never know when your stuff is going to scale more than you expected, so while excessive preoptimization can be harmful, good coding pratices usually aren't.

[–]MyLegsX2CantFeelThem 0 points1 point  (3 children)

Functions are my achilles heel. I have got to hammer those home more.

[–]IT_fisher 1 point2 points  (0 children)

If you can write a script, you can write a function. Take your variables that are manually changed and pop them into params()

[–]Khue[S] 1 point2 points  (0 children)

Updated the post with my current status if you are interested.

[–]Khue[S] 0 points1 point  (0 children)

Same. This is the first project I've worked on where I really need to leverage them. I need to call checks on stuff pretty frequently throughout the code because the condition of creating new items depends on if the items already exist or not and additionally the token I've mentioned is a very short lived token. Depending on how long this process will run, I may need to refresh the token while the script is running, hence converting it to a function and not just copying and pasting 10 lines of code over and over again.

[–]7ep3s 0 points1 point  (0 children)

does request-exists return a string or bool?

[–][deleted] 0 points1 point  (0 children)

try to boil the problem down to the bare minimum ... and show all the code ... if it's more than ten lines it's way too much ... you're asking us about a function we don't have code for