PowerShell in C# commands - c#

I'm completely new to PowerShell and am confused about some of its command syntax. I've been looking around google; however, some of the syntax I've found such as
Send-Keys "%(ea)Testing{Enter}{F5}"
has errors that I can't seem to get rid of.
Say I open Calculator with
var script = #"
Start-Process calc.exe
";
powerShell.AddScript(script);
powerShell.Invoke();
How does one go about entering in values for fields and sending keystrokes?
That is, enter in a 5, hit the - key, enter in a 6, then hit the ENTER key?
Or even better,
how does one, using PowerShell, enter in some stock symbol (which isn't the default textfield) then search for it by hitting enter? (after opening firefox.exe, navigating to www.yahoo.com)
Thank you for your time

Key SendKeys
BACKSPACE {BACKSPACE}, {BS}, or {BKSP}
BREAK {BREAK}
CAPS LOCK {CAPSLOCK}
DEL or DELETE {DELETE} or {DEL}
DOWN ARROW {DOWN}
END {END}
ENTER {ENTER} or ~
ESC {ESC}
HELP {HELP}
HOME {HOME}
INS or INSERT {INSERT} or {INS}
LEFT ARROW {LEFT}
NUM LOCK {NUMLOCK}
PAGE DOWN {PGDN}
PAGE UP {PGUP}
PRINT SCREEN {PRTSC}
RIGHT ARROW {RIGHT}
SCROLL LOCK {SCROLLLOCK}
TAB {TAB}
UP ARROW {UP}
SHIFT +
CONTROL ^
ALT %
BACKSPACE {BACKSPACE}, {BS}, or {BKSP}
One thing to bear in mind is that it takes a while for the application to start-up, you could be sending your keys before calculator is ready for them.
Try something like:
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms
Calc
start-sleep -Milliseconds 500
[Microsoft.VisualBasic.Interaction]::AppActivate("Calc")
[System.Windows.Forms.SendKeys]::SendWait("1{ADD}1=")
This should get you a quote from google:
$IE=new-object -com internetexplorer.application
$IE.navigate2("https://www.google.co.uk/finance?client=ob&q=NASDAQ:MSFT")
$IE.visible=$true

I can't go to www.yahoo.com as it automatically redirects me to uk.yahoo.com.
I was able however to go to http://finance.yahoo.com and do exactly what you want.
Bit ugly and relies on the page layout but it seems to be working:
add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms
& 'C:\Program Files (x86)\Mozilla Firefox\firefox.exe' -url http://finance.yahoo.com
start-sleep 3
[System.Windows.Forms.SendKeys]::SendWait("{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}{TAB}FB{ENTER}")

Related

MessageBox in Powershell not brought to front

I'm using an application which allows me to run Powershell scripts on devices within my network and I need to prompt users with a MessageBox.
My script creates the MessageBox fine, but my issue is that it always displays behind my application. I tried a solution online which suggested creating a new form with property Topmost=true and passing it as the first parameter, however it didn't seem to work. Is there anything immediately obvious that I'm doing wrong?
Add-Type -AssemblyName PresentationCore,PresentationFramework
$top = new-Object System.Windows.Forms.Form -property #{Topmost=$true}
$Result = [System.Windows.Forms.MessageBox]::Show($top, $MessageBody,$MessageTitle,$ButtonType,$MessageIcon)
Spawned windows need a parent. If they don't they will fall behind other windows (as you've found).
The following isn't PowerShell related, per se ... but it's what you need to know/do to get where you want to go...
Why isn't MessageBox TopMost?
and possibly
In Powershell how do I bring a messagebox to the foreground, and change focus to a button in the message box
The $this method does NOT work. I do not know where you people get your information or if you even know how to code in Powershell at all, but your are providing misinformation. I tested the $this method and I can absolutely assure you that it does not work in any way shape or form in PowerShell.
Here is the only method that TRULY works in PowerShell:
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.Interaction]::MsgBox('MyMessage','OKOnly,SystemModal,Information', 'HeaderText')
It is the SystemModal parameter that forces the MsgBox to dominate and always remains on top no matter what.
There is also another documented method, the Wscript.Shell method, that other people claim that it works, see below.
New-Object -ComObject Wscript.Shell
$wshell.Popup("MyMessage",0,"MyHeader",0 + 16 + 4096)
Where first 0 = No timeout, second 0 = OKOnly, 16 = Critical, 4096 = SystemModal
It also do NOT work as I was STILL able to go back to my previous form and make changes to it while the MsgBox was displayed, which is what I do not want.
You don't need to use a [System.Windows.Forms.Form] object, you can do it in 1 line by using the $this variable as the first parameter:
$Result = [System.Windows.Forms.MessageBox]::Show($this, $MessageBody, $MessageTitle, $ButtonType, $MessageIcon)

WPF Progress Bar PowerShell

