Powershell - Interact with executable's command line prompts? - powershell

I need to automate some tasks against a legacy application. It doesn't have an API, but the vendor offers a .exe I can run to perform various tasks against the application.
I can call the .exe from within PowerShell just fine, but after calling it it prompts for the following input:
Do you agree to the license: YES
User name: myuid
Password: SuperSecretPassword`
I can run this interactively from the command prompt just fine and manually enter the requested input as prompted, but I need to automate this in a script. The .exe doesn't accept any command line parameters for this either(it's an old app), the only parameters I can pass are the commands I want to execute against the application. The .exe is only command line based with no GUI, so GUI automation tools aren't an option either.
I could do this easily with expect in a *nix shell, however given that I have a .exe I need to run, that's out of the question. There doesn't appear to be an "expect" equivalent in Windows, so I'm curious if this can be accomplished in PowerShell?
Note: For Windows scripts I prefer PowerShell, but could utilize VBScript if necessary.

If I remember correctly, if it's just one line you can pipe a string to an exe eg. "asdf" | example.exe, but it's multiple lines of input you might need to use SendKeys
Add-Type -AssemblyName 'System.Windows.Forms'
$ID = (Start-Process example.exe -PassThru).id
Sleep 1
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.Interaction]::AppActivate([Int32]$ID)
[System.Windows.Forms.SendKeys]::SendWait("YES~")
[System.Windows.Forms.SendKeys]::SendWait("myuid~")
[System.Windows.Forms.SendKeys]::SendWait("SuperSecretPassword~")

Related

Powershell Script only opens as a .txt file when run

Hi I have a script on a memory stick that I want to be able to run in cmd line before a computer has windows fully installed. (the stage just after you've connected to a network).
Cmd used to run the script.
Start > Run D:\pscript\Intune.ps1
This only opens a .txt file, while researching I've found that the reason this happens is due to security, is there anyway to override this bar changing the default file type out.
Unlike batch files (.cmd, .bat) associated with cmd.exe (the legacy Command Prompt), PowerShell's .ps1 script files are by default not directly executable from outside PowerShell.
Instead, they are treated as documents that are by default associated with either Notepad or the (obsolescent) Windows PowerShell ISE, depending on the , and invoking them therefore opens them for editing, which applies to the following contexts:
Invoking a .ps1 file from cmd.exe
Invoking a .ps1 file from Start Menu's Run dialog, as in your case (which you can invoke with WinKey+R, for instance)
Opening (double-clicking) a .ps1 file from File Explorer or Desktop.
To execute a .ps1 script from outside PowerShell, you must therefore invoke it via PowerShell's CLI, powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+.
In the simplest case, using Windows PowerShell and the -File parameter, as also shown by Mathias R. Jessen in a comment; see the comments below and the linked docs for additional parameters:
# Note:
# * The effective execution policy applies; use -ExecutionPolicy Bypass to bypass.
# * Profiles are loaded; use -NoProfile to suppress.
# * The console window auto-closes when the script terminates; use -NoExit
# to keep the session open.
powershell.exe -File D:\pscript\Intune.ps1
For a comprehensive overview of PowerShell's CLI, see this post.
It is possible - though not advisable - to configure your system to execute .ps1 files by default - see this answer.

Powershell function call causes missing function error using powershell v7 on windows 10

I wrote a script to build all .net projects in a folder.
Issue
The issue is I am getting a missing function error when I call Build-Sollution.
What I tried
I made sure that function was declared before I used it so I am not really sure why it saids that it is not defined.
I am new to powershell but I would think a function calling another functions should work like this?
Thanks in advance!
Please see below for the error message and code.
Error Message
Line |
3 | Build-Sollution $_
| ~~~~~~~~~~~~~~~
The term 'Build-Sollution' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Build-Sollution:
Code
param (
#[Parameter(Mandatory=$true)][string]$plugin_path,
[string]$depth = 5
)
$plugin_path = 'path/to/sollutions/'
function Get-Sollutions {
Get-ChildItem -File -Path $plugin_path -Include *.sln -Recurse
}
function Build-Sollution($solution) {
dotnet build $solution.fullname
}
function Build-Sollutions($solutions) {
$solutions | ForEach-Object -Parallel {
Build-Sollution $_
}
}
$solutions_temp = Get-Sollutions
Build-Sollutions $solutions_temp
From PowerShell ForEach-Object Parallel Feature | PowerShell
Script blocks run in a context called a PowerShell runspace. The runspace context contains all of the defined variables, functions and loaded modules.
...
And each runspace must load whatever module is needed and have any variable be explicitly passed in from the calling script.
So in this case, the easiest solution is to define Build-Sollution inside Build-Sollutions
As for this...
I am new to powershell but I would think a function calling another
functions should work like this?
... you cannot use the functions until you load your code into memory. You need to run the code before the functions are available.
If you are in the ISE or VSCode, if the script is not saved, Select All and hit use the key to run. In the ISE use F8 Selected, F5 run all. In VSCode, F8 run selected, crtl+F5 run all. YOu can just click the menu options as well.
If you are doing this from the consolehost, the run the script using dot sourcing.
. .\UncToYourScript.ps1
It's ok to be new, we all started somewhere, but it's vital that you get ramped up first. so, beyond what I address here, be sure to spend time on Youtube and search for Beginning, Intermediate, Advanced PowerShell for videos to consume. There are tons of free training resources all over the web and using the built-in help files would have given you the answer as well.
about_Scripts
SCRIPT SCOPE AND DOT SOURCING Each script runs in its own scope. The
functions, variables, aliases, and drives that are created in the
script exist only in the script scope. You cannot access these items
or their values in the scope in which the script runs.
To run a script in a different scope, you can specify a scope, such as
Global or Local, or you can dot source the script.
The dot sourcing feature lets you run a script in the current scope
instead of in the script scope. When you run a script that is dot
sourced, the commands in the script run as though you had typed them
at the command prompt. The functions, variables, aliases, and drives
that the script creates are created in the scope in which you are
working. After the script runs, you can use the created items and
access their values in your session.
To dot source a script, type a dot (.) and a space before the script
path.
See also:
'powershell .net projects build run scripts'
'powershell build all .net projects in a folder'
Simple build script using Power Shell
Update
As per your comments below:
Sure the script should be saved, using whatever editor you choose.
The ISE does not use PSv7 by design, it uses WPSv5x and earlier.
The editor for PSv7 is VSCode. If you run a function that contains another function, you have explicitly loaded everything in that call, and as such it's available.
However, you are saying, you are using PSv7, so, you need to run your code in the PSv7 consolehost or VSCode, not the ISE.
Windows PowerShell (powershell.exe and powershell_ise.exe) and PowerShell Core (pwsh.exe) are two different environments, with two different executables, designed to run side-by-side on Windows, but you do have to explicitly choose which to use or write your code to branch to a code segment to execute relative to the host you started.
For example, let's say I wanted to run a console command and I am in the ISE, but I need to run that in Pwsh. I use a function like this that I have in a custom module autoloaded via my PowerShell profiles:
# Call code by console executable
Function Start-ConsoleCommand
{
[CmdletBinding(SupportsShouldProcess)]
[Alias('scc')]
Param
(
[string]$ConsoleCommand,
[switch]$PoSHCore
)
If ($PoSHCore)
{Start-Process pwsh -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
Else {Start-Process powershell -ArgumentList "-NoExit","-Command &{ $ConsoleCommand }" -PassThru -Wait}
}
All this code is doing is taking whatever command I send it and if I use the PoSHCore switch...
scc -ConsoleCommand 'SomeCommand' -PoSHCore
... it will shell out to PSCore, run the code, otherwise, it just runs from the ISE>
If you want to use the ISE with PSv7 adn not do the shell out thing, you need to force the ISE to use PSv7 to run code. See:
Using PowerShell Core 6 and 7 in the Windows PowerShell ISE

How to make a Powershell script answer a prompt for user input?

I have a Powershell script that needs to execute a command-line executable that prompts for user input (for which there is no command-line parameter). Something like this:
# promptsForInput.ps1
$someInput = Read-Host "Gimme some input"
# do something with $someInput
The actual executable is a compiled binary which I cannot modify, but this example script do for the purposes of this question. My Powershell script calls the executable:
# myScript.ps1
.\promptsForInput.ps1
At runtime, I get prompted to input something:
> .\myScript.ps1
Gimme some input:
I need to be able to fill in that input request without user intervention. When promptsForInput.ps1 prompts for user input, I need myScript.ps1 to enter the required value and proceed with script execution.
Similar questions on SO either have answers specific to the particular exe, or are otherwise unhelpful:
How to fill the prompt in powershell script
Powershell: Uninstall Software that has prompts for user input
How to "answer" a console input prompt in PowerShell (in the code)
How to write to user input in powershell
Don't use $input as the name of a variable as that's an automatic variable in PowerShell (see help about_Automatic_Variables).
Determine whether the executable can accept command-line arguments instead of stopping or prompting for input. This is obviously preferred if it is available.
Whether you can tell PowerShell to automatically send input to an arbitrary executable depends upon the design of that executable. If the executable allows you to send standard input to it, you can run something like
"test" | myexecutable.exe
In this example, PowerShell will provide the string test and a return as standard input to the executable. If the executable accepts standard input, then this will work.
If the executable does not use standard input, then you will have to do something different like send keystrokes to the window. I consider sending keystrokes a last resort and a brittle solution that is not automation-friendly.
Following sample I used to run batch file and provide inputs
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Start-Process -FilePath C:\myexecbatchfile.bat
# Wait the application start for 2 sec
Start-Sleep -m 2000
# Send keys
[System.Windows.Forms.SendKeys]::SendWait("input1")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
Start-Sleep -m 3000
[System.Windows.Forms.SendKeys]::SendWait("input2")
[System.Windows.Forms.SendKeys]::SendWait("{ENTER}")

VB equivalent to powershell

I am very new to powershell and sometimes this question may be so simple
Can please anybody please tell me what is the equivalent to the following(vbscript) in PowerShell
set obj = wscript.createobject( wscript.shell )
Obj.Run $smCmnd
What is the use of wscript.shell.
After a bit of search I found first line can be presented as;
$obj = New-Object -ComObject WScript.Shell
But have have no idea how to call Run method ($obj.run(...)???)
If I run cmd.exe with some commands as the smCmnd, How can I keep cmd.exe without close and to run another command later in same console??
EDIT
I am writing PS script and it will be call from another application. Basically it will do some folder creations and file coping etc. I would like to open CMD.exe and show all the commands running on that. How to use same cmd prompt through out my whole script.
Is smCmnd a string of shell commands? If so, you can call them directly from PowerShell, without trying to get a wscript.shell COM object to run them against like you'd need to do in VBScript.
VBScript wasn't a shell. Powershell is. You can write shell commands directly in .ps1 or .ps2 files, just like in a batch file.
I'm not a powershell expert here, but try doing
& $smCmnd
Try running $smCmnd directly. If that fails, use Invoke-Expression $smCmnd.
If you do need to use CMD.EXE (possibly because you want to run pre-existing BAT file), and you want all of the output in a single CMD window you can pipe all the input into cmd at once like this:
# Powershell script to execute existing BAT file
cmd.exe /k "cd c:\batchfiles & firstone.bat & second.bat & echo that's all folks"
# CMD will remain open (/k). User will have to type exit to return to powershell
# Or if you want user just to hit any key to leave CMD prompt:
cmd.exe /c "c:\batchfiles\mybatchfile.bat & pause"
# /C means CMD should close after is has executed the commands on the command line
However if you want to have something execute in CMD, then make a decision in your Powershell script about what to execute next in CMD then do something similar to the answer at the following link which pipes input and output between a powershell script and CMD.exe.
How to run interactive commands in another application window from powershell

How to Make Objects Persist after Running Powershell ISE Script

This is my script:
Add-Type -Path C:\MyClassLibrary\HidClassLib.dll
$hidDevice = New-Object HidClassLib.CAN_USBPort("test")
$hidDevice.openPort()
When I run this script from the command line in PowerShell ISE it runs properly and adds the HidClassLib.dll to my path.
The $hidDevice variable doesn't persist however, and before I can use it I have to retype those two lines. Is there any way to make it so that the $hidDevice would persist after running the script?
You mean that it doesn't persist between sessions? In that case, add it to your PowerShell profile!
Here's a great article on how to do that:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb613488(v=vs.85).aspx
Just add the line(s) to the applicable profile and it will run every time a shell opens.