Do-Until loop ask twice value - powershell

The problem is with loop DoUntil.
The script must take the URL, than ask what to do with him and gave the result after the user pick the number(1-4)
and with output give the menu again, and user can pick another number if he want or finish the script typing 'X'.
But this script works in a different way, it is ask for URL, after I will pick the number, and after this it asks again the URL and again the number and after this(if for example I will pick twice the same number) it will bring me the value of 2 URLs together.
Please, advice, what I'm doing wrong.
write-host ""
write-host "Past URL that you need to check"
write-host ""
write-host -nonewline "Type your URL and press Enter: "
$URLok = read-host
write-host ""
if ($URLok.Length -lt 1) {
write-host "Invalid selection"
}
do {
write-host "What do you want to do with this URL?"
write-host ""
write-host "DNS - Selection 1"
write-host " MX - Selection 2"
write-host " NS - Selection 3"
write-host "TXT - Selection 4"
write-host ""
write-host "X - Exit"
write-host ""
write-host -nonewline "Type your choice and press Enter: "
$choice = read-host
$ok = $choice -match '^[1234x]+$'
if ( -not $ok) {
write-host "Invalid selection"
}
switch -Regex ( $choice ) {
"1"
{
[System.Net.Dns]::resolve($URLok)
}
"2"
{
Resolve-DnsName -Name $URLok -Type MX -DnsOnly | select Name,Type,NameExchange
}
"3"
{
Resolve-DnsName -Name '888ladies.com' -Type NS -DnsOnly | select Name,Type,NameHost,PrimaryServer
}
"4"
{
Resolve-DnsName -Name $URLok -Type TXT | select Name,Type,Strings
}
"5"
{
write-host ""
write-host "Past URL that you need to check"
write-host ""
write-host -nonewline "Type your URL and press Enter: "
$URLok = read-host
write-host ""
}
}
} while($choice -ne "X")
P.s. And Little remark, in the 2-3-4 options I have 'Resolve-DNSName' but this script wouldn't show it on the console before the loop doUntil finished. So I can see the result only if I pick 'X' and finish the loop

The answer was with the pip Format-Table and it's work!
For Example:
Resolve-DnsName -Name $URLok -Type NS -DnsOnly | select Name,Type,NameHost,PrimaryServer| Format-Table

Related

