0

As below you can see that if files are not located at $FilesPath I try to search in $fallbackpath. The problem is that after I call to fallback the $compressedfiles is empty. maybe the ref for array is not right?

Function Init {
    $compressedfiles = @()
    $compressedfiles = Get-ChildItem -path $FilesPath\* -Include "*.vip", "*.zip", "*.cab"
    if (-Not $compressedfiles) {
        fallback
    }
}

Function fallback {
    $fallbackpath = '\\google.com\global\builds\PatchCreatorOutput'
    $compressedfiles = Get-ChildItem -path $fallbackpath\$FolderNumber\* -Include "*.vip", "*.zip", "*.cab"
    ([ref]$compressedfiles).Value = $compressedfiles
}

Update: In order to see the files from $compressedfiles after fallback I changed to this: (added return and global for the Init function)

Function Init {
        $compressedfiles = @()
        $compressedfiles = Get-ChildItem -path $FilesPath\* -Include "*.vip", "*.zip", "*.cab"
        if (-Not $compressedfiles) {
            fallback
        }


Set-Variable -Name "compressedfiles" -Value $compressedfiles -Scope global
    }
    
    Function fallback {
        $fallbackpath = '\\google.com\global\builds\PatchCreatorOutput'
        $compressedfiles = Get-ChildItem -path $fallbackpath\$FolderNumber\* -Include "*.vip", "*.zip", "*.cab"
        return $compressedfiles | out-null
    }
Bandit
  • 399
  • 3
  • 10
  • How do you determine that `$compressedfiles` is empty? There is nothing in the `Init` funtion that checks, shows or outputs the results... – iRon Dec 24 '22 at 10:44
  • if (-Not $compressedfiles) – Bandit Dec 24 '22 at 10:48
  • Besides `$compressedfiles = @()` is pointless as you overwrite the complete (empty array) assignment in the next stament. – iRon Dec 24 '22 at 10:48
  • ??? The `if (-Not $compressedfiles)` comes prior the (conditional) `fallback` invocation so that will never changed by that `fallback` function... Let me rephrase the question: How do you determine that "***after I call to fallback** the `$compressedfiles` is empty.*"? – iRon Dec 24 '22 at 10:51
  • If there are no files at $FilePath I calling fallback in order to find files then they should be seen at Init. Please try to answer my question how to pass the array. or let someone else to answer – Bandit Dec 24 '22 at 10:54
  • Its working when I added one more var between the function in order to pass the value – Bandit Dec 24 '22 at 10:55
  • How do you determine that "after I call to fallback the $compressedfiles is empty."? I know it/ there is no output for $compressedfiles. Its not working by ref and this is the main question here – Bandit Dec 24 '22 at 11:12
  • What are `$FilesPath` and `$FolderNumber` in your functions. Do these have a value in there? Shouldn't you pass them as parameter or otherwise use script: scope? Why not have function fallback return the array and have function init capture that like `$compressedfiles = fallback` ? Right now, you are not passing anything to any function which could be fine, but then inside the functions you need to refer to `$compressedfiles` as `$script:compressedfiles` where the variable itself has been declared **outside** the functions before calling them. – Theo Dec 24 '22 at 14:05
  • I completely surprised that in the update, you place the `Set-Variable -Name "compressedfiles" -Value $compressedfiles -Scope global` in the `fallback` function as I assumed that you wanted to change the `$compressedfiles` in the parent function... – iRon Dec 24 '22 at 14:50

2 Answers2

2

Continuing from my comment, you need to use Scoping to reference variables declared outside the functions in order to manipulate them.

Without scoping, these variables are simply new, local variables that exist in the function only.

Why not try

function Init {
    $script:compressedfiles = Get-ChildItem -Path $script:FilesPath -Recurse -Include "*.vip", "*.zip", "*.cab"
    if (-Not $script:compressedfiles) {
        $script:compressedfiles = fallback
    }
}

function fallback {
    $fallbackpath = '\\google.com\global\builds\PatchCreatorOutput'
    # just output
    Get-ChildItem -Path "$fallbackpath\$script:FolderNumber" -Recurse -Include "*.vip", "*.zip", "*.cab"
}

# Main script

# declare the variables you want the functions to see/manipulate here
# inside the functions you reference them with '$script:variablename'
$compressedfiles = $null  # declared outside the functions
$FilesPath       = '\\google.com\global\builds\SomeWhereToStartWith'
$FolderNumber    = 1
# call Init
Init
# show what $compressedfiles contains
$compressedfiles | Format-Table -AutoSize

Still guessing what you really want to do here, but you can of course also achieve this by eliminating the fallback function alltogether as it does nothing more than try and get a list of files from a different source path, with just a few extra lines in the init function.

This would also relieve you from the burdon of having to use scoping everywhere because now we can use local variables in the function.

