Prompt for choice. Re-prompt if option is invalid - powershell

I'm wondering how to re-prompt if someone typos or enters something other than yes/no
Would it have to be a created as a prompting function or is there an easier way?
$Continue = Read-Host -Prompt "Continue? Yes/No"
Switch($Continue){
'Yes' { Write-host -ForegroundColor Yellow "Moving on..." }
'No' {Write-host "...GoodBye"
Exit
}
default { #HOW TO RE-PROMPT USER FOR YES/No?
}
}

Using a While loop which a check variable. If Yes is typed then $Check will equal $true exiting the loop. Else it will stay false and rerun the loop again.
$Check = $false
while($Check -eq $false){
Switch(Read-Host -Prompt "Continue? Yes/No"){
'Yes' {
Write-host -ForegroundColor Yellow "Moving on..."
$Check = $true
}
'No' {
Write-host "...GoodBye"
return
}
}
}

Related

How do I use a switch statement with while loop

I am trying to add a user to the Remote Desktop group using Powershell.
It seems it's not breaking the loop and doesn't execute further statements.
Can you please help me where the issue is:
$remote = ""
While($remote -ne "Y" ){
$remote = read-host "Do you need to add anyone to the Remote Desktop group (y/n)?"
Switch ($remote)
{
Y {
$remoteuser = ""
while ( ($remoteuser -eq "") -or ($UserExists -eq $false) )
{
$remoteuser = Read-Host "Enter the username that needs to be in the group"
Write-Host "User inputted $remoteuser"
sleep -Seconds 2
try {
Get-ADUser -Identity $remoteuser -Server <server-FQDN>
$UserExists = $true
Write-Host "$remoteuser found!"
sleep 5
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityResolutionException] {
Write-Host "User does not exist."
$UserExists = $false
}
catch {
Write-Host "Username is blank"
$UserExists = $false
}
}
}
N {Write-Host "No user accounts will be added to the Remote Desktop Users group. Restart your PC."}
default {Write-Host "Only Y/N are Valid responses"}
}
}
<further statements>

How do I delete user in Active Directory through Powershell?

I have to delete users from my AD through Powershell. Powershell has to ask me who I want to delete, once I type in the username it should delete the account. Also when Powershell succesfully deleted the account or it should give me a message.
I'm kind of noob at this, but here is my code:
function aduser-remove($userremove){
Remove-ADUser -Identity $delete
if ($delete -eq $userremove){
return $true
}
else {
return $false
}
}
$delete = Read-host "Which user do you want to delete? (Type in username)."
aduser-remove $delete
if ($userremove -eq $true){
Write-Host $delete "deleted succesfully!" -ForegroundColor Green
}
elseif ($userremove -eq $false){
Write-Host "An error occured by deleting" $delete -ForegroundColor Red
}
else {
Write-Host $delete "does not exist." -ForegroundColor DarkGray
}
The result here is that Powershell does ask if I want to delete the account and it works. But Powershell keeps giving me the else message instead of the if message. Deleting the account was succesfull.
I have no idea what to now or if I'm missing something (I bet I am otherwise it would work).
I hope you guys can help me!
As commented, your code uses variables in places where they do not exist.
Also, I would recommend trying to find the user first and if you do, try and remove it inside a try/catch block, as Remove-ADUser creates no output.
Below a rewrite of your code. Please note that I have changed the name of the function to comply with the Verb-Noun naming convention in PowerShell.
function Remove-User ([string]$userremove) {
# test if we can find a user with that SamAccountName
$user = Get-ADUser -Filter "SamAccountName -eq '$userremove'" -ErrorAction SilentlyContinue
if ($user) {
try {
$user | Remove-ADUser -ErrorAction Stop -WhatIf
return $true
}
catch {
return $false
}
}
# if we get here, the user does not exist; returns $null
}
$delete = Read-host "Which user do you want to delete? (Type in username)."
# call your function and capture the result
$result = Remove-User $delete
if ($result -eq $true){
Write-Host "User $delete deleted succesfully!" -ForegroundColor Green
}
elseif ($result -eq $false){
Write-Host "An error occured while deleting user $delete" -ForegroundColor Red
}
else {
Write-Host "$delete does not exist." -ForegroundColor DarkGray
}
Note also that I have put in the -WhatIf switch. This switch ensures you will only get a message of what would happen. No user is actually deleted. Once you are satisfied the code does what you want, remove the -WhatIf switch.
Hope that helps
If you have rsat installed https://www.microsoft.com/en-us/download/details.aspx?id=45520
remove-aduser https://learn.microsoft.com/en-us/powershell/module/addsadministration/remove-aduser?view=win10-ps

