1

I have a program which gets VM information for a given user. It uses a menu system and the function REFRESH_LIST creates an array, creates an object containing VM information (ip address, name, etc.) and puts it into the array so the array is an array of objects which is as big as the amount of VMs the user has.

I then use this array to populate a table to display all the information to screen. I have another function START_INSTANCE which will start the VM based on the name of the VM but in an effort to check and make sure the user is only starting VMs assigned to them I want to go back into the array and check the VM name they entered exists in the array.

The issue I have is the array was built in one function and I need it in another. In reading I found it is a scope issue $script:var I built simple test functions and got a variable to be usable in another function when I apply that same $script:var to the array it is still not usable anywhere else.

Is there anything special with arrays or is there more to it than just scope ?

FUNCTION GET_HELP {
    ECHO ""
    ECHO " refresh  : REFRESH VM LIST" 
    ECHO " start    : START INSTANCE    : start <instance-id>"
    ECHO " stop     : STOP INSTANCE     : stop <instance-id>"
    ECHO " q        : QUIT"
    ECHO ""
}

FUNCTION INSTANCE_START {

    $i=0
    $CHECK=""
    $a.Length
    While ($i -le $a.Length) { 
    echo $CHECK
        If ($a[$i].INSTANCEID -contains $INSTANCEID) {
            $CHECK = "TRUE"}
        $i = $i+1
    Echo $CHECK
    }
    echo $CHECK
    IF ($CHECK = "TRUE") {
        #Start-EC2Instance -InstanceId 
        "STARTING " + $INSTANCEID
        ECHO $CHECK}
    ELSE {
    $CHECK=""
    "NO"}
    $INSTANCEID = ""
}

FUNCTION INSTANCE_STOP {
    #Stop-EC2Instance -InstanceId 
}
FUNCTION REFRESH_LIST {
Clear-Host
" LOADING VM LIST FOR "+$USERNAME
$date = get-date -format "MM/dd/yyyy HH:mm:ss"
$Global:a = @()
(Get-EC2Instance).instances | ? {$_.Tags.Key -eq "NAME" -and $_.Tags.Value -eq $TEST_USER} | ForEach-Object {
        $instobj = New-Object System.Object
        $instobj | Add-Member -Type NoteProperty -Name STATE -value $_.state.name
        $instobj | Add-Member -type NoteProperty -name INSTANCEID -value $_.InstanceID
        $instobj | Add-Member -type NoteProperty -name IPADDRESS -value $_.PublicIPAddress
        IF ($_.state.name -eq 'running'){
            $time=New-TimeSpan -Start $_.LaunchTime -End $date
            $val="{0}d {1}h {2}m" -f $time.Days, $time.Hours, $time.Minutes
            $instobj | Add-Member -Type NoteProperty -Name TIME -value $val}
        else{$instobj | Add-Member -Type NoteProperty -Name TIME -value ""}
        $a += $instobj}
For ($i=0; $i -le $a.Length-1; $i++){
    $instanceTags = Get-EC2Tag -Filter @{ Name="resource-id"; Values=$a[$i].INSTANCEID } 
    $a[$i] | Add-Member -type NoteProperty -name PROJECT -value $instanceTags.Where({$_.Key -eq "Project"}).Value
    $a[$i] | Add-Member -type NoteProperty -name NAME -value $instanceTags.Where({$_.Key -eq "Name"}).Value
    $a[$i] | Add-Member -type NoteProperty -name SOFTWARE -value $instanceTags.Where({$_.Key -eq "Oracle SW"}).Value
}
Clear-Host
echo $date
$a | sort STATE, PROJECT, NAME |Format-Table STATE, INSTANCEID, IPADDRESS, PROJECT, NAME, SOFTWARE, TIME -AutoSize
}

#REGION MAIN

REFRESH_LIST
DO {
$SELECTION = Read-Host ">"
$COMMAND,$INSTANCEID = $SELECTION.split(' ',2)
    SWITCH ($COMMAND) {
        '-h' {GET_HELP}
        'refresh' {REFRESH_LIST}
        'start' {INSTANCE_START}
        'stop' {'STOPPING INTANCE'}
        'q' {BREAK}
        DEFAULT {'ENTER -h FOR HELP'}
     }}
 until ($COMMAND -eq 'q')

 #ENDREGION

1 Answer 1

1

One way to resolve this would be to assign the array in the $Global: scope:

$Global:arr

Some example code:

function one {
    $Global:arr = @(1, 2, 3)
}

function two {
    one
    $arr
}

two

This outputs:

1
2
3

See ss64 or run help about_Scopes for more details.


In the code that you posted, you could try:

$Global:a = @() in REFRESH_LIST

This small example is more reflective of your code:

function one {
    $Global:a = @(1,2,3)
}

function two {
    echo $a.Length
}

one
two

Where the output is 3


As mentioned in the comments, this also works with $Script, and is preferable in your case. However, to ensure you are calling the same instance of the array each time, every time you use if you need to prefix it with whichever scope you decided to declare it into ($Global: or $Script:)

Sign up to request clarification or add additional context in comments.

9 Comments

I don't want to call function one in function two. When I start the program it runs REFRESH_LIST which is where the array is built. Since that function takes some time to complete I really only want to run it once unless I specificity say run it again. I then have a switch menu which if I type in start <host name> I want it to take the <host name> I entered look into the array and come back with yes or no. Its an effort to check for miss types.
@themackyo Did you try declaring the array with $Global: inREFRESH_LIST? You really should post some code as without it is much more difficult to help.
I posted some code and have tried setting the array to $Global the array seems empty.
@themackyo I see that you put the $Global: in front of the function name rather than the array declaration - did you try putting the actual array in the global scope, like in my updated answer?
Yes, I tried both ways global:refresh_list and $global:a. The array seems empty both ways.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.