Problem with selecting Radio Button & Forms on web page

by xeen at 2012-08-29 11:37:40

Hello.

I am a new in using PowerShell, co please, forgive maybe stupid questions. In my work, I need to automate usage of some web page, and I can’t modify this page. So source of this page looks like below: <INPUT TYPE="radio" NAME="action" VALUE="build">0<br>
<INPUT TYPE="radio" NAME="action" VALUE="rebuild">1<br>
<INPUT TYPE="radio" NAME="action" VALUE="appbuild">2<br>
<INPUT TYPE="radio" NAME="action" VALUE="special">3<br>
<INPUT TYPE="radio" NAME="action" VALUE="publogs">4<br><br>


I trying to use funciton: getElementByID, getElementsByTagName or getElementsByName. Unfortunetly non of this work.
I just need to choose option 3 and then use button submit to go to the next page.

I think i made a very simple mistake, but can’t go further, but it is very important for me. I using tutorials and other stuff from google. main link: http://msdn.microsoft.com/en-us/magazine/cc337896.aspx. I forget to bring my code from work to home, so I can post it tommorow.

Thanks for your help in advance,
Greg
by poshoholic at 2012-08-29 17:56:10
Assuming you have already called the Navigate method to load the web page and that you’re using a variable called $ie for the Internet Explorer COM object, you would do something like this:

[script=powershell]# Select the "special" radio button (note that the last Where-Object clause identifies the button to select)
$radioButtonToClick = $ie.document.getElementsByTagName('input') | Where-Object {($.type -eq 'radio') -and ($.name -eq 'action') -and ($.value -eq 'special')}
# Now set it as the active button and simulate a click on it
$radioButtonToClick.setActive()
$radioButtonToClick.click()[/script]
Note that I haven’t tested this snippet. I just put it together from some examples I came across. It should give you a good nudge in the right direction towards a solution.
by xeen at 2012-08-29 23:09:26
Thanks for your fast reply. But unfortunetly it won’t work, here is output from console:
PS C:\Users\bly7qpp> $ie = new-object -com "InternetExplorer.Application"


