Is there any way to add text to specific part of script to the currently running script?
If i have a menu with options:
Install All
Add item
Quit
Could the Add item be possible?
Learning to use powershell (heavy user of batches).
When entering Add item, then a read-host would pop up, adding a row between the long row of ### addwifi -wnm $USERINPUT afterwards 'restarting' the script.
Current script:
#cmd: title Add****
$host.ui.RawUI.WindowTitle = "Add Wi-Fi networks"
#When Show-Menu –Title 'SetupWi-Fi' is called
function Show-Menu
{
# NOTE if changing warible from somewhere else (Show-Menu -WARIBLE VALUE) then param part must be included
param (
[string]$Title = 'SetupWi-Fi'
)
Clear-Host
#cls and echo on #echo off
Write-Host "================ $Title ================"
Write-Host "a: Add Wi-Fi networks."
Write-Host "q: Quit."
}
#Do this until x
#For future shortening purposes
function addwifi
{
param (
[string]$wnm
#wnm= wifi name
)
netsh wlan add profile filename="$wnm.xml"
#for some reason (nice for this script) . stops the warible name
}
do
{
# call Show-Menu and optionally change varible: –Title 'Warible' changes the $title varible
Show-Menu
# makin varible chaase equal user input, placing Selection before it
$chaase = Read-Host "Selection:"
#switch according to the varible chaase
switch ($chaase)
{
'a' {
#'single quote' acts as echo, now executing commands of 'a' varible
'Adding Wi-Fi networks.'
$host.ui.RawUI.WindowTitle = "Adding Wi-Fi networks"
#note the upper function is called with warible
#add below here! #####################################################################
addwifi -wnm laptopidee
#add above here! #####################################################################
}
#close a execution
#close switch
}
#close do
}
#until x: selection == input q
until ($chaase -eq 'q')
One possibility is to use placeholders that you replace at runtime, though I'm not sure how well it will hold up for more complex scripts.
For example, if you have the following script:
$scriptPath = "$PsScriptRoot\$($MyInvocation.MyCommand.Name)"
$scriptContent = Get-Content "$PsScriptRoot\$($MyInvocation.MyCommand.Name)" -Raw
$newItem = Read-Host "Please enter new command"
##Placeholder
$scriptContent -replace "$([char]0x0023)$([char]0x0023)Placeholder", "$([char]0x0023)$([char]0x0023)Placeholder$([char]0x000D)$([char]0x000A)$newItem" |
Set-Content -Path $scriptPath
Each time you run it, you will be prompted for a new command, which will be added below the ##Placeholder. So, if you enter Get-Process when prompted, the script would end up on-disk like this:
$scriptPath = "$PsScriptRoot\$($MyInvocation.MyCommand.Name)"
$scriptContent = Get-Content "$PsScriptRoot\$($MyInvocation.MyCommand.Name)" -Raw
$newItem = Read-Host "Please enter new command"
##Placeholder
Get-Process
$scriptContent -replace "$([char]0x0023)$([char]0x0023)Placeholder", "$([char]0x0023)$([char]0x0023)Placeholder$([char]0x000D)$([char]0x000A)$newItem" |
Set-Content -Path $scriptPath
Next time you run the script you will be prompted for a new command, which is added to the list, and all commands already on the list will be executed.
Yes. Use external files as sources to be pulled in. The Add Item menu option creates another file to be read in at next execution.
Many people did this with batch files using .ini files to hold parameters. Similar construct.
Related
Good morning guys,
I'm new to powershell scripting. And i can't figure out what I'm doing wrong.
I tried to write a .ps1 script to compare the hash value of a stream. I used the microsoft documentation for help and modify it to a runable script so i don't need to write it over and over again.
$wc = [System.Net.WebClient]::new()
$pkgurl = Read-Host "Please enter Package Url: "
$publishedHash = Read-Host "Enter Published Hash: "
$FileHash = Get-FileHash -InputStream ($wc.OpenRead($pkgurl))
if ($FileHash.Hash -eq $publishedHash) {
Write-Host "File Hash is equal to published Hash."
}
else {
Write-Host "File Hash NOT equal to published Hash."
}
When i run the script and enter the package url and the published Hash, the program all of a sudden abruptly shuts down.
Please, anyone an idea?
The script ends as it has nothing else to do.
You can add read-host at the end to wait for user input before it closes. (it wont do anything with the input, this just forces it to stay open until input has been made.)
Alternatively if you want to use it multiple times without it closing you can create a loop:
$KeepOpen = $true
While($KeepOpen -eq $true){
$wc = [System.Net.WebClient]::new()
$pkgurl = Read-Host "Please enter Package Url: "
$publishedHash = Read-Host "Enter Published Hash: "
$FileHash = Get-FileHash -InputStream ($wc.OpenRead($pkgurl))
if ($FileHash.Hash -eq $publishedHash) {
Write-Host "File Hash is equal to published Hash."
}
else {
Write-Host "File Hash NOT equal to published Hash."
}
$user_input = Read-Host "Please enter Y to run again"
if($user_input -ne "Y"){
$KeepOpen = $false
}
}
This will keep the script open so you can see the results and if you want it to run again insert Y and hit enter and you should be back to where you start.
just wondering if its possible to escape a read-host in a while loop by pressing escape.
I've tried doing an do-else loop but it will only recognize button presses outside of the read-host.
This is basically what I have
#Import Active Directory Module
Import-Module ActiveDirectory
#Get standard variables
$_Date=Get-Date -Format "MM/dd/yyyy"
$_Server=Read-Host "Enter the domain you want to search"
#Request credentials
$_Creds=Get-Credential
while($true){
#Requests user input username
$_Name=Read-Host "Enter account name you wish to disable"
#rest of code
}
I want to be able to escape it if I want to change the domain
Using Read-Host you cannot do this, but you might consider using a graphical input dialog instead of prompting in the console. After all, the Get-Credential cmdlet also displays a GUI.
If that is an option for you, it can be done using something like this:
function Show-InputBox {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, Position = 0)]
[string]$Message,
[string]$Title = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.PSCommandPath),
[string]$defaultText = ''
)
Add-Type -AssemblyName 'Microsoft.VisualBasic'
return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $Title, $defaultText)
}
while($true) {
$_Name = Show-InputBox "Enter account name you wish to disable"
if ([string]::IsNullOrWhiteSpace($_Name)) {
# the box was cancelled, so exit the loop
break
}
# proceed with the rest of the code
}
If the user presses the Esc key, clicks Cancel, or leaves the input blank, you can exit the while loop, otherwise proceed with the code.
You cannot do it with Read-Host, but you can do it via the PSReadLine module (ships with Windows PowerShell version 5 or higher on Windows 10 / Windows Server 2016) and PowerShell Core) and its PSConsoleHostReadline function:
Important:
As of PSReadLine v2.0.0-beta3, the solution below is a hack, because the PSConsoleHostReadline only supports prompting for PowerShell statements, not open-ended user input.
This GitHub feature suggestion asks for the function to be optionally usable for general-purpose user input as well, which would allow for a greatly customizable end-user prompting experience. Make your voice heard there, if you'd like see this suggestion implemented.
The hack should work in your case, since the usernames you're prompting for should be syntactically valid PowerShell statements.
However, supporting arbitrary input is problematic for two reasons:
Inapplicable syntax coloring will be applied - you could, however, temporarily set all configurable colors to the same color, but that would be cumbersome.
More importantly, if an input happens to be something that amounts to a syntactically incomplete PowerShell statement, PSConsoleHostReadline won't accept the input and instead continue to prompt (on a new line); for instance, input a| would cause this problem.
Also:
Whatever input is submitted is invariably added to the command history.
While you can currently remove a temporarily installed keyboard handler on exiting a script, there is no robust way to restore a previously active one - see this GitHub issue.
# Set up a key handler that cancels the prompt on pressing ESC (as Ctrl-C would).
Set-PSReadLineKeyHandler -Key Escape -Function CancelLine
try {
# Prompt the user:
Write-Host -NoNewline 'Enter account name you wish to disable: '
$_Name = PSConsoleHostReadLine
# If ESC was pressed, $_Name will contain the empty string.
# Note that you won't be able to distinguish that from the user
# just pressing ENTER.
$canceled = $_Name -eq ''
# ... act on potential cancellation
} finally {
# Remove the custom Escape key handler.
Remove-PSReadlineKeyHandler -Key Escape
}
I wrote this function that works for me.
# Returns the string "x" when Escape key is pressed, or whatever is indicated with -CancelString
# Pass -MaxLen n to define max string length
function Read-HostPlus()
{
param
(
$CancelString = "x",
$MaxLen = 60
)
$result = ""
$cursor = New-Object System.Management.Automation.Host.Coordinates
while ($true)
{
While (!$host.UI.RawUI.KeyAvailable ){}
$key = $host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
switch ($key.virtualkeycode)
{
27 { While (!$host.UI.RawUI.KeyAvailable ){}; return $CancelString }
13 { While (!$host.UI.RawUI.KeyAvailable ){}; return $result }
8
{
if ($result.length -gt 0)
{
$cursor = $host.UI.RawUI.CursorPosition
$width = $host.UI.RawUI.MaxWindowSize.Width
if ( $cursor.x -gt 0) { $cursor.x-- }
else { $cursor.x = $width -1; $cursor.y-- }
$Host.UI.RawUI.CursorPosition = $cursor ; write-host " " ; $Host.UI.RawUI.CursorPosition = $cursor
$result = $result.substring(0,$result.length - 1 )
}
}
Default
{
$key_char = $key.character
if( [byte][char]$key_char -ne 0 -and [byte][char]$key_char -gt 31 -and ($result + $key_char).Length -le $MaxLen )
{
$result += $key_char
$cursor.x = $host.UI.RawUI.CursorPosition.X
Write-Host $key_char -NoNewline
if ($cursor.X -eq $host.UI.RawUI.MaxWindowSize.Width-1 ) {write-host " `b" -NoNewline }
}
}
}
}
}
How can I enter a keystroke programmatically through a PowerShell script?
Write-Host -ForegroundColor Green 'Loading...'
Function EnterKey {
[Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
#Where I want to get "|" keystroke programmatically
[System.Windows.Forms.SendKeys]::SendWait("{|}")
}
Function StartUp {
Write-Host "Environment"
$exe = ([IO.Path]::Combine("D:\7ZipApp\7ZipApp\7ZipApp\bin\Debug","7ZipApp.exe"))
& $exe 3 # argument 3 = 'Run local Sync'
EnterKey
Read-Host -Prompt $exe.ToString()
}
StartUp
Write-Host -ForegroundColor Green 'Loading...'
function StartUp {
Write-Host 'Environment'
$exe = Join-Path "D:\7ZipApp\7ZipApp\7ZipApp\bin\Debug" "7ZipApp.exe"
#& $exe 3 # argument 3 = 'Run local Sync'
start $exe -ArgumentList 3
Write-Host 'Type {|} to continue'
while ((Read-Host) -ne '{|}') {}
Read-Host -Prompt $exe.ToString()
}
StartUp
I have to go with the crowd here (from the comments):
I would abandon your approach. Too problematic.
My question was why you want to do it
The correct solution, then, is to get the author of 7zipapp.exe to fix the program so it stops doing that or to add a command-line parameter that prevents this behavior.
That said, if you want a total hack, and this program only takes ONE input, at the end presumably, then the below appears to work. I would use sparingly, perhaps never use it, but rather get the program fixed, but in my testing, this worked.
PowerShell:
$exe = 'C:\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe'
'\r\n' | & $exe
Annoying C# program:
using static System.Console;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
WriteLine("I will force you to hit Enter to exit.");
ReadLine();
}
}
}
so i am working with a bit of code that after setting a static location for the CSV i am using for import. When i run the code it seems to run until i get the Windows can't open this File pop. you know the one with what do you want to do options, like user the web services to find the correct program. i am copying the code so hopefully someone can point on where i made this fubar. just for note before i made the CSV static the Script asked you to type the location in every time so maybe i missed a setting there
if ($args[0] -eq $null)
{
$userNameFile = D:\lync_creation\userlog.csv
$userNameFile = $usernamefile -replace '"',""}
else
{$usernamefile = $args[0]}
if ($userNameFile -ne "")
{$csv=import-csv $userNameFile}
else
{"Could not find a valid .csv with the user information."
exit}
foreach($c in $csv)
# enable for lync
{
"Enabling " + $c.Identity + " for Lync 2010"
Enable-csuser -identity $c.Identity -registrarpool pool01.west.com –sipaddresstype EmailAddress
}
write-host "Press any key to continue..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,AllowCtrlC")
You are seriously over complicating things if you're just going to use a static location for your CSV file.
$csv = Import-CSV D:\lync_creation\userlog.csv
foreach($c in $csv){
"Enabling $($c.Identity) for Lync 2010"
Enable-csuser -identity $c.Identity -registrarpool pool01.west.com –sipaddresstype EmailAddress
}
write-host "Press any key to continue..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,AllowCtrlC")
The first line imports the CSV file into a variable.
The next 4 loops through all entries in that variable, write the host who it's enabling and then enables the person.
The last 2 lines give a Press any key to continue message and then waits for a key press before continuing.
Working through Jerry Lee Ford Jr.'s Powershell 2.0 for the Absolute Beginner book. There's a lot of typographical errors in the code of the book that I've been able to work through and correct (great practice), but there's one I simply can't seem to figure out. Downloaded his stock code from the companion website, and his code is throwing the exact same error. Code is as follows:
# *************************************************************************
#
# Script Name: GameConsole.ps1 (The PowerShell Game Console)
# Version: 1.0
# Author: Jerry Lee Ford, Jr.
# Date: January 1, 2007
#
# Description: This PowerShell script provides a listing of PowerShell
# game scripts and allows the player to play any game by
# entering its menu number.
#
# *************************************************************************
# Initialization Section
$menuList = #() #Stores an array containing information about script games
$playAgain = "True" #Controls the execution of a loop that controls game
#execution
# Functions and Filters Section
#This function gets the player's permission to begin the game
function Get-GameListing {
$gameList = #() #Stores and array containing a list of PowerShell scripts
$i = 0 #Used to set the index value of the array when adding elements to it
Clear-Host #Clear the screen
Write-Host #Display a game console header
Write-Host " --------------------------------------------------------------"
Write-Host " Windows PowerShell Game Console" -foregroundColor darkred
Write-Host " --------------------------------------------------------------"
$location = Set-Location C:\ShellScripts\Games #Specify the location of the game scripts
#Load an array with a list of all the PowerShell scripts in the specified folder
$gameList = Get-ChildItem . *.ps1 # | ForEach-Object -process {$i++; $gameList[$i] = $_.Name }
$gameList #Return the contents of the array to the calling statement
}
#This function displays a menu listing of PowerShell games
function Write-MenuList {
param($list) #The list of games to be displayed is passed as an array
$Counter = 0 #Used to number each menu item
Write-Host ""
ForEach ($i in $list) { #Iterate for each script stored in the array
$counter++ #Increment the counter by 1
if ($counter -lt 10) { #Format the display of the first 9 scripts
Write-Host " $counter. $i" -foregroundColor blue
}
else { #Format the display of all remaining scripts
Write-Host " $counter. $i" -foregroundColor blue
}
}
Write-Host "`n --------------------------------------------------------------"
}
function End-ScriptExecution {
Clear-Host #Clear the screen
Write-Host "`n Thank you for using the Windows PowerShell Game Console"
Start-Sleep 3 #Pause the execution of the script for 3 seconds
Clear-Host #Clear the screen
}
# Main Processing Section
$response = 0 #Stores player input
#Continue playing new games until the player decides to close the game console
while ($playAgain -eq "True") {
#Call the function that generates an array containing a list of game scripts
$menuList = Get-GameListing
#Call function that converts the contents of the array into a list of menu items
Write-MenuList $menuList
#Prompt the player to pick a game to play
$response = Read-Host "`n Enter the menu number for a game or Q to quit"
#Prepare to close the game console when the user decides to quit
if ($response -eq "Q") {
$playAgain = "False" #Modify variable value in order to terminate the loop
continue #Repeat the loop
}
#Convert the player's input to a integer and then validate the player's input
if ([int]$response -lt 1) { #Anything below 1 is not a valid menu number
Clear-Host #Clear the screen
Write-Host "`n `a`aInvalid selection."
Read-Host #Pause the script until the player presses the Enter key
continue #Repeat the loop
}
if ([int]$response -gt $menuList.length) {
Clear-Host #Clear the screen
Write-Host "`n `a`aInvalid selection."
Read-Host #Pause the script until the player presses the Enter key
continue #Repeat the loop
}
Invoke-Expression $menuList[$response] #Executed the selected game script
Clear-Host #Clear the screen
}
End-ScriptExecution
The error being thrown is:
The term 'fortuneteller.ps1' is not recognized as the name of a cmdlet, functio
n, script file, or operable program. Check the spelling of the name, or if a pa
th was included, verify that the path is correct and try again.
At line:1 char:18
+ fortuneteller.ps1 <<<<
+ CategoryInfo : ObjectNotFound: (fortuneteller.ps1:String) [], C
ommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
No matter what ps script menu item I choose, I'm getting the same error. Any help would be greatly appreciated!
Modify this line:
Invoke-Expression $menuList[$response] #Executed the selected game script
to:
Invoke-Expression $menuList[$response].FullName
or my preference:
& $menuList[$response].FullName
It was failing most likely because it is trying to execute "FortuneTeller.ps1" and the working directory is either not in that dir or even if it is in that dir, PowerShell will not execute a script from the current dir without specifying the path e.g. ".\FortuneTeller.ps1". By specifying the full path via the FullName property this problem is avoided.