# put your init helper function on top so it is defined before you use it in the main script
function Init {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$FilesPath,
        [Parameter(Mandatory = $true, Position = 1)]
        [string]$FallBackPath
    )
    $files = @(Get-ChildItem -Path $FilesPath -File -Recurse -Include "*.vip", "*.zip", "*.cab" -ErrorAction SilentlyContinue)
    if ($files.Count -eq 0) {
        # no files found in $FilesPath, so try the $FallBackPath
        Write-Host "No files found in $FilesPath.. Now trying $FallBackPath.."
        $files = @(Get-ChildItem -Path $FallBackPath -File -Recurse -Include "*.vip", "*.zip", "*.cab" -ErrorAction SilentlyContinue)
        if ($files.Count -eq 0) {
            Write-Host "No files found in $FallBackPath.."
            # no files in the fallbackpath either, return $null
            return $null
        }
    }
    # return the resulting files array.
    # because of 'unboxing' prefix this with a unary comma
    ,$files
}

# Main script
$folderNumber = 1
$filesPath    = Join-Path -Path 'X:\Somewhere\Builds\PatchCreatorOutput' -ChildPath $folderNumber
$fallBackPath = Join-Path -Path '\\google.com\global\builds\PatchCreatorOutput' -ChildPath $folderNumber
# call Init with parameters and capture the results in $compressedfiles
$compressedfiles = Init -FilesPath $filesPath -FallBackPath $fallBackPath
# show what $compressedfiles contains if anything
if (!$compressedfiles) {
    Write-Warning "Could not find any files in both the files path and the fallback path.."
}
else {
    $compressedfiles | Format-Table -AutoSize
}
Theo
  • 57,719
  • 8
  • 24
  • 41
  • thank you @Theo Can you please see my updated question? I noticed that when the fallback function return value its working return $compressedfiles | out-null. I added the global for anther functions that uses this also. It looks ok? – Bandit Dec 24 '22 at 16:55
  • Sorry its not really working..:( – Bandit Dec 24 '22 at 17:02
  • @Bandit you don't need `| Out-Null`, just output the result of Get-ChildItem in function `fallback` and capture the results when calling that function as I tried to show in my answer. – Theo Dec 24 '22 at 20:47
  • I don't want to to output the result. just use it..the variable return empty Its working only when I have more variable in the middle – Bandit Dec 24 '22 at 21:12
  • @Bandit you use it by **outputting** it from fallback and **capturing** that in function init – Theo Dec 24 '22 at 21:22
  • 2
    @Bandit, several us have tried to answer your question, but apparently we still don't understand where you looking for (or there is a contradiction in your question). Please, add an example (to your question) how you would like to "*just use it*". What is the input? (or use an "hardcoded" [mcve] example as in my answer). Show us what you **expected output** "*just use it*"and what is the **actual output** "*just use it*"? Also show us the difference with "*when I have more variable in the middle*". – iRon Dec 25 '22 at 09:42
  • Basically: [Demonstrate the problem. You should be able to say, “I expected the result to be X, it’s actually Y.” (You should actually say that too, so that we can check that we get the same results.)](https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/) – iRon Dec 25 '22 at 09:42
  • @Bandit Please see my edit. If this is still not what you are after, then please edit your question and provide a clear problem – Theo Dec 25 '22 at 11:46
1

([ref]$Item).Value changes the item of the closest parent that created it

Note that the Init function itself, is a child of the PowerShell prompt. meaning if you want to check the results of the $compressedfiles in the Init function scope you will need to output that. If you want to check the $compressedfiles at the prompt you probably want to use the global scope as answered by @Santiago Squarzon in you previous question about global variables.

Also note that the child fallback function should be defined prior the parent init function that uses it.

Function fallback {
    ([ref]$compressedfiles).Value = @('file3', 'file4')
}

Function Init ([switch]$CheckEmpty) {
    $compressedfiles = if (!$CheckEmpty) { @('file1', 'file2') }
    if (-Not $compressedfiles) {
        fallback
    }
    $compressedfiles # <-- output the value in the init scope
}
Init
file1
file2
Init -CheckEmpty
file3
file4
iRon
  • 20,463
  • 10
  • 53
  • 79
  • My code do the same... The $compressedfiles is empty. the ref is not working – Bandit Dec 24 '22 at 11:27
  • Note that the `Init` function itself, is a child of the PowerShell prompt. meaning if you want to check the results of the `$compressedfiles` in the `Init` function scope you will need to output that. If you want to check the `$compressedfiles` at the prompt you probably want to use the global scope as answered by [@Santiago Squarzon](https://stackoverflow.com/users/15339544/santiago-squarzon) in you previous [question about global variables](https://stackoverflow.com/q/74904517/1701026). – iRon Dec 24 '22 at 11:31
  • thank you for your trying but its not working...the $compressedfiles is empty in the Init but has value in the fallback. that means that the ref is not working. in order to solve this I added 1 more variable called $CompTemp at the fallback function and set to global ($CompTemp = $compressedfiles), and in the Init ($compressedfiles = $CompTemp) I want do do it by ref. – Bandit Dec 24 '22 at 11:42
  • The ref is started to working after I added the global to fallback Set-Variable -Name "compressedfiles" -Value $compressedfiles -Scope global Why its working like that? If I am using the ref why the global is needed as well? – Bandit Dec 24 '22 at 11:47
  • I noticed that its working without the ref, only the global is needed in the fallback function. make sense? – Bandit Dec 24 '22 at 11:56
  • The question was update. anyone can confirm this is the right solution? – Bandit Dec 24 '22 at 12:01