selecting multiple options from the menu list

Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
}
# Step 2) define the array of packages you are offering
$Packages = 'googlechrome',
'firefox',
'codeblocks',
'windbg',
'nasm',
'explorersuite',
'pestudio',
'vscode',
'sysinternals',
'python',
'ccleaner',
'anaconda3',
'wireshark',
'sublimetext3',
'notepadplusplus',
'Exit'
# Step 3) define the Show-Menu function
function Show-Menu
{
Clear-Host
Write-Host "**********************************************"
Write-Host "LIST OF SOFTWARES"
# write the options using the array of packages
for ($i = 0; $i -lt $Packages.Count; $i++)
{
# {0,10} means right align with spaces to max 2 characters
Write-Host ('{0,10}. {1}' -f ($i + 1), $Packages[$i])
}
Write-Host " q. Exit the script"
Write-Host "*************************************************"
Write-Host
}
# Step 4) enter an endless loop you only exit if the user enters 'q'
while ($true)
{
Show-Menu
# $UserInput = Read-Host "Enter the software number to be installed"
$UserInput = Read-Host "Select the softwares number(s) to be installed"
$ok = $UserInput -match '[123456789101112131415]+$'
if( -not $ok)
{
write-host "Invalid selection"
sleep 2
write-host ""
}
until ($ok)
switch -Regex ($UserInput)
{
"1" {googlechrome}
"2" {firefox}
"3" {codeblocks}
"4" {windbg}
"5" {nasm}
"6" {explorersuite}
"7" {pestudio}
"8" {vscode}
"9" {sysinternals}
"10" {python}
"11" {ccleaner}
"12" {anaconda3}
"13" {wireshark}
"14" {sublimetext3}
"15" {notepadplusplus}
} until ($ok)
# test if the user wants to quit and if so, break the loop
if ($UserInput -eq 'q') { break }
# test if the user entered a number between 1 and the total number of packages (inclusive)
if ([int]::TryParse($UserInput,[ref]$null) -and 1..$Packages.Count -contains [int]$UserInput)
{
# here you install the chosen package using the array index number (= user input number minus 1)
$packageIndex = [int]$UserInput - 1
Write-Host "Installing $($Packages[$packageIndex])"
# Choco install $Packages[$packageIndex] -y
Choco install $Packages[$packageIndex] -y --ignore-checksums
}
else
{
$availableOptions = 1..$Packages.Count -join ','
Write-Host "Error in selection, choose $availableOptions or q" -Foreground Color Red
}
$null = Read-Host "Press Enter to continue"
}
I have written the script which is working when the user select the number then that corresponding software will be downloaded and installed. Now instead of selecting one option the user selects multiple options from the menu list then that software's will be downloaded and installed parallely so, I have modified my script for selecting multiple options but the script is not working so, please tell me how to achieve this functionality. Thanks in Advance
I've removed the parts which (for me) made no sense or produced errors in my environment - removed the option 'Exit' from $Packages and added the foreach part. So now the user can enter several numbers space separated so that $UserInput contains e.g. 1 2. this is then split an iterated in the foreach part.
Set-ExecutionPolicy Bypass -Scope Process -Force;
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Step 2) define the array of packages you are offering
$Packages = 'googlechrome',
'firefox',
'codeblocks',
'windbg',
'nasm',
'explorersuite',
'pestudio',
'vscode',
'sysinternals',
'python',
'ccleaner',
'anaconda3',
'wireshark',
'sublimetext3',
'notepadplusplus'
# Step 3) define the Show-Menu function
function Show-Menu
{
Clear-Host
Write-Host "**********************************************"
Write-Host "LIST OF SOFTWARES"
# write the options using the array of packages
for ($i = 0; $i -lt $Packages.Count; $i++)
{
# {0,10} means right align with spaces to max 2 characters
Write-Host ('{0,10}. {1}' -f ($i + 1), $Packages[$i])
}
Write-Host " q. Exit the script"
Write-Host "*************************************************"
Write-Host
}
# Step 4) enter an endless loop you only exit if the user enters 'q'
while ($true)
{
Show-Menu
$UserInput = Read-Host "Select the softwares number(s) to be installed (space separated)"
# test if the user wants to quit and if so, break the loop
if ($UserInput -eq 'q') { break }
foreach($input in $UserInput.Split(' ')) {
# test if the user entered a number between 1 and the total number of packages (inclusive)
if ([int]::TryParse($input,[ref]$null) -and 1..$Packages.Count -contains [int]$input)
{
# here you install the chosen package using the array index number (= user input number minus 1)
$packageIndex = [int]$input - 1
Write-Host "Installing $($Packages[$packageIndex])"
Choco install $Packages[$packageIndex] -y --ignore-checksums
} else {
$availableOptions = 1..$Packages.Count -join ','
Write-Host "Error in selection, choose $availableOptions or q" -Foreground Color Red
}
}
$null = Read-Host "Press Enter to continue"
}

How can i correctly output my try-catch into a txt file?

