Powershell to automate IE | fill Paiement form issue - powershell

I'm just starting to use powershell scripts.
I am trying to automate a payment process (for personal use).
But when I enter my payment information via my script the information is not saved on the page (the data acts as a placeholder)
I tried to use a "focus()" before entering the values but it doesn't work :(
(maybe a bad use ?)
I had the idea to simulate an "ENTER" key press after entering my values but I feel like I'm misusing the syntax
Here is an example of my code:
$cardnumber = "4000 1000 2000 0000"
$nameoncard = "Alban Mysteriousguy"
$expirationdate = "10/77"
$ccv = "420"
$ie = New-Object -COMObject InternetExplorer.Application
$ie.visible = $true
$ie.Navigate(‘https://secure2.ldlc.com/fr-fr/DeliveryPayment’)
#Achat CB
while ($ie.Busy -eq $true) { Start-Sleep -Seconds 1; } #wait for browser idle
#notworking
$Carednumbervar = $ie.document.getElementsByName("CardNumber")
($Carednumbervar |Select-Object -first 1).value = $cardnumber;
#working
($ie.document.getElementsByName("OwnerName") |Select-Object -first 1).value = $nameoncard;
#notworking
($ie.document.getElementsByName("ExpirationDate") |Select-Object -first 1).value = $expirationdate;
#notworking
($ie.document.getElementsByName("Cryptogram") |Select-Object -first 1).value = $ccv;
#working
$payementButton = $ie.Document.getElementsByTagName('button') | Where-Object { ($_.ClassName -ceq 'button color2 maxi') }
$CGV = $ie.Document.getElementsByTagName('label') | Where-Object { ($_.for -ceq 'terms') }
$CGV.click
#$payementButton.click()
If anyone have an idea about how can I solve this issue or just a trick that I can try, you are welcome :)
Thanks by advance
PS: To test the script you need to create an account to Ldlc.com, add something in your cart and go to the payment page ( https://secure2.ldlc.com/fr-fr/DeliveryPayment for exemple) if needed I can upload a video of the behavior.
Edit: Here I made a youtube video to show my issue : youtu.be/pTbSWU_cudY

Thank you for the detailed code. I extracted the relevant html code and performed a simple test. I found that it works correctly. You need to cancel Enable Protected Mode in IE.
Open IE -> Tools -> Internet Options -> security tab -> uncheck option Enanle Protected Mode and apply
Something like this:

Related

Remove Com+ Application using powershell

Im currently in the process of automating an install process for a custom windows application and trying to remove a couple of the com+ applications including everything below it.
Obviously this can be done manually with a right click and delete but I need something to streamline this process and I can add powershell to my automation process.
I have tried the below code but it only seems to remove the components with in the application. While this helps I would then need to remove the application in another step.
$comCatalog = New-Object -ComObject COMAdmin.COMAdminCatalog
$appColl = $comCatalog.GetCollection("Applications")
$appColl.Populate()
$app = $appColl | where {$_.Name -eq "ApplicationName"}
$compColl = $appColl.GetCollection("Components", $app.Key)
$compColl.Populate()
$index = 0
foreach($component in $compColl) {
if ($component.Name -eq "SOMECOMPONENT.NAME") {
$compColl.Remove($index)
$compColl.SaveChanges()
}
$index++
}
I would expected to be able to remove the application and have everything below also removed.
$comCatalog = New-Object -ComObject COMAdmin.COMAdminCatalog
$appColl = $comCatalog.GetCollection("Applications")
$appColl.Populate()
for ($i=0; $i -lt $appColl.Count; $i++)
{
if ($appColl.Item($i).Name -eq "YourComponentName"){ $appColl.Remove($i) $appColl.SaveChanges() }}

net files /close does not work as expected

We have many self-written applications which are executed in a network location. Whenever a developer wants to publish a new version of this application, I have to close all opened files on the server where the app is located, by going to:
computer management > Shared Folders > Opened Files
then choose all the files of the application - right click and close.
I want the developers to do that by themselves via PowerShell, so I wrote a Unlock-Files function. This part of the function should close the files, with the net files $id /close call:
$result = Invoke-Command -ComputerName $server -Credential $cred -ArgumentList $workpath, $server {
param($workpath,$server)
$list = New-Object System.Collections.ArrayList
$ErrorActionPreference = "SilentlyContinue"
$adsi = [adsi]"WinNT://./LanmanServer"
$resources = $adsi.psbase.Invoke("resources") | % {
[PSCustomObject] #{
ID = $_.gettype().invokeMember("Name","GetProperty",$null,$_,$null)
Path = $_.gettype().invokeMember("Path","GetProperty",$null,$_,$null)
OpenedBy = $_.gettype().invokeMember("User","GetProperty",$null,$_,$null)
LockCount = $_.gettype().invokeMember("LockCount","GetProperty",$null,$_,$null)
}
}
$resources | ? { $_.Path -like $workpath } | tee -Variable Count | % {
$id = $_.ID
net files $id /close > $null
if ($LASTEXITCODE -eq 0) { $list.add("File successfully unlocked $($_.path)") > $null }
else { $list.add("File not unlocked (maybe still open somewhere): $($_.path)") > $null }
}
if (!( ($count.count) -ge 1 )) { $list.add("No Files to unlock found in $workpath on $server") > $null }
$list
}
I expect net files /close to behave the same way as the manual way I do directly on the server described above, but it doesn't behave like this at all. It sometimes closes the file, sometimes not. But it never closes all the necessary files, so the developer can not publish his application. also, net files almost never finishes with LastExitCode 0, but I can't get my head around why.
Is there a way to force net files to really close all the files?
why would net files behave different than closing the files manually?
Is there a native PowerShell way to do this?
Is there a list of last exit codes, so I can wrap my head around this issue further?
Thank you!

