Hello there, I wrote a function that parse arrays content and returns list of items plus an item property. If I execute the single lines of the function I get the expected result, which is this:
while if I use the function in a script I only get the item property but not its name:
and here is the function I created:
function Get-ArrayContent {
param (
[Array[]]$array,
[string]$message,
[string]$destinationType
)
$i = 1
Write-Host $message -ForegroundColor Yellow
Write-Host "." -ForegroundColor Yellow
switch ($destinationType){
"datastore" {
$Datastores = $Array | Select-Object Name,@{N="Free Space %";E={[math]::Round(($_.FreeSpaceGB)/($_.CapacityGB)*100,2)}} | Sort-Object FreeSpaceGB -Descending
$Datastores | ForEach-Object{ Write-Host $i":" ($_.Name) -ForegroundColor White -NoNewline; Write-Host $_."Free Space %" "% Free" -ForegroundColor Yellow; $i++}
}
"ADGroup" { 'do something else'}
default { $Array | ForEach-Object{Write-Host $i":" $_.Name; $i++} }
}
Write-Host "." -ForegroundColor Green
$DSIndex = Read-Host "Enter a number ( 1 -" $Array.count ")"
$obj = $Array[$DSIndex - 1].Name
Write-Host "You have selected the $obj $destinationType" -ForegroundColor Green
Write-Host "." -ForegroundColor Green
Set-Variable -Name $destinationType -Scope Global -Value $obj
Start-Sleep -Seconds 2
}
and here the lines where I use the function in the script:
# Choose a Datastore to deploy to
$vmhost = Get-Cluster $Cluster | Get-VMHost | Select-Object -First 1
Get-ArrayContent -array (Get-VMHost $vmhost | Get-Datastore ) -destinationType "datastore" -message "Select onto which datastore to place $computer"
There are a couple of issues.
You are passing an Array, but your parameter definition says that you are passing an array of arrays.
[Array[]]$array,
Which is the reason why the Name property is not found.
You sort on a property (FreeSpaceGB) that is not on the object.
The object at that point in the pipeline only has the properties Name and 'FreeSpace %'
$Datastores = $Array | Select-Object Name,
@{N="Free Space %";E={[math]::Round(($_.FreeSpaceGB)/($_.CapacityGB)*100,2)}} |
Sort-Object FreeSpaceGB -Descending
What are you trying to with defining a variable with the same name as a parameter to your function?
Set-Variable -Name $destinationType -Scope Global -Value $obj
The following should do what you want it to do
function Get-ArrayContent {
param (
[PSObject[]]$array,
[string]$message,
[string]$destinationType
)
$i = 1
Write-Host $message -ForegroundColor Yellow
Write-Host "." -ForegroundColor Yellow
switch ($destinationType){
"datastore" {
$Datastores = $Array | Select-Object Name,
@{N="Free Space %";E={[math]::Round(($_.FreeSpaceGB)/($_.CapacityGB)*100,2)}} |
Sort-Object "Free Space %" -Descending
$Datastores | ForEach-Object{
Write-Host "$($i): $($_.Name) " -ForegroundColor White -NoNewline
Write-Host "$($_."Free Space %") % Free" -ForegroundColor Yellow
$i++
}
}
"ADGroup" { 'do something else'}
default { $Array | ForEach-Object{Write-Host $i":" $_.Name; $i++} }
}
Write-Host "." -ForegroundColor Green
$DSIndex = Read-Host "Enter a number ( 1 -" $Array.count ")"
$obj = $Array[$DSIndex - 1].Name
Write-Host "You have selected the $obj $destinationType" -ForegroundColor Green
Write-Host "." -ForegroundColor Green
# Set-Variable -Name $destinationType -Scope Global -Value $obj
Start-Sleep -Seconds 2
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
There are a couple of issues.
You are passing an Array, but your parameter definition says that you are passing an array of arrays.
[Array[]]$array,
Which is the reason why the Name property is not found.
You sort on a property (FreeSpaceGB) that is not on the object.
The object at that point in the pipeline only has the properties Name and 'FreeSpace %'
$Datastores = $Array | Select-Object Name,
@{N="Free Space %";E={[math]::Round(($_.FreeSpaceGB)/($_.CapacityGB)*100,2)}} |
Sort-Object FreeSpaceGB -Descending
What are you trying to with defining a variable with the same name as a parameter to your function?
Set-Variable -Name $destinationType -Scope Global -Value $obj
The following should do what you want it to do
function Get-ArrayContent {
param (
[PSObject[]]$array,
[string]$message,
[string]$destinationType
)
$i = 1
Write-Host $message -ForegroundColor Yellow
Write-Host "." -ForegroundColor Yellow
switch ($destinationType){
"datastore" {
$Datastores = $Array | Select-Object Name,
@{N="Free Space %";E={[math]::Round(($_.FreeSpaceGB)/($_.CapacityGB)*100,2)}} |
Sort-Object "Free Space %" -Descending
$Datastores | ForEach-Object{
Write-Host "$($i): $($_.Name) " -ForegroundColor White -NoNewline
Write-Host "$($_."Free Space %") % Free" -ForegroundColor Yellow
$i++
}
}
"ADGroup" { 'do something else'}
default { $Array | ForEach-Object{Write-Host $i":" $_.Name; $i++} }
}
Write-Host "." -ForegroundColor Green
$DSIndex = Read-Host "Enter a number ( 1 -" $Array.count ")"
$obj = $Array[$DSIndex - 1].Name
Write-Host "You have selected the $obj $destinationType" -ForegroundColor Green
Write-Host "." -ForegroundColor Green
# Set-Variable -Name $destinationType -Scope Global -Value $obj
Start-Sleep -Seconds 2
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Many thanks Luc! I misunderstood the syntax for declaring the array parameters... obviously now it works!
This part:
$obj = $Array[$DSIndex - 1].Name
Write-Host "You have selected the $obj $destinationType" -ForegroundColor Green
Write-Host "." -ForegroundColor Green
Set-Variable -Name $destinationType -Scope Global -Value $obj
prepares the variable that will be used later for this below:
New-VM -Name $computer -VMHost $vmhost -Datastore $Datastore -Location (Get-Folder $FOLDER -location $vDC) -ErrorAction Stop
I would return the selected object via a return, which you can then assign in the calling code to a variable.
Using variables in the Global scope to exchange data between caller and function can be tricky (and hard to debug)
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
thanks Luc I'll follow your advice! As I am planning to use it for multiple purpose I'll create a return variable into each switch case. Have a great weekend man!