PS C:\Users\bly7qpp> $ie.navigate("http://site/&quot;&#41;


PS C:\Users\bly7qpp> $ie.visible = $true


PS C:\Users\bly7qpp> $doc = $ie.document


PS C:\Users\bly7qpp> $radioButtonToClick = $ie.document.getElementsByTagName('input') | Where-Object {($
.type -eq 'radio') -and ($.name -eq 'action') -and ($.value -eq 'special')}



PS C:\Users\bly7qpp> $radioButtonToClick.setActive()
You cannot call a method on a null-valued expression.
At line:1 char:30
+ $radioButtonToClick.setActive <<<< ()
+ CategoryInfo : InvalidOperation: (setActive:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull



PS C:\Users\bly7qpp> $radioButtonToClick.click()
You cannot call a method on a null-valued expression.
At line:1 char:26
+ $radioButtonToClick.click <<<< ()
+ CategoryInfo : InvalidOperation: (click:String) , RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull




Also, i made this a fully scirpt:


$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("http://webpage.address/&quot;&#41;
$ie.visible = $true
$radioButtonToClick = $ie.document.getElementsByTagName('input') | Where-Object {($
.type -eq 'radio') -and ($
.name -eq 'action') -and ($
.value -eq 'special')}
$radioButtonToClick.setActive()
$radioButtonToClick.click()

but ther results are the same.

Any ideas?
by poshoholic at 2012-08-30 04:24:03
I would start by seeing if you are able to get the radio buttons at all, without specifying their name, like this:

[script=powershell]$ie.document.getElementsByTagName('input') | Where-Object {($.type -eq 'radio') -and ($.name -eq 'action')}[/script]
If that returns nothing, then what about just doing it by type:

[script=powershell]$ie.document.getElementsByTagName('input') | Where-Object {($.type -eq 'radio')}[/script]
Or just by tag name:

[script=powershell]$ie.document.getElementsByTagName('input')[/script]
You should see the radio buttons in the output from one of these commands. If you see results from the first one, which is what I’m expecting, then it’s about figuring out how to identify the radio button you want to click on. You should be able to identify the radio button by position like this:

[script=powershell]$radioButtons = $ie.document.getElementsByTagName('input') | Where-Object {($.type -eq 'radio') -and ($.name -eq 'action')}
$radioButtonIWantToSelect = $radioButtons[3] # choose the 4th radio button[/script]

If you want it to be based on the value property instead, pass $radioButtons to Get-Member to see if there is a value member. Or pass them to Format-List * to look at their properties and find the property that you can use to uniquely identify the button you want.

Those are just a few steps I would take to go a little further towards finding the radio button to click on. Give some of those a try and let me know what happens.
by xeen at 2012-08-30 04:45:23
PS C:\Users\bly7qpp> $ie = new-object -com "InternetExplorer.Application"


PS C:\Users\bly7qpp> $ie.navigate("http://web.site/&quot;&#41;


PS C:\Users\bly7qpp> $ie.visible = $true


PS C:\Users\bly7qpp> $ie.document.getElementsByTagName('input') | Where-Object {($
.type -eq 'radio') -and ($
.name -eq 'action')}




PS C:\Users\bly7qpp> $ie.document.getElementsByTagName('input') | Where-Object {($
.type -eq 'radio')}




PS C:\Users\bly7qpp> $ie.document.getElementsByTagName('input')




PS C:\Users\bly7qpp> $radioButtons = $ie.document.getElementsByTagName('input') | Where-Object {($
.type -eq 'radio') -and ($
.name -eq 'action')}



PS C:\Users\bly7qpp> $radioButtonIWantToSelect = $radioButtons[3]
Cannot index into a null array.
At line:1 char:43
+ $radioButtonIWantToSelect = $radioButtons[ <<<< 3]
+ CategoryInfo : InvalidOperation: (3:Int32) [], RuntimeException
+ FullyQualifiedErrorId : NullArray


I tried different combinations, without results.
Is it important to make Window of IE active or something? Because IE window is in background after $ie.visible = $true
This is output, so it looks like this method is unproper. Maybe there is a some other option for this?
by poshoholic at 2012-08-30 05:25:00
Oh, there is something else I was forgetting. It can take a moment for a web page to load. If you run this interactively, do you wait after the $ie.visible = $true command to see that the page is fully loaded before you run the rest of the commands? You might want to add a call to Start-Sleep if you’re running this in a script to make sure the page is loaded. Another thing to test is whether or not it is performing a case-sensitive lookup of the element by tag name (i.e. does it make a difference if you invoke $ie.document.getElementsByTagName(‘INPUT’) instead of $ie.document.getElementsByTagName(‘input’)?).
by xeen at 2012-08-30 05:59:58
Yes, i waiting a few seconds before do anything else after $ie.visible = $true.
I made "INPUT" but it do not change anything. so i don’t know what is going on with this page.
by poshoholic at 2012-08-30 07:37:03
Based on how you describe the problem, the getElementsByTagName should be working. Without being able to see it for myself though, and without being able to inspect the $ie.document object in PowerShell to see what it actually contains, I’m limited on how I can help here. That would be my next suggestion though. Once you load the document, look at $ie.document properties, see if you can inspect what the document you have loaded actually contains, validate that it contains what you expect or, if not, identify why it doesn’t contain what you expect. Another idea would be to create a very simple web page on your local system that contains some radio buttons, see if you can automate that. You should be able to, and if you can it would indicate that the problem is something about the web page you are loading not exposing those controls the way you think it does. Unless this web page is something that is public that I can take a look at using scripts on my own system, you’re going to have to dig in deeper and identify why those controls are not there when you load the page (which is what the results you have shared seem to be indicating).
by xeen at 2012-08-31 00:55:44
Unfortunetly i can’t give you a web page. But, could you help mi with Get-members, and explain how to get need informations?
And maybe i can give you some infomrations you also need?
by poshoholic at 2012-08-31 05:04:05
Sure. Whenever you have an object, and you want to see what properties and methods that object has available, you can pipe that object to Get-Member, like this:

[script=powershell]$ie.document | Get-Member[/script]
If there is a specific member you are looking for, you can search by name as well:

[script=powershell]$ie | Get-Member -Name Document[/script]
If the Document member exists, you will see the member definition. If not, Get-Member returns nothing. Get-Member is a command you will use a lot when you’re trying various tasks out with PowerShell because it allows you to inspect what objects have to offer.

If you use Get-Member to see the properties available on $ie.Document, you will see there is a Body property. This in turn has a InnerHtml property. If you look at the contents of $ie.Document.Body.InnerHtml, does it contain the radio button definitions you are expecting to see?
by xeen at 2012-08-31 05:12:20
Here is the output: PS C:\Users\bly7qpp> $ie | Get-Member -Name Document


TypeName: System.__ComObject#{d30c1661-cdaf-11d0-8a3e-00c04fc9e26e}

Name MemberType Definition
---- ---------- ----------
Document Property IDispatch Document () {get}



_________________________________________________________________
PS C:\Users\bly7qpp> $ie | Get-Member -Name Document.Body.InnerHtml

So, it looks like there is no avalible methods?

Maybe full page code will be helpfull:

[code2=html]<HTML>
<HEAD>
<BODY>
<P>
<H2>Please choose an action:<br></H2>
<form action="/cgi-bin/ep_choose_app.pl" method="POST">
<INPUT TYPE="radio" NAME="action" VALUE="build">Submit Initial Build<br>
<INPUT TYPE="radio" NAME="action" VALUE="rebuild">Submit Re-Build<br>
<INPUT TYPE="radio" NAME="action" VALUE="appbuild">Submit Application Build<br>
<INPUT TYPE="radio" NAME="action" VALUE="special">Submit Special Request<br>
<INPUT TYPE="radio" NAME="action" VALUE="publogs">View Archive Logs<br><br>
<INPUT TYPE="submit" VALUE="submit">
</P>
</BODY>
</HTML>[/code2]Link to the page is without any extension, so i cant be sure this is a strict html or maybe it is an aspx page.
by poshoholic at 2012-08-31 05:39:11
I just loaded up a web page that has a poll on it with 6 radio buttons, and I was able to use the technique identified here to select one of those via PowerShell and then click on the button to submit my selection and it worked as expected.

Note that for Get-Member, you can’t identify a chain of members, like this:

[script=powershell]$ie | Get-Member -Name Document.Body.InnerHtml[/script]
You need to do it a piece at a time instead, like this:

[script=powershell]$ie.Document | Get-Member
$ie.Document.Body | Get-Member[/script]
Aside from looking at:

[script=powershell]$ie.Document.Body.InnerHtml[/script]
you should also look at:

[script=powershell]$ie.Document.All | Format-Table TagName,Type,Name,Value[/script]
That will return a lot of information, but it identifies the elements that you can access on the page. the $ie.getElementsByTagName method will only give you back elements that appear in this list and that have a matching TagName value. If the elements you want are not there, then the issue is with the web page you’re referring to, not the script.

Looking at the web page content you provided, I just wrote this and it works as expected:

[script=powershell]$html = @'
<HTML>
<HEAD>
<BODY>
<P>
<H2>Please choose an action:
</H2>
<form action="/cgi-bin/ep_choose_app.pl" method="POST">
<INPUT TYPE="radio" NAME="action" VALUE="build">Submit Initial Build

<INPUT TYPE="radio" NAME="action" VALUE="rebuild">Submit Re-Build

<INPUT TYPE="radio" NAME="action" VALUE="appbuild">Submit Application Build

<INPUT TYPE="radio" NAME="action" VALUE="special">Submit Special Request

<INPUT TYPE="radio" NAME="action" VALUE="publogs">View Archive Logs


<INPUT TYPE="submit" VALUE="submit">
</P>
</BODY>
</HTML>
'@
$html | Out-File C:\test.html
$ie = New-Object -Com InternetExplorer.Application
$ie.Navigate('C:\test.html')
$ie.Visible = $true
$radioButton = $ie.Document.getElementsByTagName('INPUT') | Where-Object {($
.Type -eq 'radio') -and ($
.Name -eq 'action') -and ($
.Value -eq 'special')}
$radioButton.setActive()
$radioButton.click()[/script]

This should work for you as well. You should be able to see the web page with the radio button "clicked" after this is done. You’ll then have to get the submit button element and click it too to send your results through, but the radio button part works as expected.

Also, when you’re done with all of this, don’t forget to call:

[script=powershell]$ie.Quit()[/script]
Otherwise you’ll have iexplore processes remaining open on your system.
by xeen at 2012-09-01 11:48:17
When i back to work at monday i will try your’s tips.

UPDATE

I tried to use your scirpt, and this give me this output:
You cannot call a method on a null-valued expression.
At line:29 char:49
+ $radioButton = $ie.Document.getElementsByTagName <<<< (‘INPUT’) | Where-Object {($.Ty
pe -eq ‘radio’) -and ($.Name -eq ‘action’) -and ($.Value -eq ‘special’)}
+ CategoryInfo : InvalidOperation: (getElementsByTagName:String) [], Runti
meException
+ FullyQualifiedErrorId : InvokeMethodOnNull

Exception calling "setActive" with "0" argument(s): "The object invoked has disconnected
from its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))"
At line:30 char:23
+ $radioButton.setActive <<<< ()
+ CategoryInfo : NotSpecified: (:slight_smile: [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodCOMException

Exception calling "click" with "0" argument(s): "The object invoked has disconnected fro
m its clients. (Exception from HRESULT: 0x80010108 (RPC_E_DISCONNECTED))"
At line:31 char:19
+ $radioButton.click <<<< ()
+ CategoryInfo : NotSpecified: (:slight_smile: [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodCOMException


UPDATE 2

One new info - page is using a frames.
My friend help me to get one step forward, and i can choose an option on webpage by RadioButton. It is good.But after that, i can’t manage usage of Submit button. i many time check a source adn there are no frames ( or i am wrong).

Here is the code i am using:
$ie = New-Object -com "InternetExplorer.Application"
$ie.navigate("/portal/portal_choice.html")
$ie.visible = $true
Start-Sleep -s 3
$radioButton = $ie.Document.getElementsByTagName('input') | Where-Object {($.Type -eq 'radio') -and ($.Name -eq 'action') -and ($.Value -eq 'special')}
$radioButton.checked = $true
$submitButton = $ie.Document.getElementsByTagName('submit') | Where-Object {($.Type -eq 'submit') -and ($.Value -eq 'submit')}
$submitButton.SetActive()
$submitButton.Click()


When i move my mouse cursor on the buttone it shows this link: "/cgi-bin/ep_choose_ap.pl"
Is there any method to get information about frames used on page?

The source of proper wabpage looks like above, so there are not any additional informations aobut submit button. What to do in this case?

UPDATE 3.

Hi again. After this code i got following output:
$global:ie = New-Object -com internetexplorer.application
$global:ie.Navigate("about:blank")
$global:ie.visible = $true
NavigateTo("http://portal/portal_choice.html&quot;&#41;
$doc = $global:ie.document
$elements = $global:ie.Document.getElementsByTagName('input')
Write-Host $elements

and it is output:
System.__ComObject System.__ComObject System.__ComObject System.__ComObject System.__ComObject System.__ComObject

so, how can I call a concret number of ComObject, like 3 or 5?

UPDATE 4.

Aftersearching i have made somthing like this: Function ClickElementByTagName3($tagName, [int] $position = 3)
{
if ($global:doc -eq $null) {
Write-Error "Document is null"
break
}
$elements = @($global:doc.getElementsByTagName($tagName))
if ($elements.Count -ne 3) {
$elements[$position].Click()
WaitForPage
}
else {
Write-Error "Couldn't find element ""$tagName"" at position ""$position""";
break
}
}

Function ClickElementByTagName5($tagName, [int] $position = 5)
{
if ($global:doc -eq $null) {
Write-Error "Document is null"
break
}
$elements = @($global:doc.getElementsByTagName($tagName))
if ($elements.Count -ne 5) {
$elements[$position].Click()
WaitForPage
}
else {
Write-Error "Couldn't find element ""$tagName"" at position ""$position""";
break
}
}

$global:ie = New-Object -com internetexplorer.application
$global:ie.Navigate("about:blank")
$global:ie.visible = $true
NavigateTo("http://njrarlpsvr0012.njrar.us.ups.com:940/portal/portal_choice.html&quot;&#41;
$doc = $global:ie.document
ClickElementByTagName3('input')
ClickElementByTagName5('input')


And it is working, but i don’t know how. In function i need to change a place to call ( in eg. 3 and 5 ) so i need to made two functions. So, how to made this using one funcion?