powershell $var has value, but when in if statement - gets false

Just making a little menu for zoom usage.
The user insert it's selection, and the script automatically opens zoom to the specific session.
The problem is at if (($hashTable.$selection).Count -gt 1) where $selection does have the value 1 (if I pressed 1) but the expression always gets false - so it proceeds to the else statement.
The goal is to have in the hash table either only a session number or both session number and a password.
After checking if there's more than one value to the key, then I chose my action.
$selection does holds the number the user enters - so why $hashTable.$selection is empty?
$hashTable = #{
1 = '6108514938', 'f'
2 = 'Val2'
3 = 'Val3'
}
function Show-Menu
{
param (
[string]$Title = 'My Menu'
)
Clear-Host
Write-Host "================ $Title ================"
Write-Host "1: Press '1' for Algorithms."
Write-Host "2: Press '2' for this option."
Write-Host "3: Press '3' for this option."
Write-Host "Q: Press 'Q' to quit."
}
do
{
    Show-Menu –Title 'ZOOM Menu'
$zoomBaseLink = 'zoommtg://zoom.us/join?confno='
$selectedSession = $null
   
$selection = Read-Host "Please select session"
    switch ($selection)
    {
        '1' { $selectedSession = ($hashTable.1) }
'2' { $selectedSession = ($hashTable.2) }
'3' { 'You chose option #3' }
    }
if($selection -ne 'q') {
if (([string]::IsNullOrEmpty($selectedSession))) {
Write-Host 'session is null or empty'
}
else {
Write-Host $selection
Write-Host $selectedSession
pause
<#($hashTable.$selection) always gets false.#>
if (($hashTable.$selection).Count -gt 1) { Write-Host 'here 1'; Write-Host $hashTable.$selection[1] }
else{ Write-Host 'here 2'; Write-Host ($zoomBaseLink + $selectedSession) }
}
$selectedSession = $null
}
    pause
}
until ($selection -eq 'q')
The problem ist, that you didn't convert the variable $selection to an integer.
[int]$selection = [convert]::ToInt32($selection, 10)
If you do that first, it will work (tested):
if($selection -ne 'q') {
if (([string]::IsNullOrEmpty($selectedSession))) {
Write-Host 'session is null or empty'
}
else {
Write-Host $selection
Write-Host $selectedSession
pause
[int]$selection = [convert]::ToInt32($selection, 10)
<#($hashTable.$selection) always gets false.#>
if (($hashTable.$selection).Count -gt 1) { Write-Host 'here 1'; Write-Host $hashTable.$selection[1] }
else{ Write-Host 'here 2'; Write-Host ($zoomBaseLink + $selectedSession) }
}
$selectedSession = $null
[string]$selection = $null
}
pause
Please let me know if it worked and if it did, please mark my post as the answer :)

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++
}

Checking for multiple conditions without a break in Powershell

