11
<div class="w-btn" ng-click="vm.callbacks.compareAll();" ng-if="vm.folderData.projects.length > 0 &amp;&amp; vm.noneSelectedProjects" tabindex="0"><i class="glyphicon glyphicon-transfer btn-icon"></i> Report from all</div>

I need to use Powershell to click that button. There are multiple div's on that page with the class="w-btn" but only one with the ng-click that has Compare all in it.

when that button is clicked it will change another tag on the page which is like the following

<a href="/data/project/export/projects-tasks?projectIds[]=103473&amp;projectIds[]=103474&amp;projectIds[]=106186&amp;projectIds[]=108395&amp;projectIds[]=110653&amp;projectIds[]=110657" target="_self" class="inline-btn pull-right" ng-if="vm.projects.length > 0">

the first button changes that href for the projects as they get added. I have to write this script to click the first button and then use the resultant href as part of a link in my wget

so far I haven't been able to get anything to work

$Link = 'https://url.com/folder/2880'
$html = Invoke-WebRequest -Uri $Link -UseDefaultCredentials
$btnclick = $html.getElementsByTagName("div") | Where-object{$_.Name -like 'ng-click="vm.callbacks.compareAll();"' }

when I then do a write to console to see what $btnclick is I get an error:

Method invocation failed because [Microsoft.PowerShell.Commands.HtmlWebResponseObject] does not contain a method named 'getElementsByTagName'

eventually, I think I would then do like $btnclick.Click() and do another getElement on the href so I can pull the

/data/project/export/projects-tasks?projectIds[]=103473&amp;projectIds[]=103474&amp;projectIds[]=106186&amp;projectIds[]=108395&amp;projectIds[]=110653&amp;projectIds[]=110657

portion out.

Any help getting this done is appreciated. The high-level overview is I need to click an angular js button from a webpage and then extract a piece of a URL to use in a wget from the resulting a href tag.

1
  • 1
    Have you tried $html.ParsedHtml.getElementsByTagName('div') |where name -like '…'? Invoke-WebRequest's Microsoft.PowerShell.Commands.HtmlWebResponseObject uses IE to headlessly render the DOM unless you add -UseBasicParsing, and the objects returned do seem to have a click() method. Commented Mar 14, 2018 at 17:55

2 Answers 2

7
+25

Invoke-WebRequest in AngularJS webpages is useless, since there is client side javascript rendering. You can use combination of powershell + selenium + protractor for that (Powershell v5 required):

# initialize selenium
$protractorPackage = Install-Package Protractor -Destination ".\NugetPackages" -Force -Source 'https://www.nuget.org/api/v2' -ProviderName NuGet
Add-Type -Path ".\Selenium.WebDriver.$($protractorPackage.Where({$_.name -eq "Selenium.WebDriver"}).version)\lib\net40\WebDriver.dll"
Add-Type -Path ".\Protractor.$($protractorPackage.Where({$_.name -eq "Protractor"}).version)\lib\net40\Protractor.dll"

# initialize chrome driver
$chromeDriverPackage = Install-Package Selenium.WebDriver.ChromeDriver -Destination "." -Force -Source 'https://www.nuget.org/api/v2' -ProviderName NuGet
$Env:Path += ";" + ((Resolve-Path ".\Selenium.WebDriver.ChromeDriver.$($chromeDriverPackage.Version)\driver\win32") -join ";")
$Selenium = New-Object OpenQA.Selenium.Chrome.ChromeDriver

# interact with website
$Selenium.Manage().Timeouts().SetScriptTimeout([TimeSpan]::FromSeconds(15)) # Configure timeouts (important since Protractor uses asynchronous client side scripts)
$Protractor = New-Object Protractor.NgWebDriver($Selenium)
try
{
    $Protractor.Url = "https://url.com/folder/2880"
    $Protractor.WaitForAngular() # sync with angular, this waits for all elements to load

    $Protractor.FindElement([OpenQA.Selenium.By]::CssSelector('[ng-click="vm.callbacks.compareAll();"]')).Click();

    Write-Host "Url is: $($Protractor.Url)"
    $FullhtmlDOM = $Protractor.PageSource
    Write-Host "Full page source: $FullhtmlDOM"
}
finally
{
    $Protractor.Dispose()
}

if you don't want to depend on Chrome browser, you can use headless PhantomJS instead. It will work the same way, you just download different packages:

...
# initialize phantomjs driver
$phantomJsDriverPackage = Install-Package Selenium.WebDriver.PhantomJS -Destination "." -Force -Source 'https://www.nuget.org/api/v2' -ProviderName NuGet
$Env:Path += ";" + ((Resolve-Path ".\Selenium.WebDriver.PhantomJS.$($phantomJsDriverPackage.Version)\driver") -join ";")
$Selenium = New-Object OpenQA.Selenium.PhantomJS.PhantomJSDriver
...
Sign up to request clarification or add additional context in comments.

3 Comments

Worth mentioning the NuGet source isn't defined by default, so if Install-Package throws an error, try adding the parameters -Source 'https://www.nuget.org/api/v2' -ProviderName NuGet
Thanks for the example, I just modify the installation part because Protractor nuget install brings also Selenium.WebDriver.
Invoke-WebRequest's Microsoft.PowerShell.Commands.HtmlWebResponseObject uses IE to headlessly render the DOM unless you add -UseBasicParsing.
1

If your fine with IE It appears creating an IE COM object will get what you want.

$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Navigate("URL GOES HERE")
$Document = $ie.document
$Document.GetElementsByTagName('div')

If you want it visible:

$ie.visible = $True

Here is the Microsoft page on the COM Object

https://msdn.microsoft.com/en-us/library/aa752084(v=vs.85).aspx

And one on using it in powershell.

https://blogs.msdn.microsoft.com/luisdem/2016/02/09/browsing-in-internet-explorer-via-powershell/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.