I'm working on a powershell script that would allow me to see if my DHCP servers are running well and what's their current state (how much address left, how much of them are used...).
So far, so good. I'm getting all the info i need but, the first test here is to check if the server is responding pretty much.
For this, i'm using try-catch and i'd like to output into a .txt all of the servers that are not responding.
Problem : i'm only outputting the last server that did not respond, i'm not getting the previous one that did not respond aswell.
Tried | out-file
| set-content and | add-content
There's nothing that i've found searching seems to work.
$DHCPSRV=""
$myError=0
$myArray=#( Import-Csv .\CSV\DHCP_list.csv)
foreach ($element in $myArray) {
try {
Write-Output ""
$DHCPSRV=$element.FQDN
$Message = "Server DHCP: " + $DHCPSRV
Write-Output $Message
Write-Output ""
$srv=get-dhcpserverv4statistics -ComputerName $DHCPSRV
$Message ="Server start time : " + $srv.ServerStartTime
Write-Output $Message
$Message ="Number of address : " + $srv.TotalAddresses
Write-Output $Message
$Message ="Address used : " + $srv.AddressesInUse
Write-Output $Message
$Message ="% remaining : " + $srv.PercentageAvailable + " %"
Write-Output $Message
Get-DhcpServerSetting -ComputerName $DHCPSRV
Write-Output ""
}
catch{
Write-host "Server not responding " $DHCPSRV -BackgroundColor red -ForegroundColor White
$myerror=$error+1
$test = $DHCPSRV
}
}
if ($myError -eq 0){
Write-Output ""
Write-host "All DHCP are working good" -BackgroundColor green -ForegroundColor black
}
$test | Set-Content '.\Output\dhcp_failed.txt'
$test | Add-Content '.\Output\dhcp_failed.txt'
Write-Output ""
Write-Output ""
Write-Output "------------------------------------------------"
pause
I'd like to output all of the server that failed the try-catch test in my txt!
solved by bluuf - Thank you !
Just had to add the -append in my catch
catch{
Write-host "Server not responding " $DHCPSRV -BackgroundColor red -ForegroundColor White
$myerror=$error+1
$DHCPSRV | out-file '.\path\file.txt' -append
}
also added clear-content '.\path\file.txt' at the beginning of the script so my file get cleared every time i launch it!

Jumping to another section in a PowerShell script

I want to jump from one section in the script to another section in the same PowerShell script. My script is only going from top to bottom right now, but I have several tasks. e.g. I want to be able to choose from a task list in the beginning of the script and go to task number 2 skip task 1.
I hope this makes any sense for you. Take a look at my script:
Write-Host -ForegroundColor Yellow "welcome to my powershell script..."
""
""
""
Start-Sleep -Seconds 1
Write-Host -ForegroundColor Yellow "Choose a task:"
""
""
Write-Host -ForegroundColor Yellow "1. Clean up"
Write-Host -ForegroundColor Yellow "2. Uninstall Pre-Installed Apps"
Write-Host -ForegroundColor Yellow "3. Something should be written here"
""
""
""
While ($Valg -ne "1" -or $Valg -ne "2" -or $Valg -ne "3") {
$Valg = Read-Host "Choose a number from the task list"
If ($Valg –eq "1") { Break }
If ($Valg –eq "2") { Break }
If ($Valg –eq "3") { Break }
if ($Valg -ne "1" -or $Valg -ne "2" -or $Valg -ne "3") {
""
Write-Host -ForegroundColor Red "Ups. Try again..."
}
}
#### 1. First task should come here (clean up)
#some code here for the "cleaning up" task
#### 2. Second task here
#some code here for the "Uninstall Pre-Installed Apps" task
#### 3. Third task there
#Some code for the third task here
#### And so on...
Here is a generic solution which uses an array of PSCustomObject that represents the task (message and the function to invoke). It doesn't need a switch, you can simply add new Tasks to the array (and implement the desired function) without modifying the remaining script:
# define a task list with the messages to display and the functions to invoke:
$taskList = #(
[PSCustomObject]#{Message = 'Clean up'; Task = { Cleanup }}
[PSCustomObject]#{Message = 'Uninstall Pre-Installed Apps'; Task = { Uninstall }}
[PSCustomObject]#{Message = 'Something should be written here'; Task = { Print }}
)
# define the functions:
function Cleanup()
{
Write-Host "Cleanup"
}
function Uninstall()
{
Write-Host "Uninstall"
}
function Print()
{
Write-Host "Print"
}
# let the user pick a task:
Write-Host -ForegroundColor Yellow "Choose a task:"
$taskList | foreach -Begin { $i = 1;} -Process {
Write-Host -ForegroundColor Yellow ('{0}. {1}' -f ($i++), $_.Message)
}
do
{
$value = Read-Host 'Choose a number from the task list'
}
while($value -match '\D+' -or $value -le 0 -or $value -gt $taskList.Count)
# invoke the task:
& $taskList[$value-1].Task
I am updating answer to complete script based on inputs by "bluuf" and "majkinator".
Use the Switch-Case construct along with Functions like below. This is complete working solution.
#region Function Definitions. These come first before calling them
function FirstTask
(
[string] $inputVariable
)
{
"write any scipt for First task here without quotes. Input is: " + $inputVariable
}
function SecondTask
{
"write any scipt for Second task here without quotes"
}
function ThirdTask
{
"write any scipt for Third task here without quotes"
}
#endregion
#region Showing Options
Write-Host -ForegroundColor Yellow "welcome to my powershell script..."
""
""
""
Start-Sleep -Seconds 1
Write-Host -ForegroundColor Yellow "Choose a task:"
""
""
Write-Host -ForegroundColor Yellow "1. Clean up"
Write-Host -ForegroundColor Yellow "2. Uninstall Pre-Installed Apps"
Write-Host -ForegroundColor Yellow "3. Something should be written here"
Write-Host -ForegroundColor Yellow "0. Exit"
""
""
""
#endregion
#region Getting input
While ($true) {
$Valg = Read-Host "Choose a number from the task list"
If ($Valg –eq "0")
{
"Thanks for using my utility";
Break;
}
If (($Valg -ne "1") -and ($Valg -ne "2") -and ($Valg -ne "3") -and ($Valg -ne "0")) {
""
Write-Host -ForegroundColor Red "Ups. Try again..."
}
#region Main Code
switch ($Valg)
{
1{
FirstTask("sending input");
}
2 {
SecondTask;
}
3 {
ThirdTask;
}
default { "Please select a correct option."}
}
#endregion
}
#endregion

