Using $_ as your own loop variable is a very bad idea since it is the built in PowerShell pipeline variable. And in general using singular and plural of a certain noun to distinguish between arrays and single elements is a bad idea as well as itās quite error prone.
A much better approach would be to use for example
You want to combine them into what, a string? ā$var1 $var$ā itās no different than the lnk description line in your code just reference the other property
In the first function Create-Rdp , I am creating rdp shotcuts based on import-csv server.csv
In the second function Show-Menu i am creating an dynamic menu based on Get-ChildItem from the items in the shortcutDir.
In this Menu if want to see at Write-Host the Name of the server and the Role.
I am not able to populate the Server.Role from the get-childitem , So I want to combine them some how.
Probably its simple but I dont see it now.
Could you run it, and see want your findings are?
Get-ChildItem returns file system objects. Those objects do not have a property role. You would need to extract the link description to get those information from a *.lnk file.
Why donāt you use the CSV file as source for your menu?
Why? You already have what you want in the input CSV?!
You may make A BIG STEP BACK and start with explaining in simple terms what it is what youāre actually trying to achieve. Donāt explain the way you think you have to go to achieve your goal - explain the bigger picture please.
I have 10 customers with each a bunch of servers.
For each customer I want a menu with their servers when selecting a specified server it needs to start a RDP session to it.
After accomplising this in a script, I want to convert it to exe.
Why do you need all these *.lnk files then? You could simply start an RDP session with a command line?!
Regardless of that ⦠wouldnāt be better to install them an a little more professional RDP solution like the RDP-Manager from CInspiration for example? https://www.cinspiration.de/uebersicht4.html
Their website seems to be not working at the moment but the tool is actually very nice. I use it every day.
Why that? You know that it will not protect your code from beeing seen, donāt you?
Besides that ⦠youāre overcomplicating this a lot
$InputData = @'
Name,Role
SVR001,App1
SVR002,DB1
SVR022,Datacenter
SVR008,Middleware
SVR012,MGT
SVR012,DomainController1
SVR013,Radiusserver1
'@ |
ConvertFrom-Csv
$Index = 1
$IndexedInputData =
$InputData |
ForEach-Object {
[PSCustomObject]@{
Index = $Index++
Name = $_.Name
Role = $_.Role
}
}
$IndexedInputData
[int]$choice = 0
do {
try {
[int]$choice = Read-Host "`nPlease enter index of the desired item (<Enter> = 0 = cancel)" -ErrorAction Stop
}
catch {
Write-Warning "Incorrect input! Please choose a numeric value between '0' and '$($IndexedInputData.Length )'!"
$choice = -1
}
}
until ($choice -ge 0 -and $choice -le $IndexedInputData.Length )
if ($choice -eq 0) {
$selectedItem = 'none'
}else {
$selectedItem = $IndexedInputData[$choice - 1].Name
}
$selectedItem
Now you can simply run a command line calling MSTSC.exe with the server name and you have your RDP session.
This method should be robust enough to even tolerate false inputs of any kind.
Great Olaf, many thanks Okay so I added this to a menu with a loop.
This to have them for each customer all together in an general menu.
Sharing this toā¦
# Main menu all customers
function Show-Menu {
param (
[string]$Title1 = "$env:USERNAME Custom script",
[string]$Title = 'Choose Which to Start'
)
Clear-Host
Write-Host "================ $Title1 ================" -ForegroundColor red -BackgroundColor Blue
Write-Host "================ $Title ================"
Write-Host "1: Press '1' CU1 RDP Menu "
Write-Host "2: Press '2' CU2 RDP Menu"
Write-Host "3: Press '3' CU3 RDP Menu"
Write-Host "4: Press '4' CU4 RDP Menu"
Write-Host "5: Press '5' CU5 RDP Menu"
Write-Host "Q: Press 'Q' to quit."
}
if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript")
{ $ScriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition }
else
{ $ScriptPath = Split-Path -Parent -Path ([Environment]::GetCommandLineArgs()[0])
if (!$ScriptPath){ $ScriptPath = "." } }
# Functions go here
Function CU1-RDP { & ".\CU1-RDP.ps1" }
Function CU2-RDP { & ".\CU2-RDP.ps1" }
Function CU3-RDP { & ".\CU3-RDP.ps1" }
Function CU4-RDP { & ".\CU4-RDP.ps1" }
Function CU5-RDP { & ".\CU5-RDP.ps1" }
# Menu loop
do {
Show-Menu
$input = Read-Host "Please make a selection"
Clear-Host
switch ($input) {
'1' { CU1-RDP ; break }
'2' { CU2-RDP ; break }
'3' { Cu3-RDP; break }
'4' { CU4-RDP; break }
'5' { CU5-RDP; break }
'q' { break } # do nothing
default {
Write-Host "You entered '$input'" -ForegroundColor Red
Write-Host "Please select one of the choices from the menu." -ForegroundColor Red
}
}
Pause
} until ($input -eq 'q')
The Main menu is a ps1 script to exe, this is for convenience to simply execute it , not to hide code. And I am aware of RDP managers, but I like to get it done in Powershell .
Why not offering a shortcut file with the proper command line to launch the PowerShell script with the according command line?
Iād recommend avoiding the added complexity with a compiled script. Iād prefer to work according to the
I actually donāt get why youāre creating functions you use only once. And the rest of your code is quite repetitive and inefficient and hard to maintain.
Well well its all about the learning curve to me. I`ll just practice and create projects to learn Powershell more advanced. Will be more effective in the end . I try that to with the shortcutfile . About the function, did you meen to keep them all together in one ps1 ?
It does not make that much sense to create functions when you use them only once.
Actually you just have to take my code suggestion and add one more line of code to make it work - the command line calling the mstsc.exe with the according computer name. Did you actually run my code?
Iād try to avoid repetitive code like this. If there is a target server added you have to change cour code on several places instead of just adding one line to your input CSV.
Do your customers really need to read to press a number that often? IMHO thatās actually not very nice to look at. And youāre clearing the console jsut to display the same menu again. And if one of the options are chosen you show the menu again just to close it?
Edit:
Using the variable $input is a bad idea because it is an automatic variable built in PowerShell. Assigning to it might have undesired side effects.
To my knowledge a main function is the way to go. I`ll have to figure out how to get all the customers dynamic and seperated inside your code which I am using indeed.
Your code is not showing the servers the first time I run it, and it also exits when using it, gone make it like a loop as the main I showed.
here is a piece of the current.
# Main menu, for user selection:
function Show-Menu {
param (
[string]$Title1 = 'Andreas Custom Menu',
[string]$Title = 'Select a menu to start'
)
Clear-Host
Write-Host "================ $Title1 ================" -ForegroundColor red -BackgroundColor Blue
Write-Host "================ $Title ================"
Write-Host "1: CU1 RDP-Menu "
Write-Host "2: CU2 RDP-Menu"
Write-Host "Q: Press 'Q' to quit."
}
# Functions Go here:
function RDP-CU1 {
$InputData = @'
Name,Role
SRV01,(Management server - WinDom)
SRV02,(Store & Forward server)
SRV03,(MCS Database server1)
SRV04,(MCS Database server2)
'@ |
ConvertFrom-Csv
$Index = 1
$IndexedInputData =
$InputData |
ForEach-Object {
[PSCustomObject]@{
Index = $Index++
Name = $_.Name
Role = $_.Role
}
}
$IndexedInputData
[int]$choice = 0
do {
try {
[int]$choice = Read-Host "`nPlease enter index of the desired item (<Enter> = 0 = cancel)" -ErrorAction Stop
}
catch {
Write-Warning "Incorrect input! Please choose a numeric value between '0' and '$($IndexedInputData.Length )'!"
$choice = -11
}
}
until ($choice -ge 0 -and $choice -le $IndexedInputData.Length )
if ($choice -eq 0) {
$selectedItem = 'none'
}else {
$selectedItem = $IndexedInputData[$choice - 1].Name
}
mstsc.exe /v:$selectedItem
}
# Main menu loop:
do {
Show-Menu
$input = Read-Host "Please make a selection"
switch ($input) {
'1' { CU1-RDP ; break }
'2' { CU2-RDP ; break }
'q' { break } # do nothing
default {
Write-Host "You entered '$input'" -ForegroundColor Red
Write-Host "Please select one of the choices from the menu." -ForegroundColor Red
}
}
Pause
} until ($input -eq 'q')
Thatās actually not common for PowerShell. Are you coming from another programming language?
What does that mean? Do you use the same script for all customers? So all customers can see the server names from all other customers? Why donāt you use CSV files as input? I just added it inside my code suggestion for demo purposes here in the forum. Usually itās good to separate data (input data) from logic (code).
So you changed my code suggestion?
Thatās by design. It offers a choice and when one of the options is chosen it exits. Do you want to open more than one RDP session at a time?
And again:
Using the variable name input is a bad idea because itās a built in variable of PowerShell. Assing to it may cause undesired side effects.
Iād recommend using VSCode as your IDE and add besides the PowerShell extension one thatās called Error Lens. It helps avoiding common errors in advance.
I have no programming background, I`m an application engineer Linux -Windows started to use taskautomation /scripting with powershell since a year or two.
This script is not ment for others , only for own use , might share it with someone. Indeed working in several customer environments.This RDP menu is ment to easily switch and access other enviroments. And in the first place fun learning gathering knowledge about PS.