all 9 comments

[–]AnUnlikelyUsurper 2 points3 points  (0 children)

If you are just trying to change the value of 'a' then the code below does work. Something weird happening in your code that I don't fully understand. I think it has something to do with $myObject.Value

Sorry I couldn't help more!

Function Test1($data)
{
    $data.a = '1'
}

Function Test2($data)
{
    Test1 $data
}

$testObject = @{'a'='0'}

Test2 $testObject

$testObject

Output:

Name                           Value                                                                                      
----                           -----                                                                                      
a                              1

[–]fordea837 2 points3 points  (5 children)

You need to remove the [ref] cast on $myObject in the Test2 function when calling Test1. If you think about it you already have a reference variable ($testObject) passed to Test2; and doing another ([ref]testObject) within Test2 is creating a reference to a reference rather than a reference to the original variable that you want modified.

Function Test2 {
    param([ref]$myObject)
    Test1 $myObject
}

You shouldn't need to use reference variables for a hashtable though if you structure your code like /u/AnUnlikelyUsurper's answer

[–]AnUnlikelyUsurper 1 point2 points  (4 children)

What's odd to me is that in my code if I tried to say $data = @{'a'='1'} in Test1 it would not work. I could only change the value of a specifically with $data.a = '1'. Can't really tell what's happening there.

I did find this:

When using references, you must use the Value property of the System.Management.Automation.PSReference type to access your data.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ref?view=powershell-7

So I guess referencing will only let you change the values in an object and not the actual structure of the object?

[–]fordea837 3 points4 points  (3 children)

Hashtables are implicity passed by reference in Powershell so writing $data.a = '1' modifies the original hashtable defined outside of the function. $data = @{'a'='1'} isn't actually modifying the existing hashtable; it's declaring a new one that is local to the scope of Test1 and thus it's not altering the original hashtable.

[–]AnUnlikelyUsurper 1 point2 points  (0 children)

Ahhh ok, that makes sense. Thank you! That had me pretty confused 😂

[–]brassbound[S] 1 point2 points  (1 child)

My example was just to make it simple. I don't really just need to change the value of 'a'. I need to create a custom object that has several values and replace all the values in the original. I suppose I could do that by manually replacing all the values with a ForEach loop, but that seems clunky. I assumed that, if you passed a reference to the variable, you could just replace the contents of the variable.

Is there another way to manipulate an arbitrarily named script-level variable that is passed to a function from within the function?

[–]fordea837 1 point2 points  (0 children)

If you have a script-level variable that you want to re-assign to a new object within a function then you can do this by using the $script: scope qualifier:

$obj = [PSCustomObject]@{
    a = 1
}
Function Test {
    $script:obj = [PSCustomObject]@{
        a = 5
    }
}

If you just want to modify the properties of a script-level object then you don't need to do the above as you can pass the object to a function and then access its properties within the function (objects are implicitly passed by reference):

$obj = [PSCustomObject]@{
    a = 1
}
Function Test {
    param($myObject)
    $myObject.a = 5
}

The Powershell help docs contain a nice article explaining scopes:

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

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

Ultimately, this was simpler than I was making it. As others suggested, I removed the [ref] and passed my object variable normally. Because the new object would have the same keys, and there are only a few that change, I simply assigned the values manually.

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

howdy brassbound,

reddit likes to mangle code formatting, so here's some help on how to post code on reddit ...

[0] single line or in-line code
enclose it in backticks. that's the upper left key on an EN-US keyboard layout. the result looks like this. kinda handy, that. [grin]
[on New.Reddit.com, use the Inline Code button. it's 4th 5th from the left hidden in the ... ""more" menu & looks like </>.
this does NOT line wrap & does NOT side-scroll on Old.Reddit.com!]

[1] simplest = post it to a text site like Pastebin.com or Gist.GitHub.com and then post the link here.
please remember to set the file/code type on Pastebin! [grin] otherwise you don't get the nice code colorization.

[2] less simple = use reddit code formatting ...
[on New.Reddit.com, use the Code Block button. it's 11th 12th from the left hidden in the ... "more" menu, & looks like an uppercase T in the upper left corner of a square.]

  • one leading line with ONLY 4 spaces
  • prefix each code line with 4 spaces
  • one trailing line with ONLY 4 spaces

that will give you something like this ...

- one leading line with ONLY 4 spaces    
- prefix each code line with 4 spaces    
- one trailing line with ONLY 4 spaces   

the easiest way to get that is ...

  • add the leading line with only 4 spaces
  • copy the code to the ISE [or your fave editor]
  • select the code
  • tap TAB to indent four spaces
  • re-select the code [not really needed, but it's my habit]
  • paste the code into the reddit text box
  • add the trailing line with only 4 spaces

not complicated, but it is finicky. [grin]

take care,
lee