1

I have 10 variables, called rows($row1, $row2, $row3...), I need the user to choose from one of this variables only knowing the right row, I'm struggling to understand how to connect text to a variable, that corrisponds to another variable and get the value, not to write it as text

$ChoosenRow = Read-Host
$rownumber = $("row" + $ChoosenRow)
$IP = Write-Output $rownumber 

If I input 10, I get $IP = row10 I'm trying to get $IP to become the value of $row10, not as a string.

Sorry for my broken english and my stupid question, I tried to search similar questions but didn't found any

Edit: iRon asked me to put more of the script:

# Carica il file e crea le variabili per il file
$FilePath = '\\ntced\CED\AssistenzaPC\IP IN GESTIONE\2021-08-16 TabellaIP.xls'
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $true
$wb = $xl.Workbooks.Open($filepath)

# Prendi la prima colonna
$data = $wb.Worksheets['Foglio1'].UsedRange.Rows.Columns[1].Value2
$data2 = $wb.Worksheets['Foglio1'].UsedRange.Rows.Columns[2].Value2

# Chiudi excel aperto per prendere i dati
$wb.close()
$xl.Quit()
While([System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb) -ge 0){}
while([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl) -ge 0){} 
Remove-Variable xl,wb # Rimuovi le due variabili create

# display results
$data | select -skip 1 # Rimuove il titolo sopra

# Variabili degli IP

$variables = @()
$i = 0
foreach ($row in ($data -split [Environment]::NewLine)) {
  # Crea una variabile per ogni riga
  New-Variable -Name "row$i" -Value $row
  # e un membro dell'array
  $variables += [pscustomobject]@{Name = "row$i"; Value = $row} # Copiato male, era troppo complicato arrivarci
  $i++
}

$variables2 = @()
$ii = 0
foreach ($linea in ($data2 -split [Environment]::NewLine)) {
  # Crea una variabile per ogni riga
  New-Variable -Name "linea$ii" -Value $linea
  # e un membro dell'array
  $variables2 += [pscustomobject]@{Name = "linea$ii"; Value = $linea} 
  $ii++
}

function Show-Menu
{
 param (
 [string]$Title = 'Scegli IP'
 )
 Clear-Host
 Write-Host "================ $Title ================"
 Write-Host "1: Cambia IP da tabella IP nuovi"
 Write-Host "Q: premi 'Q' per uscire."
}

Show-Menu –Title 'Scegli IP'
$selection = Read-Host 'Scegli la'

switch ($selection)
 {
     '1' {
         ' Scrivi la linea che contiene IP libero'

         $LineaScelta = Read-Host
         $rownumber = $("row" + $LineaScelta)

          $IP = Write-Output $rownumber
          $MaskBits = 20 # subnet mask in bits = 255.255.240.0
          $Gateway = "172.16.111.254"
          $Dns = "172.16.16.1"
          $IPType = "IPv4"
     } 

     'q' { 
           return
         }
 }

  # Imposta su tutte le schede di rete attive, quindi tenere acceso solo quella necessaria!
$adapter = Get-NetAdapter | ? {$_.Status -eq "up"}

# Rimuove gli IP prima di metterli 
If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) {
 $adapter | Remove-NetIPAddress -AddressFamily $IPType -Confirm:$false
}

If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) {
 $adapter | Remove-NetRoute -AddressFamily $IPType -Confirm:$false
}

 # Configura gli IP, CHE BESTEMMIE PER CAPIRE COME USARE

$adapter | New-NetIPAddress `
 -AddressFamily $IPType `
 -IPAddress $IP `
 -PrefixLength $MaskBits `
 -DefaultGateway $Gateway

# Configura il primo server DNS, non so come configurare il secondo ancora.
$adapter | Set-DnsClientServerAddress -ServerAddresses $DNS




iRon
  • 20,463
  • 10
  • 53
  • 79
