themackyo
themackyo

Reputation: 413

Create array in function and use it another function

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

Upvotes: 1

Views: 274

Answers (1)

Bassie
Bassie

Reputation: 10380

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:)

Upvotes: 1

Related Questions