Powershell selection validation failing

I am having some issues with a dynamic picklist I am generating for a script. I can see it return the list of options and I can select each of them. However the validation I have is not working as I would have expected.
Write-Host "Gathering cluster information..." -foreground Green
$allclusters = Get-Cluster | Sort Name
$allHosts = $allclusters | Get-VMHost
Write-Host "Found " $allclusters.count " containing " $allHosts.count " Hosts." -Foreground Green
# LoopMain Start
Do {
$userMenuChoice = "y"
Write-Host "Select Cluster to patch:" -Foreground Yellow
for($i=0;$i -le $allclusters.length-1;$i++)
{"[{0}] - {1}" -f $i,$allclusters[$i]}
# Select VMCluster
Write-Host ""
Write-Host "Which Cluster would you like to use (0 to"($allclusters.length-1)")" -ForegroundColor Cyan -NoNewLine ; $clusterSelect = Read-Host " "
Write-Host ""
# Validate selection
IF ($clusterSelect -le ($allclusters.length-1))
{
Write-Host "Selection is valid"
# Display item from clusterarray
Write-Host ""
Write-Host "You selected " -NoNewLine ; Write-Host $allclusters[$clusterSelect] -ForegroundColor Cyan -NoNewLine ; $clusterSelectCont = Read-Host ". Shall we continue? (Y/N)"
}
ELSE
{
Write-Host "Selection is not valid"
$clusterSelectCont = "n"
}
The picklist will work for some number but not all. For example I can select number 12 form the list and everything is fine but number 7 fails. Is there something fundamentally wrong with the way I have created the picklist or is it the validation that is failing perhaps?
Ah, so discussed with a colleague here and the suggestion was to cast the variable to an integer using the following line:
[int]$clusterSelect = $clusterSelect
This now validates as expected and I can select all values without issue.

How do I allow for multiple selections in a numbered menu?

This is related to my previous question about FTP time stamps. I'm working on a script to help make my job, and hopefully others, better by making PC setups easier. As it is right now everything works perfectly, except I'd like to make it more automated. Right now it only allows for one thing at a time. I'd like to be able to choose multiple numbers and have it run them all one after the other.
This needs to work in Windows 7 without importing any extra modules.
Here's what I have so far:
echo ""
$answer = read-host "Select a number"
echo ""
if ($answer -eq 1){uninstall}
if ($answer -eq 2){flashjava}
if ($answer -eq 3){reader}
if ($answer -eq 4){firefox}
if ($answer -eq 5){chrome}
if ($answer -eq 6){office}
if ($answer -eq 7){reader}
if ($answer -eq 8){updates}
if ($answer -eq 9){exit}
else {write-host -ForegroundColor red "Invalid Selection"
sleep 2
mainmenu
}
echo ""
Instead of choosing option 2 (for example), letting that go, then hitting option 3, and so on I'd like to type "2,3" (no quotes) and have it hit both functions one after the other.
I've looked into foreach loops, but can't get it to work.
echo ""
$num = read-host "Select a number"
echo ""
$num.split(",")
ForEach($answer in $num){
if ($answer -eq 1){uninstall}
if ($answer -eq 2){flashjava}
if ($answer -eq 3){reader}
if ($answer -eq 4){firefox}
if ($answer -eq 5){chrome}
if ($answer -eq 6){office}
if ($answer -eq 7){reader}
if ($answer -eq 8){updates}
if ($answer -eq 9){exit}
}
else {write-host -ForegroundColor red "Invalid Selection"
sleep 2
mainmenu
}
echo ""
I'm aware the Else statement would catch anything other than a single 1-9. I've tried commenting that section out, still nothing. It works if I choose a single number, but not multiples. I've also tried putting the numbers in the if statements in quotes. It also displays the number(s) I've chosen before it either runs the function or quits. I'd like to not display any output.
Thanks!
UPDATE: After looking around I found the switch parameter. Seems to work great!
do {
do {
cls
write-host ""
write-host "****************************"
write-host "** Main Menu **"
write-host "****************************"
write-host ""
write-host "1 - Uninstall Bundled Apps"
write-host "2 - Install Flash & Java"
write-host "3 - Install Adobe Reader"
write-host "4 - Install Firefox"
write-host "5 - Install Chrome"
write-host "6 - Install Office 365"
write-host "7 - Install All"
write-host ""
write-host "8 - Check for Installer Updates"
write-host ""
write-host "9 - Exit"
write-host ""
$answer = read-host "Select number(s)"
$ok = $answer -match '[123456789]+$'
if ( -not $ok) {write-host "Invalid selection"
sleep 2
write-host ""
}
} until ($ok)
switch -Regex ( $answer ) {
"1" {uninstall}
"2" {flashjava}
"3" {reader}
"4" {firefox}
"5" {chrome}
"6" {o365}
"7" {uninstall}
"8" {updates}
}
} until ( $answer -match "9" )
}
You were really close actually. The main problem is that $num.Split() returns the array, but does not modify $num, so when you then use $num in your foreach() loop, you are using the original value. Have a look at the change here:
echo ""
$num = read-host "Select a number"
echo ""
$nums = $num.split(",")
ForEach($answer in $nums){
if ($answer -eq 1){uninstall}
if ($answer -eq 2){flashjava}
if ($answer -eq 3){reader}
if ($answer -eq 4){firefox}
if ($answer -eq 5){chrome}
if ($answer -eq 6){office}
if ($answer -eq 7){reader}
if ($answer -eq 8){updates}
if ($answer -eq 9){exit}
}
# else {write-host -ForegroundColor red "Invalid Selection"
# sleep 2
# mainmenu
# }
# commented out because this else no longer corresponds to anything
echo ""
Now just to clean this up a bit, let's look at it with switch:
echo ""
$num = read-host "Select a number"
echo ""
$nums = $num.split(",")
ForEach($answer in $nums){
switch ($answer) {
1 {uninstall}
2 {flashjava}
3 {reader}
4 {firefox}
5 {chrome}
6 {office}
7 {reader}
8 {updates}
9 {exit}
default {
write-host -ForegroundColor red "Invalid Selection"
sleep 2
mainmenu
}
}
}
echo ""