Manipulating a CSV with Powershell

At the moment I am working on a script to automate a process in IE to add Computer Names and their MACs so we can image them. The page has two fields one for MAC and one for a computer name then a add new button. I had to come to a pretty sloppy solution for avoiding a popup from the page by just quitting out of the com object after submitting.
I don't have much experience with Powershell yet and none with working with CSVs so I'm having a bit of trouble making this work. My goal is to have the script read two entries from a row fill out the correct field then submit it then move to the next row and repeat.
Right now what it does is fills out the fields with undefined in both fields, then submits and repeats.
EDIT: I have edited my code slightly just so it confirms what is trying to read.This is what the results look like. I believe #WalterMitty is on to something that something is wrong with $ie.document.getElementsByName lines, I just tried $ie.document.getElementById but that didn't fill out any fields. It seems it has no problem reading the CSV, but it does have a problem entering the information it reads into the fields properly.
This is an example of what the CSV would look like.
NewComputerName,NewMACAddress
ComputerName1,111122223333
ComputerName2,112233446677
ComputerName3,AAAABBBBCCCC
ComputerName4,AABBCCDDEEFF
This is what my code currently looks like.
cls
$URL = ""
$iterator = 1;
$csv = Get-Content C:\example1.csv
foreach($row in $csv)
{
#starts IE
$ie = new-object -ComObject "InternetExplorer.Application"
$ie.visible = $true
$ie.navigate($URL)
while($ie.Busy -eq $true) { start-sleep -Milliseconds 100 }
($ie.document.getElementsByName("mc_id") |select -first 1).value = $_.NewComputerName;
($ie.document.getElementsByName("mac_id") |select -first 1).value = $_.NewMACAddress;
$ie.document.forms | Select -First 1| % { $_.submit() };
$ie.quit()
$iterator++
write-host "$iterator new ID(s) added"
write-host $row.NewComputerName - $row.NewMACAddress
}
$URL = ""
$iterator = 1
# use Import-Csv for CSV files
$csv = Import-Csv "C:\example1.csv" -Delimiter ","
foreach($row in $csv) {
Write-Host "$iterator new ID(s) added"
#starts IE
$ie = New-Object -ComObject "InternetExplorer.Application"
$ie.Visible = $true
$ie.Navigate($URL)
while ($ie.Busy -eq $true) { Start-Sleep -Milliseconds 100 }
# $_ is not defined in foreach blocks, you have to use $row here
($ie.Document.getElementsByName("mc_id") | Select-Object -First 1).Value = $row.NewComputerName
($ie.Document.getElementsByName("mac_id") | Select-Object -First 1).Value = $row.NewMACAddress
$ie.Document.Forms | Select-Object -First 1 | ForEach-Object { $_.submit() }
$ie.Quit()
$iterator++
}
I'm having similar issues but I just found this may help you guys - I don't have 50 reputation to comment sorry :/....
I messed around with the -Path of the Import-CSV command but I just couldn’t make it work. Apparently this has nothing to do with the path of the CSV file. The Warlock posted this on his blog:
Long story short, the error came from having trailing blank columns in
my CSV. Import-Csv uses the first row in the CSV as names for the
columns (unless you specify otherwise) and when you have blank columns
(or at least multiple blank columns) it causes this error as it
doesn’t have a valid name for them.
Instead of changing the file, I changed my import command to include the headers as per Dale's comment and it worked perfectly:
$data = import-csv "C:\Sharepoint.csv" -header("Department","AD Group","Members","Notes")
The Warlock and Dale saved me lots of time, please stop by the Warlock’s blog and give them a big Thanks
Consider using Import-Csv and Invoke-WebRequest in combination, e.g. like this:
import-csv .\example.csv | %{ iwr http://someurl.local -body #{mc_id=$_.NewComputerName; mac_id=$_.NewMACAddress} -Method POST }
It will read the csv file, iterate over the records and create a application/x-www-form-urlencoded POST request with the values from each record.
When you use iwr (Invoke-WebRequest) and pass a hash table as the "body" it will act as if it is a form being submitted. The POST method will submit the form values as application/x-www-form-urlencode. Without the POST method it would submit the form as if it was a GET, i.e. pass the values in the url.
If you need authentication, session support etc. then read the documentation for Invoke-WebRequest.
Using IE to automate web requests is brittle and error prone.

Set audience on specific node in SharePoint quick launch with powershell

I'm using a script for setting an audience group for a navigation node in SharePoint. When I set the group It's no problem, or it sets the group but the settings is never pushed through. But If I edit the node in the GUI and just press OK (on both the node settings and navigation settings) the changes goes through.
Script:
$FindString = "Custom link"
Get-SPSite "http://dev:18792/sites/devsite/" | Get-SPWeb -Limit ALL | ForEach-Object {
$web = $_
$_.Navigation.QuickLaunch | ForEach-Object {
$_.Children | ForEach-Object {
if($_.title -eq $FindString){
$node = $_
$node.Properties["Audience"] = "Custom group"
$node.Update()
}
}
}
$web.Update()
}
Am I using the Updates in the wrong place?
EDIT: "SharePoint Server Publishing Infrastructure" feature is activated on the site collection.
Solved it by adding ;;;; before the group name.
$node.Properties["Audience"] = ";;;;Custom group"

How to pin to start menu using PowerShell

I can pin some programs to taskbar on Win7 using PowerShell.
$shell = new-object -com "Shell.Application"
$folder = $shell.Namespace('C:\Windows')
$item = $folder.Parsename('notepad.exe')
$verb = $item.Verbs() | ? {$_.Name -eq 'Pin to Tas&kbar'}
if ($verb) {$verb.DoIt()}
How do I modify the above code to pin a program to the Start menu?
Another way
$sa = new-object -c shell.application
$pn = $sa.namespace($env:windir).parsename('notepad.exe')
$pn.invokeverb('startpin')
Or unpin
$pn.invokeverb('startunpin')
Use the code below
$shell = new-object -com "Shell.Application"
$folder = $shell.Namespace('C:\Windows')
$item = $folder.Parsename('notepad.exe')
$verb = $item.Verbs() | ? {$_.Name -eq 'Pin to Start Men&u'}
if ($verb) {$verb.DoIt()}
Note: the change is in the fourth line.
The main problem with most of the solution is that they enumerate the verbs on a file, search for the string to perform the action (“Pin to Startmenu” etc.) and then execute it. This does not work if you need to support 30+ languages in your company, except you use external function to search for the localized command (see answer from shtako-verflow).
The answer from Steven Penny is the first that is language neutral and does not need any external code. It uses the verbs stored in the registry HKEY_CLASSES_ROOT\CLSID\{90AA3A4E-1CBA-4233-B8BB-535773D48449} and HKEY_CLASSES_ROOT\CLSID\{a2a9545d-a0c2-42b4-9708-a0b2badd77c8}
Based on this, here’s the code we are now using:
function PinToTaskbar {
param([Parameter(Mandatory=$true)][string]$FilePath)
ExecuteVerb $FilePath "taskbarpin"
}
function UnpinFromTaskbar {
param([Parameter(Mandatory=$true)][string]$FilePath)
ExecuteVerb $FilePath "taskbarunpin"
}
function PinToStartmenu {
param([Parameter(Mandatory=$true)][string]$FilePath)
ExecuteVerb $FilePath "startpin"
}
function UnpinFromStartmenu {
param([Parameter(Mandatory=$true)][string]$FilePath)
ExecuteVerb $FilePath "startunpin"
}
function ExecuteVerb {
param(
[Parameter(Mandatory=$true)][string]$File,
[Parameter(Mandatory=$true)][string]$Verb
)
$path = [System.Environment]::ExpandEnvironmentVariables($File)
$basePath = split-path $path -parent #retrieve only the path File=C:\Windows\notepad.exe -> C:\Windows
$targetFile = split-path $path -leaf #retrieve only the file File=C:\Windows\notepad.exe -> notepad.exe
$shell = new-object -com "Shell.Application"
$folder = $shell.Namespace($basePath)
if ($folder)
{
$item = $folder.Parsename($targetFile)
if ($item)
{
$item.invokeverb($Verb)
# "This method does not return a value." (http://msdn.microsoft.com/en-us/library/windows/desktop/bb787816%28v=vs.85%29.aspx)
# Therefore we have no chance to know if this was successful...
write-host "Method [$Verb] executed for [$path]"
}
else
{
write-host "Target file [$targetFile] not found, aborting"
}
}
else
{
write-host "Folder [$basePath] not found, aborting"
}
}
#PinToTaskbar "%WINDIR%\notepad.exe"
#UnpinFromTaskbar "%WINDIR%\notepad.exe"
PinToStartmenu "%WINDIR%\notepad.exe"
#UnpinFromStartmenu "%WINDIR%\notepad.exe"
See the script (international) here : http://gallery.technet.microsoft.com/scriptcenter/b66434f1-4b3f-4a94-8dc3-e406eb30b750
If you want to add an action like Pin to Modern UI interface (Windows 8), at $verbs, add 51201
Steven Penny's second answer above worked well for me. Here are a couple more tidbits.
It's doing COM through PowerShell, so you can do the same thing with pretty much any COM client. For example, here's an AutoHotkey version.
Shell := ComObjCreate("Shell.Application")
Target := Shell.Namespace(EnvGet("WinDir")).ParseName("Notepad.exe")
Target.InvokeVerb("startpin")
VBScript or InnoSetup would look almost the same except for the function used to create the object.
I also found that I have one program that pinned OK, but didn't have the right icon and/or description because of limitations in the compiler. I just made a little 1-line WinForms app that starts the target with Process.Start, and then added the appropriate icon, and the name I wanted in the Start Menu in the Title property in AppInfo.cs.