I have been trying to get a WPF progress bar in to my PowerShell script for awhile now, but i can not figure it out. I have tried probably 13 different ways but to no avail. Here is my code:
$WPFRunQuick_Button.Add_Click({
<# Add-Type -AssemblyName System.Windows.Forms
$Form.Text = "Processing"
$Label = New-Object System.Windows.Forms.Label
$Font = New-Object System.Drawing.Font("Times New Roman",16,[System.Drawing.FontStyle]::Bold)
$form.Font = $Font
$Form.Controls.Add($Label)
$Label.Text = "You have run the quick test, please be patient as it runs."
$Label.AutoSize = $True
$form.autosize = $true
$form.AutoScroll = $true
$form.autosizemode = "GrowAndShrink"
$Form.MinimizeBox = $False
$Form.MaximizeBox = $False
$Form.SizeGripStyle = "Hide"
$form.startposition = "CenterScreen"
$Form.Visible = $True
$Form.Update() #>
$max = 100
For($i = 1; $i -le $max; $i++){
Write-progress -Activity “Device Check” -Status “Testing, please wait.” `
-percentcomplete ($i / $max*100) -id 1
sleep 1
}
# Quick Test Run Function
Quick_Test_Run
# Prompt to send logs to associate support
$a = new-object -comobject wscript.shell
$intAnswer = $a.popup("Do you want to send these results?", 0,"Results",4)
if ($intAnswer -eq 6) {
$a.popup("Results Sent")
# Create email
$EmailSubject = "Tasa Test"
$EmailTo = "usupportlogs#test.com"
$EmailBody = [IO.File]::ReadAllText("C:\Temp\PMCS_TicketLogs.log")
# Send email to usupportlogs inbox
Send-MailMessage -From "PMCS_No_Reply#test.com" -To $EmailTo -subject $EmailSubject -Body $EmailBody -SmtpServer "SMTPRR.Cerner.Com"
} else {
$a.popup("Sending Cancelled")
}
$Form.Close()
})
When i try to put one in before i call the quick test function, it will load all the way then launch the test, and if i put it in after it will do the test and then launch the progress bar. I just want a simple progress bar for this script. Any help or insight would be appreciated, thanks!
In a script I created recently, my GUI application would check availability of a series of computers in our corporate estate by iterating through a user-submitted list of IP Addresses (a System.Windows.Forms.TextBox named in my script as $boxIpInput) and perform a Test-Connection conditional statement on each one. To allow the users to see what progress the scripts had made on the ping tests, I used a System.Windows.Forms.ProgressBar to communicate the progress of the script; I found this out by googling for "Powershell Forms Progress Bar" and happened upon this link.
To create the ProgressBar object, I used the following code;
$barPingProgress= New-Object System.Windows.Forms.ProgressBar
$barPingProgress.Size= New-Object System.Drawing.Size(274,20);
$barPingProgress.Location= New-Object System.Drawing.Size(8,440);
$barPingProgress.Style= 'Continuous'
$barPingProgress.Value= 0
$objForm.Controls.Add($barKioskPingProgress);
Upon clicking the $btnRunIpCheck Button to perform the ping test, I used the input from $boxIpInput and piped it into a ForEach-Object loop to incrementally increase the count of the progress bar in a similar way to your For loop before the Quick_Test_Run function (I have removed all irrelevant code from the below snippet for brevity);
//other button initialisation code (removed)
...
$btnRunIpCheck.Add_Click({
//some code to validate entries (removed)
...
$arrTmpIpAddresses= $boxIpInput.Text.Split(" `n",[System.StringSplitOptions]::RemoveEmptyEntries)
//some code to check size of list and warn users of the time it would take (removed)
...
$arrTmpIpAddresses | ForEach-Object {
$intOrderCount++
[int]$tmpProgNum= ($intOrderCount/$arrTmpIpAddresses.Count) * 100
$barPingProgress.Value= $tmpProgNum
//ping test code (removed)
}
}
}
Personally, I would recommend using the System.Windows.Forms.ProgressBar object over the Write-Progress method you're using at present; in the case of your code, you can either add the ProgressBar object as a part of the Add_Click event or have it created when you generate the main $Form object and then begin the Value incrementation during the Add_Click event.
To further help you, I'd need to understand what it is that you're counting the progress against - I can't really see what you're counting against (aside from the "Device Check" part that is) so I don't feel comfortable incorporating an example of how the ProgressBar Form would work in the context of your code. If you want me to help you further, you'll need to give me a little more detail. :)

How to send Keys to an application

