is there a better way for me to write a script for quiz in shell - powershell

I have been at this script for 24 hours and I am getting nowhere. I am so desperate for help.
I am trying to create a quiz and I need the switches to verify if the user's input matches the 3 options; 'Y' 'N' 'G' and if true move to the next question. If not, I need the switch to then prompt the user of the default output each time the user enter's anything else besides those 3 options.

function Test-statement ($Y,$N,$G,$YY,$NN,$GG){
$check = $Y -eq $YY
$check =$check -and ($N -eq $NN)
$check =$check -and ($G -eq $GG)
$check
}
$questions = #{
"what is the current year now" = #('2023','2023','2023')
"what is the previous year" = #('2022','2022','2022')
}
foreach ($key in $questions.keys) {
$check = $false
do{
write-host ("$key" + "?")
$Y = read-host "1"
$N = read-host "2"
$G = read-host "3"
$YY = $questions.$key[0]
$NN = $questions.$key[1]
$GG = $questions.$key[2]
$check = Test-statement $Y $N $G $YY $NN $GG
if (!($check)){write-host "not true" -ForegroundColor red}
} until ($check)
}

Related

powershell until loop not working as intended

the desired output would be to repeat the question until either "Y" or "N" is selected.
$msg = 'Does this Share contain Sensitive Data? [Y/N]'
do {
$response = Read-Host -Prompt $msg
if ($response -eq 'n') {
$sdata = "No"
}
if ($response -eq 'y') {
$sdata = "(Sensitive)"
}
} until ($response -ne '$null')
However if I enter anything else it will still continue to run the script. I have this working on other scripts so I am unsure of why its not working now.
Thanks as always!
So you want to repeat the prompt until someone enters a valid value - either y or n.
You can either use the -or operator:
do {
# ...
} until ($response -eq 'y' -or $response -eq 'n')
Since you're testing the same variable for one of multiple possible values, you could also use the reverse containment operator -in to test if the input was part of the set of valid values:
do {
# ...
} until ($response -in 'y','n')
... or, if you want a "cleaner" condition expression, use a variable to keep track of whether a valid value has been entered:
$done = $false
do {
$response = Read-Host -Prompt $msg
if ($response -eq 'n') {
$sdata = "No"
$done = $true
}
if ($response -eq 'y') {
$sdata = "(Sensitive)"
$done = $true
}
} until ($done)

Guessing a number with if-else statement

I have write a short powershell script for a guessing number game. This looks like following:
clear-host
$Guess = "11"
$response=read-host "Enter your guess"
if ($response -eq $guess)
{
write-host "Congratulations"
}
else {
write-host "Try again"
}
Now, if I want to do in such way that after a certain number of times wrong guessing for example, 3 times wrong guessing the program will exit. How I can do this? Can you please shade some light on that issue?
Here is a solution with a while loop
$count = 0
$answered = $false
while ($count -lt 3 -and $answered -eq $false) {
clear-host
$Guess = "11"
$response=read-host "Enter your guess"
if ($response -eq $guess)
{
$answered = $true
write-host "Congratulations"
}
else {
write-host "Try again"
}
$count++
}

Is there a way to pre-fill out Read-Host in Powershell?

I have a script that helps a user find if a file hash exists in a folder. After the user has entered the hash I determine what type of hash it is and if it is not supported or if the user missed a letter it will return to asking for a hash. For ease of use I want to be able to pre-fill out what the user had type in the previously so they do not need to start over.
while (1)
{
$hashToFind = Read-Host -Prompt "Enter hash to find or type 'file' for multiple hashes"
# Check if user wants to use text file
if ($hashToFind -eq "file" )
{
Write-Host "Be aware program will only support one has type at a time. Type is determined by the first hash in the file." -ForegroundColor Yellow
Start-Sleep -Seconds 3
$hashPath = New-Object system.windows.forms.openfiledialog
$hashPath.InitialDirectory = “c:\”
$hashPath.MultiSelect = $false
if($hashPath.showdialog() -ne "OK")
{
echo "No file was selected. Exiting program."
Return
}
$hashToFind = Get-Content $hashPath.filename
}
# Changes string to array
if ( $hashToFind.GetTypeCode() -eq "String")
{
$hashToFind+= " a"
$hashToFind = $hashToFind.Split(" ")
}
if ($hashToFind[0].Length -eq 40){$hashType = "SHA1"; break}
elseif ($hashToFind[0].Length -eq 64){$hashType = "SHA256"; break}
elseif ($hashToFind[0].Length -eq 96){$hashType = "SHA384"; break}
elseif ($hashToFind[0].Length -eq 128){$hashType = "SHA512"; break}
elseif ($hashToFind[0].Length -eq 32){$hashType = "MD5"; break}
else {echo "Hash length is not of supported hash type."}
}
I am newer to PowerShell so if there are any other comments they are welcome!
From Super User:
[System.Windows.Forms.SendKeys]::SendWait("yes")
Read-Host "Your answer"
I have came up with solution like this:
while (1)
{
$hashToFind = Read-Host -Prompt "Enter hash to find or type 'file' for multiple hashes. Enter 'R' for reply input"
if ($hashToFind -eq 'R' -and $PreviousInput)
{
$handle = (Get-Process -Id $PID).MainWindowHandle
$code = {
param($handle,$PreviousInput)
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
[void][Tricks]::SetForegroundWindow($handle)
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait($PreviousInput)
}
$ps = [PowerShell]::Create()
[void]$ps.AddScript($code).AddArgument($handle).AddArgument($PreviousInput)
[void]$ps.BeginInvoke()
}
$PreviousInput = $hashToFind
# Check if user wants to use text file
if ($hashToFind -eq "file" )
{
$PreviousInput = $null
Write-Host "Be aware program will only support one has type at a time. Type is determined by the first hash in the file." -ForegroundColor Yellow
Start-Sleep -Seconds 3
$hashPath = New-Object system.windows.forms.openfiledialog
$hashPath.InitialDirectory = “c:\”
$hashPath.MultiSelect = $false
if($hashPath.showdialog() -ne "OK")
{
echo "No file was selected. Exiting program."
Return
}
$hashToFind = Get-Content $hashPath.filename
}
# Changes string to array
if ( $hashToFind.GetTypeCode() -eq "String")
{
$hashToFind+= " a"
$hashToFind = $hashToFind.Split(" ")
}
if ($hashToFind[0].Length -eq 40){$hashType = "SHA1"; break}
elseif ($hashToFind[0].Length -eq 64){$hashType = "SHA256"; break}
elseif ($hashToFind[0].Length -eq 96){$hashType = "SHA384"; break}
elseif ($hashToFind[0].Length -eq 128){$hashType = "SHA512"; break}
elseif ($hashToFind[0].Length -eq 32){$hashType = "MD5"; break}
else {echo "Hash length is not of supported hash type."}
}

