Do_While stuck in a loop Powershell - powershell

I am trying to come up with a simple function to verify credentials before running other commands in ExchangeOnline.
Here is my problem(s):
IF I run the function with correct credentials the first time, it proceeds as expected. But if the credentials are wrong the first time, it get stuck in the "Get-credential" loop even when I provide the correct credentials. can't seem to find what the issue is.
try
{
$Global:ErrorActionPreference ='Stop'
$Usercreds= Get-Credential -Message "Please enter your Elevated account credentials"
Connect-MsolService -Credential $Usercreds
Write-Host "`nSuccesfully authenticated" -ForegroundColor Green
Get-MsolDomain
}
catch
{
#$Global:ErrorMessage = $_.Exception.Message
$Global:ErrMsg= $Error[0]
Write-Host `n$Global:ErrMsg -ForegroundColor Red
}
}
DO{
verCreds
}WHILE($Global:ErrMsg -like "Authentication Error: *")

This is because the ErrMsg is a global variable and it will always have the value of Authentication Error: even you entered the credential right.
try to clear its value in the last step of the try
try
{
$Global:ErrorActionPreference ='Stop'
$Usercreds= Get-Credential -Message "Please enter your Elevated account credentials"
Connect-MsolService -Credential $Usercreds
Write-Host "`nSuccesfully authenticated" -ForegroundColor Green
Get-MsolDomain
$Global:ErrMsg = $null
}
catch
{
#$Global:ErrorMessage = $_.Exception.Message
$Global:ErrMsg= $Error[0]
Write-Host `n$Global:ErrMsg -ForegroundColor Red
}
}
DO{
verCreds
}WHILE($Global:ErrMsg -like "Authentication Error: *")

Related

Statements has no effect (if/else) in PS

I'm working on a script that gets executed only if X account is found, but is not working as intended the if/else statements get bypassed and the code gets executed anyways. What am i doing wrong?
$Account = "XXXX"
Get-LocalUser -name $Account
if (($Account) -eq $true) {
} else {
Write-host -foreground cyan "I found it"
}
exit
If i ran the script as is it will output the text on the console even tho "XXX" account is not present, could something like that can be done?
This should do it:
$Account = "XXXX"
$AccountObject=Get-LocalUser -name $Account -ErrorAction SilentlyContinue
if (($AccountObject)) {
Write-host -foreground cyan "I found it"
} else {
Write-host -foreground cyan "No luck"
}
The issue with the sniplet provided - the return of Get-LocalUser was not used. Instead you were using a string value which is always set therefore true - as you set it to 'XXXX' in your first line.
As Bill_Stewart explains, the reason that the else block is reached is because ($Account) -eq $true evaluates to $false unless the account name is "true".
In order to test whether Get-LocalUser succeeded or failed to retrieve the user account, you can instead inspect the $? automatic variable - it will have a value of $false only if the previous command threw an error:
$AccountName = "nonExistingUser"
# Try to fetch existing user account, don't show any errors to the user
$UserAccount = Get-LocalUser -Name $AccountName -ErrorAction SilentlyContinue
# Test if the call was successful
if($?) {
Write-Host "Found account named '$AccountName'!" -ForegroundColor Cyan
$UserAccount
} else {
Write-Host "No account named '$AccountName' was found ..." -ForegroundColor Magenta
}

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

Not entering Function

I'm trying to write a script to remotely rename multiple computers. Here's what I have (I know the Verify function works so that can be skipped over. The issue is occurring with the GetComputers function)
function main{
$DomainCredential = Verify
$computers = GetComputers
#Rename -computers $computers -DomainCredential $DomainCredential
}
function Verify{
# Prompt for Credentials and verify them using the DirectoryServices.AccountManagement assembly.
Write-Host "Please provide your credentials so the script can continue."
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
# Extract the current user's domain and also pre-format the user name to be used in the credential prompt.
$UserDomain = $env:USERDOMAIN
$UserName = "$UserDomain\$env:USERNAME"
# Define the starting number (always #1) and the desired maximum number of attempts, and the initial credential prompt message to use.
$Attempt = 1
$MaxAttempts = 5
$CredentialPrompt = "Enter your Domain account password (attempt #$Attempt out of $MaxAttempts):"
# Set ValidAccount to false so it can be used to exit the loop when a valid account is found (and the value is changed to $True).
$ValidAccount = $False
# Loop through prompting for and validating credentials, until the credentials are confirmed, or the maximum number of attempts is reached.
Do {
# Blank any previous failure messages and then prompt for credentials with the custom message and the pre-populated domain\user name.
$FailureMessage = $Null
$Credentials = Get-Credential -UserName $UserName -Message $CredentialPrompt
# Verify the credentials prompt wasn't bypassed.
If ($Credentials) {
# If the user name was changed, then switch to using it for this and future credential prompt validations.
If ($Credentials.UserName -ne $UserName) {
$UserName = $Credentials.UserName
}
# Test the user name (even if it was changed in the credential prompt) and password.
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
Try {
$PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $ContextType,$UserDomain
} Catch {
If ($_.Exception.InnerException -like "*The server could not be contacted*") {
$FailureMessage = "Could not contact a server for the specified domain on attempt #$Attempt out of $MaxAttempts."
} Else {
$FailureMessage = "Unpredicted failure: `"$($_.Exception.Message)`" on attempt #$Attempt out of $MaxAttempts."
}
}
# If there wasn't a failure talking to the domain test the validation of the credentials, and if it fails record a failure message.
If (-not($FailureMessage)) {
$ValidAccount = $PrincipalContext.ValidateCredentials($UserName,$Credentials.GetNetworkCredential().Password)
If (-not($ValidAccount)) {
$FailureMessage = "Bad user name or password used on credential prompt attempt #$Attempt out of $MaxAttempts."
}
}
# Otherwise the credential prompt was (most likely accidentally) bypassed so record a failure message.
} Else {
$FailureMessage = "Credential prompt closed/skipped on attempt #$Attempt out of $MaxAttempts."
}
# If there was a failure message recorded above, display it, and update credential prompt message.
If ($FailureMessage) {
Write-Warning "$FailureMessage"
$Attempt++
If ($Attempt -lt $MaxAttempts) {
$CredentialPrompt = "Authentication error. Please try again (attempt #$Attempt out of $MaxAttempts):"
} ElseIf ($Attempt -eq $MaxAttempts) {
$CredentialPrompt = "Authentication error. THIS IS YOUR LAST CHANCE (attempt #$Attempt out of $MaxAttempts):"
}
}
} Until (($ValidAccount) -or ($Attempt -gt $MaxAttempts))
# If the credentials weren't successfully verified, then exit the script.
If (-not($ValidAccount)) {
Write-Host -ForegroundColor Red "You failed $MaxAttempts attempts at providing a valid user credentials. Exiting the script now... "
EXIT
} Else {
Write-Host "Credntials authenticated"
return $Credentials
}
}
function GetComputers{
$oldnames = New-Object System.Collections.ArrayList
Write-Output "Enter the PC numbers to be named. Do not include 'PC' only type the following numbers. Type 'end' when finished"
$userinput = Read-Host
while($userinput -ne "end"){
$userinput = "$('PC')$($userinput)"
[void]$oldnames.Add($userinput)
$userinput = Read-Host
}
return $oldnames
}
workflow Rename($computers, $DomainCredential){
foreach -parallel ($computer in $computers){
$newname = "$($computer)$('MK')"
Rename-Computer -PSComputerName $computer -NewName $newname -DomainCredential $DomainCredential
}
}
main
The Verify function works perfectly, but then it just hangs and nothing else happens. I added a debug line between the call of the Verify and the call of the GetComputer functions, and that also printed out. Im new to powershell and am out of ideas
Are you certain that it is hanging, or is Read-Host just showing a blank input location? Calling that function without any arguments will just give you a blinking cursor in command line. Try adding some form of prompt to read-host, like below:
PS C:\Users\mbolton> $var=read-host
"string"
PS C:\Users\mbolton> $var
"string"
PS C:\Users\mbolton> $var=read-host "type something in"
type something in: "different string"
PS C:\Users\mbolton> $var
"different string"
PS C:\Users\mbolton>