Kitsu
  • 13
  • 3
  • Does this answer your question? [PowerShell - Merge two variables into one](https://stackoverflow.com/questions/68822619/powershell-merge-two-variables-into-one) – Olaf Aug 18 '21 at 07:10
  • ... or do you mean something like a lookup table? – Olaf Aug 18 '21 at 07:15
  • 1
    Don't worry about your English, it's good enough. Anyway, maybe you'd need an array and input is used to index it, or use a switch statement. Please [edit] the question and explain with more details what you'd like to do in plain English, so we can propose appropriate solution. – vonPryz Aug 18 '21 at 07:35
  • If I understand correctly, I think you should have a play with `Get-Variable` – mjsqu Aug 18 '21 at 08:16
  • 1
    Please try to create a [mcve] and show us (in the question) how you *exactly* created "*I have 10 variables, called rows($row1, $row2, $row3...)*". Note that it is very likely that you made a wrong start, instead of creating 10 individual variables (and `Get-Variable` which is definitely a bad practice for this), you probably want to create an array (or a [hashtable](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_hash_tables)) and then use: something like `$Rows[10]` . – iRon Aug 18 '21 at 08:37
  • So, I have a table in excel with 2 columns, one with IP addresses, and one with a mac addreses if the IP is taken, I want to make a script that takes the IP, and based on user choice will set the IP configuration to the machine, I need to take IPs from there since they are managed by the network manager not me, so I don't know which ones he will place there. iRon, I think you gave me the right track to follow (hashtable/array), instead of using a single variable for every row in the file... I fell in love with powershell, but am noob... I edited the answer and put the whole (horrible) thing. – Kitsu Aug 18 '21 at 08:57
  • @vonPryz I commented a better explanation and put the complete script, it's my first script / use of powershell so I know it's pretty bad. – Kitsu Aug 18 '21 at 09:10

1 Answers1

3

General (best practice) advice:

Don't use the <verb>-Variable cmdlets for dynamic variable names!

(Rule request: #1706 Warning if Set/Get-Variable is invoked with only the basic -Name/-Value parameters.)

Background

PowerShell (as almost all other programming languages) has an internal dictionary were it keeps all the variable names and a (direct or indirect) reference to their containing value. This dictionary (quote wikipedia),

is a data structure that implements a set abstract data type, a structure that can map keys to values. A hash table uses a hash function to compute an index, also called a hash code, into an array of buckets or slots, from which the desired value can be found. During lookup, the key is hashed and the resulting hash indicates where the corresponding value is stored.

Why not?

It is a general usage to create any (unique) variable name for a specific value, but at the moment that you find out that you start repeating yourself for a specific variable set, your program starts to become so called WET (as opposed to DRY). At this point you might come to the obvious conclusion to automate the variable names itself with statements using Set-Variable, like:

New-Variable -Name "row$i" -Value $row

To automate variables with a common purpose is definitely a good thought, but using <verb>-Variable cmdlets for this, is a bad practice as all the variables will eventually end up in the same dictionary. Therefore you might lose the oversight or even introduce conflicts with other variable names. Instead, you better create your own custom dictionary using a hashtable which is based on a similar data structure as the general variables.

How?

Instead of this:

$variables = @()
$i = 0
foreach ($row in ($data -split [Environment]::NewLine)) {
  # Crea una variabile per ogni riga
  New-Variable -Name "row$i" -Value $row
  # e un membro dell'array
  $variables += [pscustomobject]@{Name = "row$i"; Value = $row} # Copiato male, era troppo complicato arrivarci
  $i++
}

You might simply do this:

$Rows = @{}
$i = 0
foreach ($row in ($data -split [Environment]::NewLine)) { $Rows[$i++] = $Row }

And to get the specific value:

$LineaScelta = Read-Host
$IP = $Rows[[Int]$LineaScelta]

As the key of the dictionary appears to be a consecutive zero-based numeric serie, you might even simplify this further using an array:

$Rows = $data -split [Environment]::NewLine

$LineaScelta = Read-Host
$IP = $Rows[$LineaScelta]

As a side node: also try I avoid using the increase assignment operator (+=) to create a collection

iRon
  • 20,463
  • 10
  • 53
  • 79
  • 1
    THIS IS AMAZING, first you made the code super faster and cleaner + solved my issues and teached me a lot, in just a few lines.... I was banging my head for 3 days.... Thank you so much! – Kitsu Aug 18 '21 at 11:10
  • 2
    @Kitsu This is a very good example why it's a good idea to include background information as well as details in the question. It's much more easy to help when we know what's actually going on. – vonPryz Aug 18 '21 at 15:55