powershell highlight the blank space found

I have the following script which finds a blank space in a csv file by going line by line
$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Retain blank space."
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Delete blank space."
$n = #()
$f = Get-Content C:\MyPath\*.csv
foreach($item in $f) {
if($item -like "* *"){
$res = $host.ui.PromptForChoice("Title", "want to keep the blank on this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
switch ($res)
{
0 {$n+=$item}
1 {$n+=$item -replace ' '}
}
} else {
$n+=$item -replace ' '
}
}
$n | Set-Content C:\MyPath\*.csv
The question is: When there is a space found, how can I highlight where it is on a line or put a color there, anything that would ease the process of finding it?
EDIT: don't want to alter the file or the text, this should be done only shown in the console for PowerShell or in the window popup for ISE.
A basic code sample for the method described in the comments using Read-Host for user input and changing the background color with write-host would look like this:
$str= "test abc1 abc2 test3"
$index = $str.IndexOf(" ")
while ($index -gt -1) {
write-host $str.Substring(0,$index) -NoNewline
write-host "_" -foreground "magenta" -NoNewline
$str = $str.Substring( $index + 1, $str.length - $index - 1);
$index = $str.IndexOf(" ")
}
write-host $str.Substring( $index + 1, $str.length - $index - 1);
$confirmation = Read-Host "Do you want to keep the blank on this line?"
if ($confirmation -eq 'y') {
#do action
}
Edit: Included code for multiple white spaces
Code for initial Post:
$n = #()
$f = Get-Content C:\MyPath\*.csv
foreach($item in $f) {
if($item -like "* *"){
#$res = $host.ui.PromptForChoice("Title", "want to keep the blank on this line? `n $item", [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no), 0)
$str = $item
$index = $str.IndexOf(" ")
while ($index -gt -1) {
write-host $str.Substring(0,$index) -NoNewline
write-host "_" -foreground "magenta" -NoNewline
$str = $str.Substring( $index + 1, $str.length - $index - 1);
$index = $str.IndexOf(" ")
}
write-host $str.Substring( $index + 1, $str.length - $index - 1);
$confirmation = Read-Host "Do you want to keep the blank on this line?"
if (($confirmation -eq 'y') -or ($confirmation -eq 'Y')) {
$n+=$item
}
else {
$n+=$item -replace ' '
}
} else {
$n+=$item -replace ' '
}
}
$n | Set-Content C:\MyPath\*.csv

-Contains operator not working powershell

All I'm trying to do is to see if the user input $month is in the array $months. But it's not liking something. Help?
Write-host "The script is to collect from the user High Tempature and Low Tempature for a day in degrees F."
$months = #("January", "February","March","April","May","June","July","August","September","October","November","December")
$finished = $false
while ($finished -eq $false){
$month = read-host "Enter the month";
if ($months -Contains $month)
{
write-host "Invalid entry"
$finished = $false
}
else
{
$finished = $true
}
}
You test logic is just not the good one, just reverse youy test or reverse your actions:
Write-host "The script is to collect from the user High Tempature and Low Tempature for a day in degrees F."
$months = #("January", "February","March","April","May","June","July","August","September","October","November","December")
$finished = $false
while ($finished -eq $false){
$month = read-host "Enter the month";
if ($months -Contains $month)
{
$finished = $true
}
else
{
write-host "Invalid entry"
$finished = $false
}
}
Instead of using -Contains you should just run a RegEx match using the -Match operator. Or, as you are currently testing for a negative result, use -notmatch instead. You can use your existing code, just modify it a little by joining your months with a pipe character. Like:
Write-host "The script is to collect from the user High Tempature and Low Tempature for a day in degrees F."
$months = #("January", "February","March","April","May","June","July","August","September","October","November","December")
$finished = $false
while ($finished -eq $false){
$month = read-host "Enter the month";
if ($month -notmatch ($months -join "|"))
{
write-host "Invalid entry"
$finished = $false
}
else
{
$finished = $true
}
}
Better yet, let's get rid of the If/Else and shorten this. Move the Join to where we define $Months, and then ask for a month and if it isn't a match ask for it again until it is with a While.
$months = #("January", "February","March","April","May","June","July","August","September","October","November","December") -join '|'
$month = read-host "Enter the month"
While($month -notmatch $months){
"Invalid Entry"
$month = read-host "Enter the month"
}