Exiting from a powershell menu - powershell

I've created a powershell menu script but occasionally I don't want to use the menu function I have created I want to come out and run a custom command, or even better add a menu feature which allows me to write a custom command.
Can anyone help me achieve this please?
write-host "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
write-host "Exchange Online Management"
write-host
write-host "Press 1: To assign Full Access To A Mailbox"
write-host "Press 2: Get Mailbox Size"
write-host "Press 3: Custom Exchange Command"
write-host "Press Q: To Leave Exchange Management"
write-host
write-host
write-host "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
$SM2 = Read-Host "Please Make A Selection"
Switch ($SM2) {
'1'{
DO something
}
'2' {
$Mailboxuser = read-host "Who's Mailbox are you trying to query?"
Get-MailboxStatistics $Mailboxuser | ft DisplayName, TotalItemSize, ItemCount
}
'3' {
return
}
'Q' {
Remove-PSSession $Session
return
}
}
}
until ($SM -eq 'Q')

The PowerShell console window is closing after it has finished executing your script.
You can get around this by running another powershell process with your script:
'Q' {
Remove-PSSession $Session
& powershell
}
The other option is to create a shortcut to your script and add the -NoExit switch, which stops the window from closing when the script is finished.
PowerShell -NoExit "C:\folder\script.ps1"

Related

Powershell script - Remove-AppxPackage

I'm trying to build a powershell script to do 4 things:
Create a list with Get-AppxPackage and Output-File - works
Erase with Remove-AppxPackage - doesn't work
Display a list on the terminal - works
Quit the script - works
How do I put the second option running without problems?
Here's the code for the second option:
function Erase {
([string] $app) = Read-Host -Prompt "Insert the AppxPackage name."
cls
Write-Host $app
$appchoice = Read-Host -Prompt "Is this the correct name? Answer Y or N."
cls
If (($appchoice -eq 'Y') -or ($appchoice -eq 'y')) {
Get-AppxPackage "'$app'" | Remove-AppxPackage -AllUsers "'$app'"
Write-Host "The package $app was erased."
Read-Host -Prompt "Press enter to continue."
Menu
} Else {
Write-Host "Somehow we messed things up. Let's start again!"
Read-Host -Prompt "Press enter to continue."
Menu
}
}
The error is the image attached to this question. It doesn't even prompts the user for the name...
Thanks in advance.

How can I get the following to execute after the remote powershell session is established?

