PowerShell: Function doesn't have proper retur

2019-06-26 20:11发布

问题:

I wrote a powershell script to compare the content of two folders:

$Dir1 ="d:\TEMP\Dir1"
$Dir2 ="d:\TEMP\Dir2"

function Test-Diff($Dir1, $Dir2) {
    $fileList1 = Get-ChildItem $Dir1 -Recurse | Where-Object {!$_.PsIsContainer} | Get-Item | Sort-Object -Property Name
    $fileList2 = Get-ChildItem $Dir2 -Recurse | Where-Object {!$_.PsIsContainer} | Get-Item | Sort-Object -Property Name

    if($fileList1.Count -ne $fileList2.Count) {
        Write-Host "Following files are different:"
        Compare-Object -ReferenceObject $fileList1 -DifferenceObject $fileList2 -Property Name -PassThru | Format-Table FullName
        return $false
    }

    return $true
}

$i = Test-Diff $Dir1 $Dir2

if($i) { 
    Write-Output "Test OK" 
} else { 
    Write-Host "Test FAILED" -BackgroundColor Red
}

If I set a break point on Compare-Object, and I run this command in console, I get the list of differences. If I run the whole script, I don't get any output. Why?

I'm working in PowerGUI Script Editor, but I tried the normal ps console too.

EDIT:

The problem is the check on the end of the script.

$i = Test-Diff $Dir1 $Dir2

if($i) { 
   Write-Output "Test OK" 
...

If I call Test-Diff without $i = check, it works!

Test-Diff returns with an array of objects and not with an expected bool value:

[DBG]: PS D:\>> $i | ForEach-Object { $_.GetType() } | Format-Table -Property Name
 Name                                                                                                                        
 ----                                                                                                                        
 FormatStartData                                                                                                             
 GroupStartData                                                                                                              
 FormatEntryData                                                                                                             
 GroupEndData                                                                                                                
 FormatEndData                                                                                                               
 Boolean         

If I comment out the line with Compare-Object, the return value is a boolean value, as expected.

The question is: why?

回答1:

I've found the answer here: http://martinzugec.blogspot.hu/2008/08/returning-values-from-fuctions-in.html

Functions like this:

Function bar {
 [System.Collections.ArrayList]$MyVariable = @()
 $MyVariable.Add("a")
 $MyVariable.Add("b")
 Return $MyVariable
}

uses a PowerShell way of returning objects: @(0,1,"a","b") and not @("a","b")

To make this function work as expected, you will need to redirect output to null:

Function bar {
 [System.Collections.ArrayList]$MyVariable = @()
 $MyVariable.Add("a") | Out-Null
 $MyVariable.Add("b") | Out-Null
 Return $MyVariable
}

In our case, the function has to be refactored as suggested by Koliat.



回答2:

I have modified the bit of your script, to make it run the way you want it. I'm not exactly sure you would want to compare files only by the .Count property though, but its not within the scope of this question. If that wasn't what you were looking after, please comment and I'll try to edit this answer. Basically from what I understand you wanted to run a condition check after the function, while it can be easily implemented inside the function.

$Dir1 ="C:\Dir1"
$Dir2 ="C:\Users\a.pawlak\Desktop\Dir2"

function Test-Diff($Dir1,$Dir2)
{
$fileList1 = Get-ChildItem $Dir1 -Recurse | Where-Object {!$_.PsIsContainer} | Get-Item | Sort-Object -Property Name
$fileList2 = Get-ChildItem $Dir2 -Recurse | Where-Object {!$_.PsIsContainer} | Get-Item | Sort-Object -Property Name

if ($fileList1.Count -ne $fileList2.Count)
{
Write-Host "Following files are different:"
Compare-Object -ReferenceObject $fileList1 -DifferenceObject $fileList2 -Property FullName -PassThru | Format-Table FullName
Write-Host "Test FAILED" -BackgroundColor Red

}
else 
{ 
return $true
Write-Output "Test OK" 
}
}

Test-Diff $Dir1 $Dir2

If there is anything unclear, let me know

AlexP