I have a very basic problem, For a game (Dota 2) I want to write a little macro which opens the console, writes "setinfo name ".........................."" into it and then closes it, the hotkey for console is set to '#'. For this I wrote an application which listens for the key 'f' to be pressed, and then send
1) '#' (open the console)
2) "messag ebla bla b...."
3) '#' (close the console)
everything is working except that it will not open the console (but if the console is already open it will write #messagej.j....# into it when i press f just as wanted)
my code for sending the keys.
SendKeys.Send("#");
SendKeys.Send("my message for consol");
SendKeys.Send("#");
does anybody know why the hotkeys dont work by sending keys? I thought its an simulation of when the user presses F or Q.
First thing You should try is adding a "software" delay between keypresses.
string MSG = "#yourmessage#";
foreach (object c_loopVariable in MSG) {
c = c_loopVariable;
Sendkeys.Send(c);
sleep(20);
}
The other thing to consider - sendkeys do not emulate the keypress at the hardware layer - it is on windows API level, and the DirectX DirectInput., witch most games use for user input processing goes a level further. So it is possible You will not be able to do it this easy.
You should check out more of keybd_event. Ive had better luck using that - as i understand it goes a level deeper than just sendkeys.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646304(v=vs.85).aspx
Anyways, I hope u are not going to use this for some spamming in a great game! :)

Simulate KeyPress in C# to Game

I'm trying to simulate a keypress into another window, which is a game. The things that don't work are:
SendKey - Send the input as strings like some text or something but doesn't go for ENTER TAB or other critical keys
InputSimulator - Complete waste of time
SendInput - Have some problems with this as well. It doesn't compile, and I've never used it before
PostMessage - it seems these 2 are pretty much the same and again they do send text but again no other keys such as ENTER TAB or other. Also couldn't figure out the value for wParam if i wanna hold down the key for a number of seconds. It is a 32bit Hex value in which seems the last 16 are repetition number.
SendMessage - See PostMessage
AUTOIT or AHK it seems that they have troubles being incorporated into C# if anyone knows how to do that, it would help immensely, this meaning I'd be able to write AHK script in the C# .cs file so it would compile. COM, ref, or anything.
Having problems with DirectInput
public void Test_KeyDown()
{
INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].ki.wScan = (short)VirtualKeyCode.NUMPAD2 ; //ScanCode;
InputData[0].ki.dwFlags = (int)KEYEVENTF.SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].ki.wScan = (short)VKeys.VK_W;
InputData[1].ki.dwFlags = (int)(KEYEVENTF.KEYUP | KEYEVENTF.UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}
}
It gives this error:
Could not load file or assembly 'Microsoft.DirectX.DirectInput.dll' or one of
its dependencies. is not a valid Win32 application.
(Exception from HRESULT: 0x800700C1)
I've referenced it from DirectX SDK tool kit 2007
I'm trying to send a key to another instance or handle. C++ or C# anything that works is fine, too.
Looks like you are trying to load a 32bit dll in a 64 bit solution, so please use the 64bit dll

Gems with .NET Applications - How do I set up the Executables so they run without error?

I have a gem, roundhouse, which is an application compiled with .NET (C#). Runs on Windows and it should run in a 32 bit process.
To set up my gemspec, I set:
Gem::Specification.new do |s|
s.platform = 'mswin32'
s.name = 'roundhouse'
s.version = version
s.files = Dir['lib/**/*'] + Dir['bin/**/*']
s.bindir = 'bin'
s.executables << 'rh.exe'
When I install the gem, I should be able to type rh.exe from the command line at any path and it should run correctly.
In practice, I'm not seeing this work correctly. This is what I'm getting back:
Window has this for the header: 16 bit MS-DOS Subsystem
C:\WINDOWS\system32\cmd.exe - rh.exe
The NTVDM CPU has encountered an illegal instruction.
CS:xxxx IP:xxxx OP:xx xx xx xx xx Choose 'Close' to terminate the application.
Here is a picture of the issue (link to TwitPic): Error
If I go to the directory where the item was installed, I can run it and it works great. It's just something in the registration of the command to run from anywhere.
I did quite a bit of searching before asking and came up with nothing. It could be that I don't know what I should be searching for. So let me ask the question, is there a way to register an executable with gems for windows executable applications (built with .NET) and have them register properly with the command line? If so, how is that done?
UPDATE:
I found that gems creates a shim in the C:\Ruby\bin directory that points back to the other file. So there is a rh.exe file that is really just a text file. This is its contents:
#!C:/Ruby/bin/ruby.exe
#
# This file was generated by RubyGems.
#
# The application 'roundhouse' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'roundhouse', version
load Gem.bin_path('roundhouse', 'rh.exe', version)
if you're distributing it with the file "rh.exe"
then you'll want to create a file
bin/rh
s.executables << 'bin/rh'
then when it's installed gems will create an "rh.bat" file which runs ruby "bin/rh" essentially (as you've seen).
So within bin/rh put something like
result = system(File.dirname(__FILE__) + "/rh.exe" ARGV.join(' '))
exit 1 unless result
result = system(File.dirname(__FILE__) + "/rh.exe " + ARGV.join(' '))
exit 1 unless result
So the endresult should maybe look like? note the space after 'rh.exe'

Categories