I'm working on a powershell script that will create a printer on my Company Print Server, which is all done and working.
But we have however a location where we list all used IP's, which is a webpage.
So I'm trying to use Invoke-WebRequest to do this. Login to the page works but then when it tries to use the form to add the IP it doesn't.
Login only has one submit button in the form and to add the IP there is three buttons. I will list them in the order they are on the page
Clear the form
Apply
Cancel
So I'm thinking when I Invoke-Webrequest it is using the "clear form" function.
Is there any way I could specify which function to use when sending a webrequest?
I cant remove the "Clear form" button since it is being used frequently, just to get that clear.
$R = Invoke-WebRequest -URI http://localhost -SessionVariable IP
$Form = $R.Forms[0]
$Form.fields["ctlUsername"]=User
$Form.fields["ctlPassword"]=Pass
$R=Invoke-WebRequest -Uri ("http://localhost/" + $Form.Action) -WebSession
$IP -Method POST -Body $Form.Fields
$D = Invoke-WebRequest -URI http://localhost/addIP.php -WebSession $Test
$Form2 = $D.Forms[0]
$Form2.fields["IP"]="172.10.0.1"
$Form2.fields["name"]="Printer300"
$Form2.fields["location"]="Room407"
$Form2.fields["MAC"]="000"
$Form2.fields["ID"]="000"
Invoke-WebRequest -Uri http://localhost/addIP.php -WebSession $IP -Method POST -Body $Form2.Fields
Don't think in terms of "filling in web pages" when it comes to sending those requests. Web pages for a human user. Filling in a form and clicking a button is the manual way of creating an HTTP message with data.
When you post this form:
IP: [172.10.0.1 ]
Name: [Printer300 ]
Location: [Room407 ]
[Apply] [Cancel]
the browser creates a text string like this:
IP=172.10.0.1&Name=Printer300&Location=Room407
and sends it to the target URL.
Invoke-WebRequest can create this format directly from your data. This means, you don't need to "fill in" anything. Just pass a hashtable with the proper keys and values:
Invoke-WebRequest "http://localhost/addIP.php" -WebSession $IP -Method POST -Body #{
IP = "172.10.0.1"
Name = "Printer300"
Location = "Room407"
MAC = "000"
ID = "000"
}
Of course the keys must correspond to the form field names.
That being said, I don't see much of a need for authentication with requests coming from the localhost. You can save yourself some busywork by disabling authentication for all local requests, and requiring it only for remote requests.
Anyway, making a website request a password and then storing that password in clear text in a script is not exactly secure to begin with.
Invoke-WebRequest supports Windows integrated authentication, so that you don't have to bother with usernames and passwords at all. This would be my preferred authentication solution for such tasks.
Found the issue, it needed a hidden value that was not being sent via the form but was added in php function later.
Thanks for all your help.
Related
Website I am attempting to do this on: https://www.netvendor.net/login
I am trying to login to the website automatically and kick off a script to create users in bulk for us.
If you run an Invoke-WebRequest on this page, it returns information, but nothing about the forms. They are simply not displayed. However, if you view the page source or inspect element, there are clearly forms on the page and they are not composed of JS or anything else that would mess it up. How can I get PowerShell to recognize these fields? I am using the following command:
Invoke-WebRequest -Uri "www.netvendor.net/login" -Method GET -UseBasicParsing
Because of the issue above, I decided I would just POST the information I needed by examining the request. The request requires three things:
email
password
_token
Unfortunately, the token is randomly generated each time a browser session is initiated. If you view source on the page and search for "_token", you will get the parameter that is needed. It doesn't seem like there is any way to retrieve this from the page? I am a bit lost as to what I can do at this point, especially since there is no API or anything else for me to work with.
For all interested, here is the final working script:
$nvlogin = Invoke-WebRequest "https://www.netvendor.net/login" -SessionVariable "netvendor"
$nvtoken = $nvlogin.InputFields.Where({ $_.Name -eq "_token" })[0].Value
$nvbody = #{
"_token" = $nvtoken
"email" = "your.name#website.com"
"password" = 'credentials'
}
Invoke-WebRequest -Uri "https://www.netvendor.net/login" -WebSession $netvendor -Method 'POST' -Body $nvbody
Considering following code, which is part of a larger powershell script. When the scripts is triggered, a phone call is made by Twilio to 'To' with a text (in the XML $MessagURL) that is read with a TextToSpeech-Engine.
$params = #{ To = $XmlDocument.Response.Dial; From = $number; Url =
$MessageURL}
# Make API request, selecting JSON properties from response
Invoke-WebRequest -URI $url -Method Post -Credential $credential -Body
$params -UseBasicParsing
$MessageURL is an URL to an XML. The XML contains the data for the text that needs to be said when calling the numbeer 'To' (which comes from another XML).
When $MessageURL is to a private public webspace, everything works fine.
When i change the $MessageURL to a azure blob-location, then the Twilio-logic can't read/access the XML-file anymore. The XML on the blob-storage is also free accessable through the internet.
Anyone any ideas why the script has problems with calling an xml on an azure blob-storage?
I'm trying to download and save the text file http://www.gutenberg.org/cache/epub/164/pg164.txt using Powershell. I tried using the code:
$curl http://www.gutenberg.org/cache/epub/164/pg164.txt -OutFile verne.txt
But instead of saving the text file it saved the text file for the page source of http://www.gutenberg.org/ebooks/164?msg=welcome_stranger. I'm wondering if there's something wrong with my code or if I need to use another code.
It's a redirect. If you put the url in the browser you will get the same welcome stranger page. My guess is that they don't want you to access this content in this way. They may require log in, or at the very least, a valid session cookie.
Your link is a redirection, try this :
$uri = 'www.gutenberg.org/ebooks/164.txt.utf-8'
$request = Invoke-WebRequest -Uri $uri -MaximumRedirection 0 -ErrorAction Ignore
if($request.StatusDescription -eq 'found')
{
#redownload the new url (redirection)
$request=Invoke-WebRequest -Uri $request.Headers.Location
$request.ParsedHtml.body.outerText
}
When I provide this in PowerShell:
Invoke-RestMethod -Uri "https://outlook.office365.com/api/v1.0/users/andrew.stevens#mydomain.com/folders/"
-Credential $cred | foreach-object{$_.value |select DisplayName,ID}
I successfully determine Folder IDs, but not all folders are visible. How do I get a complete listing of folders (the one I particular want is recoverable items). I'm thinking once I get the ID I can see the messages the folder would contain?
Did you mean the Deleted Items folder?
If I understand correctly, it should be listed by the REST you calling. And we can use the well-known folder names: DeletedItems to get the messages. Here is an example for your reference:
Get: https://outlook.office.com/api/v2.0/me/MailFolders/DeletedItems/messages
Update
To use the Office 365 REST API, we need to use the bearer token which we need to register the app first. Below is an sample to get the access token via PowerShell for your reference(refer to Obtaining an Access Token):
#region Construct Azure Datamarket access_token
#Get ClientId and Client_Secret from https://datamarket.azure.com/developer/applications/
#Refer obtaining AccessToken (http://msdn.microsoft.com/en-us/library/hh454950.aspx)
$ClientID = '<Your Value Here From Registered Application>'
$client_Secret = ‘<Your Registered Application client_secret>'
# If ClientId or Client_Secret has special characters, UrlEncode before sending request
$clientIDEncoded = [System.Web.HttpUtility]::UrlEncode($ClientID)
$client_SecretEncoded = [System.Web.HttpUtility]::UrlEncode($client_Secret)
#Define uri for Azure Data Market
$Uri = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13"
#Define the body of the request
$Body = "grant_type=client_credentials&client_id=$clientIDEncoded&client_secret=$client_SecretEncoded&scope=http://api.microsofttranslator.com"
#Define the content type for the request
$ContentType = "application/x-www-form-urlencoded"
#Invoke REST method. This handles the deserialization of the JSON result. Less effort than invoke-webrequest
$admAuth=Invoke-RestMethod -Uri $Uri -Body $Body -ContentType $ContentType -Method Post
#Construct the header value with the access_token just recieved
$HeaderValue = "Bearer " + $admauth.access_token
#endregion
#region Construct and invoke REST request to Microsoft Translator Service
[string] $text = "Use pixels to express measurements for padding and margins.";
[string] $textEncoded = [System.Web.HttpUtility]::UrlEncode($text)
[string] $from = "en";
[string] $to = "de";
[string] $uri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + $text + "&from=" + $from + "&to=" + $to;
$result = Invoke-RestMethod -Uri $uri -Headers #{Authorization = $HeaderValue}
#endregion
$result.string.'#text'
After we get the access token, we can use the sample below to make the REST call:
$uri ="https://outlook.office.com/api/v2.0/me/MailFolders/DeletedItems/messages"
$accessToken=''
Invoke-RestMethod -Uri $uri -Headers #{Authorization=("bearer {0}" -f $accessToken)}
Links below are also helpful for you learning Office 365 REST API:
Manually register your app with Azure AD so it can access Office 365 APIs
Office 365 APIs platform overview
Thanks for the comment, and yes DeletedItems would be the folder name (for deleted items) but I discovered this..
https://msdn.microsoft.com/en-us/library/office/dn424760(v=exchg.150).aspx.
And from this you can do this..
Invoke-RestMethod -Uri "https://outlook.office365.com/api/v1.0/users/andrew.stevens#anydomain.com/folders/recoverableitemsdeletions/messages?
" -Credential $cred | foreach-object{$.value |select #{n='Sender';e={$.sender.emailaddress.name}},Subject,DateTimeReceived}
So this gets messages in the recovered deleted items container.
Question now is how do I move them to inbox?
//A
OK.. thanks for the information regarding app registration and OAuth. But just to see the recovered deleted items the method using v1.0 does actually work..
What I now need to understand (apologies for my lack of knowledge on this) is how to move messages from the folder located (recovered deleted items) to say the Inbox (or perhaps another folder of choice). Since I was able to use V1.0 (with no requirement for app registration) can I use the same version to do this?
Your answer you provided for sending email worked perfectly and that didnt require any app registration.. so this would be a POST of somekind..
All I have to go on is
1. POST https://outlook.office.com/api/v1.0/me/messages/{message_id}/move
2. {
"DestinationId": "AAMkAGI2NGVhZTVlLTI1OGMtNDI4My1iZmE5LTA5OGJiZGEzMTc0YQAuAAAAAADUuTJK1K9aTpCdqXop_4NaAQCd9nJ-tVysQos2hTfspaWRAAAAAAEJAAA="
}
Which is a folder ID
//A
I have a worksite that I am trying to "browse".
Done it with this...
$login = Invoke-WebRequest -Uri 'http://www.privateworksite.com' -SessionVariable GetIP
$form = $login.Forms[0]
$Form.Fields['ctl00$ContentPlaceHolder1$RadTextBox7']= "*******" <-- User ID goes here
$Form.Fields['ctl00$ContentPlaceHolder1$RadButton1'] = "submit" <-- Submit button
$afterfirstclick Invoke-WebRequest -Uri 'http://www.privateworksite.com' -WebSession $GetIP -Method POST -Body $form.Fields
Now that I am at the page I need to click on a new button that appears. I have tried to add a -sessionvariable $afterfirstclick but I get the dreaded PS Red lines stating that you cannot have -WebSession and -SessionVariable together.
ADDED INFO:
So how do I click on the button that is produced in $afterfirstclick? This is what I have for a button after the first click return.
ctl00$ContentPlaceHolder1$RadGrid1$ctl00$ctl04$GECBtnExpandColumn <-- a new button to create
a drop down table with the info I need. The table is not there prior to the
clicking the button so I need to click this button.
I have been all over and ever demo/post is about logging in to a site but after that how do you move around the site?
I have tried to feed $afterfirstclick into the -WebSession, bust...
Also tried to repeat the whole thing with the next Field to click the button and that just results in a new site not the "continuation" of the current.
Where to go from here?
Oh and the URL never changes so I cannot submit VIA URL.
Ok found the solution! I needed to feed $afterfirstclick into the next invoke-webrequest. I feel so stupid that it was not that obvious.
End result...
$url = "http://private.com" #<-- setup the URL
$tool = Invoke-WebRequest -Uri 'http://private.com' -UseDefaultCredentials -SessionVariable fb #<--create the site in a variable
write-host "1111111111111111" #<--just a marker to seperate the two requests so I can see the form.fields clearly
$Form = $tool.Forms[0] #<--first invoke form.fields
$Form.Fields #<--just printing them so I can see them
$Form.Fields['ctl00$ContentPlaceHolder1$RadTextBox7']= "USERID" #<--entering USERID into the form
$Form.Fields['ctl00$ContentPlaceHolder1$RadButton1'] = "submit" #<--clicking the submit button
$mainPage = Invoke-WebRequest ("$url" + $Form.Action) -WebSession $fb -Body $Form.Fields -Method Post #<--create the new page by calling the page with the fields
$mainPage.RawContent | out-file h:\response.html #<--sending it to a file so I can see the first page and second page side by side
write-host "2222222222222222" #<--just a marker to seperate the two requests so I can see the form.fields clearly
$Form2 = $mainPage.Forms[0] #<--pulling the new page form.fields NOTICE I am using the previous variable for the first invoke
$Form2.Fields #<--printing fields to take a look at what needs to be included in the next round
$Form2.Fields['ctl00$ContentPlaceHolder1$RadGrid1$ctl00$ctl04$GECBtnExpandColumn'] = "submit" #<--The newly generated button that needed to be clicked to continue
$mainPage2 = Invoke-WebRequest ("$url" + $Form2.Action) -WebSession $fb -Body $Form2.Fields -Method Post -UseDefaultCredentials #<--OK BIG ONE!! First the form.field needs to be correct as well as using the original -websession!!!
$mainPage2.RawContent | out-file h:\response1.html #<--output the second resulting page to compare
You have to watch that second request. It must use the first invoke to create new form.fields but still use the original -websession variable.
No idea why but this works this way, but I used this for another site to go deep into it so it is solid, just keep repeating the chain. You could even use a foreach loop with all the known form.fields.