Upload local users outlook client signature to Office 365 OWA (remotely) - On-prem exchange to Exchange online

We are in the process of migrating user mailboxes from on-prem exchange to office 365. Since we are only doing few users at a time, our requirements were to sync local outlook client signatures into office 365 OWA portal. So user sees the same signature on their OWA portal.
Has anyone done this?
I have figured it out. So I have created a script to help our migration team to upload local outlook client signature to office 365.
You need to have admin access to user PC and exchange online admin privileges such as Global Administrator.
Here is the code:
write-host "`n`n`n`n"
#initializing variables
$username = $null
$computer = $null
$path = $null
$number = $null
$i = 0
$select = $null
$signs = $null
$chkerr = $false
$session = $null
#Run a continous loop
do {
#if powershell is not connected to office 365 then run the connection code below
if ($session.State -ne "opened") {
Write-Host "`nChecking connection to Office 365: " -NoNewline
Write-Host "Inactive!" -ForegroundColor white -BackgroundColor red
Write-Host "`nConnecting to Office 365 account...`n"
#Get user office 365 credentials
$UserCredential = Get-Credential
#create session
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
#start the session to office 365
Import-PSSession $Session
Sleep 4
}
#if the session to 365 is success then run the code below
if ($?) {
Write-Host "`nChecking connection to Office 365: " -NoNewline
Write-Host "Active!" -ForegroundColor Black -BackgroundColor green
#Start a loop to prompt for username and machinename
do {
#this variable is used below and set as false if there is an error. Also, shows a message that user need to re-enter the information
$chkerr = $false
if ($chkerr) {write-host "`nPlease try again..." -BackgroundColor yellow -ForegroundColor black}
#store username and machine name
$username = Read-Host "`n`nPlease enter user name"
$computer = Read-Host "Please enter computer name"
#if machine is not pingable then show an error
if (!(Test-Connection $computer -Count 1) ) {Write-Host "`nError: Computer is offline or name is incorrect" -ForegroundColor white -BackgroundColor red; $chkerr = $true}
else {
#if machine is pingable then check if signature direcotry exists
if (!(Test-Path "\\$computer\c$\Users\$username\AppData\Roaming\Microsoft\Signatures\")) { Write-Host "`nError: Outlook signature directory does not exists `nOR `nUsername is incorrect!" -ForegroundColor white -BackgroundColor red;$chkerr = $true}
}
#show error msg if username or machine name is left blank
if ($username -eq $null -or !$username -or $computer -eq $null -OR !$computer) {Write-Host "`nError: Username or computer name cannot be left empty" -ForegroundColor white -BackgroundColor red;$chkerr = $true }
#repeatedly ask for username and machine name until user gets it right or moves on to next username and machine name
} while ($chkerr)
#set the path to signature directory
$path = "\\$computer\c$\Users\$username\AppData\Roaming\Microsoft\Signatures"
#get a list of signature files and store them in a variable
$number = Get-ChildItem "$path\*.htm"
#check if there are any signature files at all
if ($number -or $number -ne $null) {
#start a loop
do {
#if there are multiple signature files found then show them on screen
Write-Host "`nSelect one for following file:`n"
for ([int]$i=0;$i -lt $number.count; $i++) {
Write-Host ("$i" +' --> ' + $number[$i].name)
}
#if there is more than one signature file then prompt user to select one
if ($number.count -gt 1) {
$select = Read-Host "`nPlease enter your selection"
#show error if user enters a number that is of selection
if ([int]$select+1 -gt [int]$number.Count) {Write-Host "`nError: Please enter a valid selections!" -ForegroundColor white -BackgroundColor red}
} else {
#if only one signature file is found then do not prompt and select that one file as default
$select = "0"
Write-Host "`nOnly one file found, selecting default file -->" $number[$select].name -ForegroundColor black -BackgroundColor yellow
}
#repeat the loop until user selects atleast one signature file
} while ([int]$select+1 -gt [int]$number.Count)
#show the selected signature file
Write-Host "You have selected following signature file:" $number[$select].fullname
sleep 3
#grab the html file and store it into a variable
Write-Host "`nImporting signatures into powershell"
$signs = Get-Content $number[$select].fullname
#show error if the signature import fails
if (!$?) {Write-Host "`nError: Unable to import signature into powershell!" -ForegroundColor white -BackgroundColor red}
else {
Write-Host "`nSuccess!" -ForegroundColor Black -BackgroundColor green
Write-Host "`nImporting signatures to Office 365 account of $username"
#import the signature into users OWA and set it to be used during replies, forwards and message creations.
Get-Mailbox $username | Set-MailboxMessageConfiguration -SignatureHtml $signs -AutoAddSignature:$true -AutoAddSignatureOnReply:$true -AutoAddSignatureOnMobile:$true
if (!$?) {Write-Host "`nError: Unable to import signature into Office 365 account!" -ForegroundColor white -BackgroundColor red}
else {Write-Host "`nSuccess!" -ForegroundColor Black -BackgroundColor green}
}
}
else {
#show error if no signature files are found
Write-Host "`nError: No signature files found!" -ForegroundColor white -BackgroundColor red
}
}
else {
# show error if we are unable to connect to office 365 account.
Write-Host "`nError: Connection to office 365 is required for this script to work" -ForegroundColor white -BackgroundColor red
}
} while ($true)
Successful test of Output:
Making connection:
After successfull connection:
After entering username and password:
After making the selection:
OWA view:
Error checking against user input:
Entering wrong office 365 credentials:
Entering correct computer name but wrong username:
Entering correct username but wrong computer name:
Entering wrong selecting that is out of the provided set of options:
You can also modify the script to grab input from an excel sheet.

How to detect if Azure Add-AzureAccount login fails or is canceled?

In an Azure PowerShell script I use Add-AzureAccount to login the user to Azure. But how do I detect if the user didn't finish the login successfully so that I can abort the script?
Another way to do this is to use a try and catch block.
try {
Add-AzureAccount -ErrorAction Stop
}
catch {
Write-Error $_.Exception.Message
}
#Write the remaining script here
#Control won't come here unless the Add-AzureAccount was successful
Write-Verbose 'User logged in'
However, any Microsoft account would be able to login even if they don't have any subscriptions associated. So, here is a bit modified code.
try {
$a = Add-AzureAccount -ErrorAction Stop
if ($a.Subscriptions) {
Write-Verbose 'User Logged in'
} else {
throw 'User logged in with no subscriptions'
}
}
catch {
Write-Error $_.Exception.Message
}
#Write the remaining script here
#Control won't come here unless the Add-AzureAccount was successful
Not really a PowerShell expert (and hoping we would get better answers), but can't we do something like the following:
$a = Add-AzureAccount
If ($a)
{
Write-Verbose "User logged in"
}
Else
{
Write-Verbose "User not logged in"
}
I use following function, and the key is using the -warningVariable which will capture if the user canceled the login screen on purpose or if the logged in user doesn't have any subscriptions attached. Just in case something is not captured I added an errorAction stop so the exceptions are also taken care of.
The script below also offers the chance to re-enter credentials in case the user made a mistake.
function LoginAzure
{
try
{
$a = Add-AzureAccount -ErrorAction Stop -WarningVariable warningAzure -ErrorVariable errorAzure
if ($warningAzure -ne "")
{
$continue = Read-Host "Following warning occured: " $warningAzure " Press 'R' to re-enter credentials or any other key to stop"
if ($continue -eq "R")
{
LoginAzure
}
else
{
exit 1
}
}
}
catch
{
$continue = Read-Host "Following error occured: " $errorAzure " Press 'R' to re-enter credentials or any other key to stop"
if ($continue -eq "R")
{
LoginAzure
}
else
{
exit 1
}
}
     
}
Import-Module "C:\Program Files (x86)\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Azure.psd1"
LoginAzure