0

In this snippet I have a function (FDiskScan) that gets a computer name as an input and should return an array of objects.

function FDiskScan ([String] $name)
{
    $outarray = [System.Collections.ArrayList]@()
    $diskscan = Get-WmiObject Win32_logicaldisk -ComputerName $name

    foreach ($diskobj in $diskscan)
    {
        if($diskobj.VolumeName -ne $null ) 
        {
            $max = $diskobj.Size/1024/1024/1024
            $free = $diskobj.FreeSpace/1024/1024/1024
            $full = $max - $free

            $obj = @{ 
                'ID' = $diskobj.deviceid
                'Name' = $diskobj.VolumeName
                'TotalSpace' = $max
                'FreeSpace' = $free
                'OccupiedSpace' = $full }
            $TMP = New-Object psobject -Property $obj
            $outarray.Add($TMP) 
        }
    }
    return $outarray
}

$pc = "INSERT PC NAME HERE"
$diskdata = [System.Collections.ArrayList]@()
$diskdata = FDiskScan($pc)

foreach ($disk in $diskdata) 
{
   Write-Host "Disco: " $disk.ID
   Write-Host "Espaço Total: " ([math]::Round($disk.TotalSpace, 2)) "GB"
   Write-Host "Espaço Ocupado: " ([math]::Round($disk.OccupiedSpace, 2)) "GB"
   Write-Host "Espaço Livre"  ([math]::Round($disk.FreeSpace, 2)) "GB" "`n"
}

Within the function with debugging and going into the variables I can see that everything is alright, and when the array gets out of the function and into the script scope it adds 2 more entries.

While in debug mode it tells me that $outarry within FDiskScan has the two disks that I have on my system organised as they should be.

However on:

$diskdata = FDiskScan($pc)

It says that it has an entry of value 0 on index 0 and of value 1 on index 1, then the disks follow suit, first disk C: in index 3 and disk D in index 4.

The expected behaviour was for index 0 and 1 having disks C and D respectively not a phantom 0 and 1 entries.

rufer7
  • 3,369
  • 3
  • 22
  • 28
Muttsuri
  • 28
  • 1
  • 4
  • @PhaniAnne's One thing to be aware of: `$diskdata = FDiskScan($pc)` is not the correct way to call a function with PowerShell. The correct way is `$diskdata = FDiskScan $pc`. The incorrect way will work with a single argument function, but once you get to two arguments, like `$diskdata = FDiskScan2($pc, $DriveType)` it will not work like you expect. – Bacon Bits Dec 29 '17 at 07:48
  • You think you're calling a function with argument 1 = `$pc` and argument 2 = `$DriveType`, but what you're really doing is calling the function with argument 1 = an array of `($pc, $DriveType)` and argument 2 is null. The correct way to call the function would be `$diskdata = FDiskScan2 $pc $DriveType`. – Bacon Bits Dec 29 '17 at 07:48
  • @BaconBits The fucntion is ment to have only one argument, at least for now. But I thank you anways for refering me to the better way of writting arguments. I have better notion of C like syntax, so sometimes I get mixed but with some of the details of languages like powershell. – Muttsuri Dec 29 '17 at 23:33

2 Answers2

2

You are seeing 0, 1 because of this line - $outarray.Add($TMP). Change it to $outarray.Add($TMP) | Out-Null. I think PowerShell is printing the index when adding to the array.

scorpion35
  • 944
  • 2
  • 12
  • 30
  • After searching about it, it seems that the Add method of the ArrayList object besides adding prints out the index to which it was added. What that does is ignore said output, and I also found the variants: `$null = $outarray.Add($TMP) $outarray.Add($TMP) > $null` NOTE: The `$null = $outarray.Add($TMP)` was presented in the other responce by @rufer7 – Muttsuri Dec 29 '17 at 23:29
  • Sorry for the double comment, but I stumbled on this [thread](https://stackoverflow.com/questions/5260125/whats-the-better-cleaner-way-to-ignore-output-in-powershell). Which seems to indicate that other options would be genraly better than piping to Out-Null. Opinions ? And yes I am clear that it's needles in and pointless in this case, I juse like to pick up the best practices a long the way. – Muttsuri Dec 29 '17 at 23:40
  • @AlexanderCorreia It's good to pick up on best practices, but I wouldn't worry about performance unless the app is running really slow. Feel free to run Measure-Command cmdlet as shown in your link, and find out which is faster, if you have time! There is *always* a better way; you might lose time trying to find the "best" way, for little gain. – scorpion35 Dec 30 '17 at 23:22
2

When adding an object to an array list in PowerShell (i.e. $outarray.Add($TMP)) the index, the object was added at, gets returned. As you don't assign the return value to a variable the function returns a System.Array containing the indexes and the entries of the array list returned by return $outarray. That's the reason why your functions return value contains 4 elements. Furthermore your functions return value in this case is not of type System.Collections.ArrayList but of type System.Array. To avoid that behaviour do the following.

$null = $outarray.Add($TMP);
rufer7
  • 3,369
  • 3
  • 22
  • 28
  • You refeered that the function's return type is `System.Array` instead of `` `System.Collections.ArrayList`. Since the unintended effect was was due to the out put of the Add method, could you tell me what and how does the type of the fucntion is affcting, and how to declared the output type of a function – Muttsuri Dec 29 '17 at 23:36
  • PowerShell is a dynamically, implicit typed script language. That means that a variable can change its type at runtime. Furthermore there is no possibility to define the output type of a function. The type of the return value depends on the value returned by the return statement. If there are other non assigned values returned by a Cmdlet (i.e. like in the question) these values get added to the return value which then will be an array containing all the elements. – rufer7 Dec 30 '17 at 17:23