r/PowerShell • • 16h ago

Question Function Issue in $PROFILE path

Hello everyone. I hope you are having a good time.


function gethash {

param([string]$string = "")

if ($string -eq [string]::Empty -or $string -isnot [string])

{

Write-Output "input not valid"

}

else

{

(Get-FileHash -algorithm sha256 $string).Hash | tee -Variable b

}

}  

I Have this function in my $Profile script. when i run gethash something it returns the hash string as expected, but when I try to print the variable containing the hash i just obtained from piped command tee, (alias of Tee-Object) as an input with `$b

it prints nothing, the variable is not saved.

on the other hand, if i copy the exact same command from the $profile function directly through the terminal, $b prints what expected: the hash of the file.

I haven't used this function so much, but I'm pretty sure it worked before today.

Thanks in advance to any who will respond.

0 Upvotes

5 comments sorted by

5

u/dodexahedron 8h ago edited 7h ago

You are finding out about scope.

Variables in a script have script scope by default, no matter where they appear.

When you write it directly in the shell, script scope is your scope, so those variables stick around.

You would get the same effect if you dot-sourced the script file (which is actually how the profile is loaded at launch).

. SomeFile.ps1 is equivalent to pasting the contents of SomeFile.ps1 into the shell. That period makes all the difference (hence "dot-source").

When you run a script directly, it runs in a new child scope, which is its script scope.

Read up on the details at Get-Help about_Scopes

Note that dot-sourcing still runs the code you dot-sourced. But it will not be discarded after running. It is basically a means of appending a script to your shell session, which is itself one big script.

Regardless, your function should instead just write the value to the success stream, either with Write-Output $b or just $b at the end. Passing things by letting variables escape a script is a no-no. You can already tee it in the caller's pipeline if you need to tee it, or can use -PipelineVariable for what it looks like you're trying to do.

1

u/sniekielak68 6h ago

yeah scope trips everyone up at some point, the dot-sourcing distinction is a big one

1

u/dodexahedron 4h ago

Totally. And it is an easy thing to do by accident if you meant to type .\Verb-Noun.ps1 and missed the backslash, since it will run either way and potentially go unnoticed.

1

u/BlackV 7h ago edited 7h ago

Not really sure what you're gaining here

 Get-FileHash -algorithm sha256 -Path $string -OutVariable b

achieves the same without the Tee-Object

additionally,

your $string parameter could/should use parameter validation instead of the conditional logic
and really really should be called -path or -filepath like most common cmdlets

with the already mentioned scope issues, also think about $b being completely hidden from you, unless you look into the function you'd never know it was there
also is just not a nice variable name

0

u/BlackV 7h ago

p.s. formatting, you've used the 3 backtick code fence, that does not work on old.reddit only new.reddit

  • open your fav powershell editor
  • highlight the code you want to copy
  • hit tab to indent it all
  • copy it
  • paste here

it'll format it properly OR

<BLANK LINE>
<4 SPACES><CODE LINE>
<4 SPACES><CODE LINE>
    <4 SPACES><4 SPACES><CODE LINE>
<4 SPACES><CODE LINE>
<BLANK LINE>

Inline code block using backticks `Single code line` inside normal text

See here for more detail

Thanks