I am working on a validation script for a Domain Controller. I have an account that has 4 things that I need to verify. The code that I have works but I don't want it to break if one of the conditions aren't met and that is what it is doing now. So, basically I'm needing it to check all 4 criteria, regardless if the condition is met or not.
Here is my code:
if(net user "user.dadm") {
Write-Host "[√] User.dadm was created successfully" -fore GREEN
if((((uACADA "user.dadm") -band 65536) -ne 0) -eq $true) {
Write-Host "[√] Password for user.dadm is set to never expire" -fore GREEN
if((Get-ADGroupMember -Identity "Domain Admins").Name -contains "user.dadm") {
Write-Host "[√] User.dadm was added to Domain Admins" -fore GREEN
if((((uACADA "user.dadm") -band 1048576) -ne 0) -eq $true) {
Write-Host "[√] Account Delegation Authority was removed" -fore GREEN
} else {
Write-Host "[X] Account Delegation was not removed" -fore RED
}
} else {
Write-Host "[X] User.dadm was not added to Domain Admins" -fore RED
}
} else {
Write-Host "[X] Password for user.dadm has been set to expire" -fore RED
}
} else {
Write-Host "[X] User.adam was not created" -fore RED
}
What this does is it will break to the else statement if any of the conditions aren't met but I need it to continue checking each condition.
I know that I could break this up and check each condition individually but I prefer to have it as compressed as possible as it is already going to be over a thousand lines.
I guess the REAL question is if this can be done without making 4 separate IF/ELSE statements.
I'm not sure if its a structuring issue (nested IF) or a command issue (using IF and ELSE when I should use IF and ELSEIF).
Could someone point me in the right direction? Thanks in advance.
not tested, but this may be a starting point, though you may just choose the simplicity of multiple if statements.
$user = 'user.dadm'
$info = [ordered]#{
created = "[X] $user was not created"
neverexp = "[X] Password for $user has been set to expire"
admin = "[X] $user was not added to Domain Admins"
delegation = "[X] Account Delegation for $user was not removed"
}
switch ($true) {
{net user $user} {
$info.created = "[√] $user was created successfully"
}
{((uACADA $user) -band 65536) -ne 0} {
$info.neverexp = "[√] Password for $user is set to never expire"
}
{(Get-ADGroupMember -Identity 'Domain Admins').Name -contains $user} {
$info.admin = "[√] $user was added to Domain Admins"
}
{((uACADA $user) -band 1048576) -ne 0} {
$info.delegation = "[√] Account Delegation Authority for $user was removed"
}
default {Write-Host 'all are false'}
}
$info.Keys | % {
if ($info.$_.startswith('[X]')) {
Write-Host $($info.$_) -ForegroundColor Red
} else {
Write-Host $($info.$_) -ForegroundColor Green
}
}
Yes, you can write it without if tests, e.g.
$colors = #('Red', 'Green')
$messages = #('[X] Failed -', '[√] Succeeded -')
$username = "user.adm"
$result = [bool](net user "$username")
Write-Host "$($messages[$result]) Check user account exists" -ForegroundColor $colors[$result]
$result = [bool]((uACADA "$username") -band 65536)
Write-Host "$($messages[$result]) Check password never expires" -ForegroundColor $colors[$result]
$result = [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username")
Write-Host "$($messages[$result]) Check account is a domain admin" -ForegroundColor $colors[$result]
$result = [bool]((uACADA "$username") -band 1048576)
Write-Host "$($messages[$result]) Check Delegation Authority removed" -ForegroundColor $colors[$result]
NB. that if you aren't using if/else, you need some other way to do the true/false testing. I'm casting results to [bool] and using 2-element arrays. $array[$false] casts $false -> 0 and gets element 0, $array[$true] casts $true -> 1 and gets element 1. That's how the result is turned into the appropriate colors and messages.
Another reasonable way to write this would be to move the Write-Hosts into a function.
Function Report-Result {
param($Result, $Text)
if ($Result) {
Write-Host "Success - $Text" -Fore Green
} else {
Write-Host "Failure - $text" -Fore Red
}
}
$result = [bool](...)
report-result $result "Check password never expires"
... etc.
Output looks like:
Which is okayyyy - it gets your 20 lines of code down to ~10, and has no nesting, and runs all the tests.
But it really feels like you're re-inventing PowerShell DSC ("my desired state is that accounts with .adm at the end have their passwords set to never expire") or Pester - PowerShell's test framework, ("test that all .adm accounts have passwords set to never expire").
I'm not sure that you can exactly fit Pester into your use case, but it makes me think I would change everything about the script from the way it's structured to the output messages, to make it look and feel like Pester. Particularly I want clear separation of test definitions and printed output, e.g.:
1. Here are my tests, with self-explanatory names
2. Here is a loop which runs all tests, and reports on them
and that gives me something like:
Function Validate-DCUserAccountShouldExist {
param($Username) [bool](net user "$UserName")
}
Function Validate-DCUserAccountPasswordNeverExpireShouldBeSet {
param($Username) [bool]((uACADA "$username") -band 65536)
}
Function Validate-DCUserAccountShouldBeADomainAdmin {
param($Username) [bool]((Get-ADGroupMember -Identity "Domain Admins").Name -contains "$username")
}
Function Validate-DCUserAccountShouldHaveDelegationAuthorityRemoved {
param($Username) [bool]((uACADA "$Username") -band 1048576)
}
# Search for all Validation functions and run them
$tests = (gci function: |Where Name -Like 'Validate-DCUserAccount*').Name
foreach ($test in $tests) {
$result = try {
& $test "user.adm"
} catch {
$false
}
if ($result) {
Write-Host -ForegroundColor Green "[√] $test - succeeded"
} else {
Write-Host -ForegroundColor Red "[X] $test - Failed"
}
}
Which gives an output like:
My view of my second code is that:
It's longer
more complex, less easy to follow
a lot less duplication of Write-Host
more structured, separation of test definitions and output
function names explain what the state should be, which makes the output messages work for success/failure
Output messages are neater in the code, but uglier to read in the output (but could be adjusted, e.g. add spaces when printing them)
would scale to more tests nicely, just by adding more tests