I'm working on a script that gets the quick and full scan times and then prompts a menu to select which type of scan to run. The issue I'm getting is that after the remote PowerShell session is established, the rest of the code doesn't run. Here is what I have.
<# create powershell remote session #>
$ComputerName = Read-Host "Enter Computer Name"
Enter-PSSession -ComputerName $computerName
<# checks to see if powershell session is active #>
if (Test-Path variable:PSSenderInfo) {
Get-MpComputerStatus | Select QuickScanEndTime, FullScanEndTime
}
<# Make selection based on scan end times #>
function Show-Menu
{
Write-Host "1: Run Quick Scan"
Write-Host "2: Run Full Scan"
}
Show-Menu
$selection = Read-Host "Please make a selection"
switch ($selection)
{
'1' {
Start-MpScan -ScanType QuickScan
} '2' {
Start-MpScan -ScanType FullScan
}

giving variables to another powershell console [duplicate]

This question already has answers here:
How to pass a variable to new console window in Powershell
(2 answers)
Closed last year.
I have a script that opens a powershell console as admin and do sth in eventlog.
I have two variables that i the new admin-PS console needs.
[string] $PiEventLog = "'Company Name Prv.Limt'"
[String] $PiEventLogSource = "'XY-Test'"
I am opening the new PS-Console like this
start powershell -Verb runas {
If(Get-EventLog -List | ?{$_.Log -like $PiEventLog}){
Write-Host "EventLog already exists." -ForegroundColor Yellow
}
else{
New-EventLog -LogName $PiEventLog -Source $PiEventLogSource -ErrorAction Stop
Write-Host "EventLog was successfully created." -ForegroundColor Green
}
Read-Host "Press any key to close the console..."
}
If i try to execute the script, i get the following error:
The argument for the parameter "LogName" cannot be checked. The
argument is NULL or empty. Specify an argument that is not NULL or
empty and re-execute the command.
anyone got an idea, how i can give those two variables to the new PS-console, without having to set two different variables in the new console?
I believe this should work, it's easier if you use a Here-String. Since you're using the -like operator, I would assume you're looking for a Log that "contains" the input given in $PiEventLog, in that case, you should use wildcard characters: -like "*$PiEventLog*".
param(
[string] $PiEventLog = 'Company Name Prv.Limt',
[String] $PiEventLogSource = 'XY-Test'
)
$command = #"
If(Get-EventLog -List | Where-Object Log -Like '*$PiEventLog*'){
Write-Host 'EventLog already exists.' -ForegroundColor Yellow
}
else{
New-EventLog -LogName $PiEventLog -Source $PiEventLogSource -ErrorAction Stop
Write-Host 'EventLog was successfully created.' -ForegroundColor Green
}
Read-Host "Press any key to close the console..."
"#
Start-Process powershell -Verb RunAs -ArgumentList '-c', $command
Then you call this script like:
PS /> ./script.ps1 -PiEventLog 'something' -PiEventLogSource 'something'

canceling get-credentials in loop

I am working on developing PowerShell script to automate a task on a remote server by using Invoke-Command with WinRM.
The script will take the server IP, test WinRM and "Get-Credential" cmdlet to establish session and use Invoke-Command to run another script on remote server. I have made significant progress of what I want to achieve, however, I am having trouble on how to setup the code so that when I press the "Cancel" or "X" button on Get-Credential prompt it should abort the script and return to the regular PowerShell command line prompt.
Below is what I have so far, I have erased the comments and description of the code to keep the number of words less in here.
function SS
{
Add-Type -AssemblyName System.Windows.Forms
$BInput = [System.Windows.Forms.MessageBox]::Show('Do you want to proceed?', 'Confirmation',[System.Windows.Forms.MessageBoxButtons]::YesNo)
switch ($BInput)
{
"Yes" {
while ($true)
{
$server=Read-Host "Enter Server IP Address"
set-item -Path WSMan:\localhost\Client\TrustedHosts -Value "$server" -Force
if(Test-WSMan -ComputerName $server -ErrorAction SilentlyContinue)
{
Write-Host "$server is accessible, enter credentials to connect"
while ($true)
{
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
$serversession = New-Pssession -ComputerName $server -Credential $creden -ErrorAction SilentlyContinue
if(-not($serversession))
{
write-warning "Credentials are not valild, please try again"
}
else
{
write-host "$server is connected, starting the workflow ......"
Invoke-Command -Session $serversession -FilePath "C:\Temp\XXX.ps1"
}
}
Break
}
else
{
write-host "Windows Remote Management (WinRM) protocol is not running, please check service and confirm."
}
}
Get-Pssession | Remove-PSSession
}
"No" {
Break
}
}
}
I understand I have to apply the changes / logic after this line
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
But can't seem to find it yet. I looked online and have taken different approaches but no success so far. I would like to have opinions or recommendations on how to tackle this, appreciate your help.
Thanks
What i'm seeing is that you may be thinking too much into it. A simple if statement should do the trick, try:
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
if(!$creden){break}
Continuing from my comment.
Try this refactor of your use case.
Point of note: Note fully tested since I do not have an environment at this time to test.
Function Start-WorkFlow
{
<#
.Synopsis
Execute a workflow
.DESCRIPTION
Sets up a WinRM session to a remote host to execute the defined workflow
.EXAMPLE
Start-WorkFlow
.EXAMPLE
swf
.INPUTS
Remote host IPAddress
Remove host credentials
.OUTPUTS
Resutls of teh workflow
.NOTES
V 0.0.1 - Prototype script. Clean-Up before production use
.COMPONENT
Stand-alone script
.ROLE
Administrative actions
.FUNCTIONALITY
Implemetned error logic for each code block
Restrict the user input to only be a proper IPAddress
Validate TCPIP state
Validate WSman state
Establish a new session
Process workflow
Exit session
#>
[cmdletbinding(SupportsShouldProcess)]
[Alias('swf')]
Param
(
)
If ((Read-Host -Prompt 'Do you want to proceed: [Yes/No]') -eq 'No' )
{Break}
Else
{
Do {$RemoteServerIPAddress = (Read-Host -Prompt 'Enter Server IP Address')}
Until ($RemoteServerIPAddress -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
Get-ChildItem -Path 'WSMan:\localhost\Client\TrustedHosts'
Try
{
(Test-Connection -ComputerName $RemoteServerIPAddress -Count 1 -ErrorAction Stop).IPV4Address
# Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value $RemoteServerIPAddress -Force
Get-ChildItem -Path 'WSMan:\localhost\Client\TrustedHosts'
Try
{
Test-WSMan -ComputerName $RemoteServerIPAddress -ErrorAction Stop
"$RemoteServerIPAddress is accessible, enter credentials to connect"
Do
{
$Creds = $null
$CredMesssage = 'Please enter the remote server credentials that you want to connect.'
$CredMesssage = "$CredMesssage If credentials are not valid, you will be prompted to re-enter them."
$Creds = Get-Credential -Message $CredMesssage
if(-Not $creds)
{
Write-Warning -Message 'Credential request cancelled.'
Start-Sleep -Seconds 3
Exit
}
$NewPSSessionSplat = #{
ComputerName = $RemoteServerIPAddress
Credential = $Creds
Name = 'RemoteSessionName'
ErrorAction = 'Stop'
}
New-PSSession $NewPSSessionSplat
}
Until (Get-PSSession -Name 'RemoteSessionName')
"$RemoteServerIPAddress is connected, starting the workflow ......"
Invoke-Command -Session $RemoteServerSession -FilePath 'C:\Temp\XXX.ps1'
}
Catch
{
Write-Warning -Message 'Session connection results:'
$PSitem.Exception.Message
}
Finally
{
Get-PSSession |
Remove-PSSession -ErrorAction SilentlyContinue
}
}
Catch
{
Write-Warning -Message "
The remote server $RemoteServerIPAddress is not available
Exiting the session."
Start-Sleep -Seconds 3
Exit
}
}
}
Start-WorkFlow

Using Read-host with Input validation and TRAP

I'm just a typical admin trying to make a simple script for some IT assistants in remote offices, to make domain joins easier while minimizing potential errors. The script's end game is to run the one-liner command Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart.
But the whole script is supposed to include input validation for the computer's new name as well as for the target OU for the two-letter code for the remote office.
Googling for code snippets for days, esp. from sites like yours, was very helpful. But the problem I have now is I couldn't find the right codes to combine Read-Host , input length validation, and TRAP to work together without losing the value for my variables.
Pardon my coding as obviously I'm no real PS scripter, and I know the wrong portions of it are very basic. I would want to spend more time if I had the luxury, but I would really so much appreciate it if you could point me in the right direction.
Thank you so much in advance.
Please see my code below:
# START: Display name and purpose of invoked script
$path = $MyInvocation.MyCommand.Definition
Clear-Host
Write-Host $path
Write-Host " "
Write-Host "This script will allow you to do the following in a single-step process:"
Write-Host "(1) RENAME this computer"
Write-Host "(2) JOIN it to MYDOMAIN"
Write-Host "(3) MOVE it to a target OU"
Write-Host "(4) REBOOT"
Write-Host " "
Pause
# Function: PAUSE
Function Pause ($Message = "Press any key to continue . . . ") {
if ((Test-Path variable:psISE) -and $psISE) {
$Shell = New-Object -ComObject "WScript.Shell"
$Button = $Shell.Popup("Click OK to continue.", 0, "Script Paused", 0)
}
else {
Write-Host -NoNewline $Message
[void][System.Console]::ReadKey($true)
Write-Host
}
Write-Host " "
}
# Function: Define the parameters
Function Define-Parameters {
# Specify new computer name, with validation and TRAP
$WS_NewName = $null
while ($null -eq $WS_NewName) {
[ValidateLength(8,15)]$WS_NewName = [string](Read-Host -Prompt "NEW NAME of computer (8-15 chars.)" )
TRAP {"" ;continue}
}
Write-Host " "
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Specify the target OU, with validation and trap
$baseOU='OU=Offices OU,DC=mydomain,DC=net'
$OU2 = $null
while ($null -eq $OU2) {
[ValidateLength(2,2)]$OU2 = [string](Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)' )
TRAP {"" ;continue}
}
Write-Host " "
$LocDN = "OU=$OU2,$baseOU"
}
# Function: Summary and confirmation screen for defined parameters.
Function Confirm-Parameters {
Write-Host "==========================================================================="
Write-Host "Please confirm that you are joining this computer to
$DomainToJoin (MYDOMAIN)"
Write-Host "with the following parameters:"
Write-Host ""
Write-Host ""
Write-Host "Computer's NEW NAME: $WS_NewName"
# Write-Host "Domain to Join: $DomainToJoin"
Write-Host "TARGET mission OU: $OU2"
}
# Call Define-Parameters Function
Define-Parameters
# Call Confirm-Parameters Function
Confirm-Parameters
<#
Some more code here
#>
# FINAL COMMAND if all else works: Join the computer to the domain, rename it, and restart it.
# Add-Computer -DomainName $DomainToJoin -OUPath $LocDN -NewName $WS_NewName -Restart
In your code, you have a lot of things defined very strangely. Your functions create a new scope and the variables you're trying to define therein will disappear after calling them unless you change the variable scope (in this case, to $script: or $global:). Also, to use functions, you need to define them first (your Pause doesn't actually do anything)
Here's something you can do with your Define-Parameters function (I suggest looking at Get-Verb)
# Domain to join.
$DomainToJoin = 'mydomain.net'
# Function: Define the parameters
Function Get-Parameters {
do {
$global:WS_NewName = Read-Host -Prompt 'NEW NAME of computer (8-15 chars)'
} until ($WS_NewName.Length -gt 7 -and $WS_NewName.Length -lt 16)
''
do {
$global:OU2 = Read-Host -Prompt 'Target OU (TWO-LETTER code for your office)'
} until ($OU2 -match '^[a-z]{2}$')
''
$OU2 = "OU=$global:OU2,OU=Offices OU,DC=mydomain,DC=net"
}
I'd strongly recommend moving away from the ISE to do your testing and test in an actual powershell console.
Perhaps Try/Catch block instead of trap?
Try {
[ValidatePattern('^\w{8,15}$')]$compname=read-host 'enter comp name' -ErrorAction Stop
[ValidatePattern('^\w{2}$')]$OU=read-host 'enter OU name' -ErrorAction Stop
}
Catch {
$ErrorMessage = $_.Exception.Message
$ErrorLineNumber = $_.InvocationInfo.ScriptLineNumber
$ErrorCommandName = $_.InvocationInfo.InvocationName
Write-Error -Message "The error message was: <$ErrorMessage>, script line: <$ErrorLineNumber>, command name: <$ErrorCommandName>"
exit 255
}