Problem to connect to TFS with user/password - rest

When I try to connect to tfs the function Get-Data failed with 401 error although the function Get-DataWithCred succeed with the same argument.
And don't understand the difference with this two ?
function Get-Data([string]$username, [string]$password, [string]$url)
{
# Step 1. Create a username:password pair
$credPair = "$($username):$($password)"
# Step 2. Encode the pair to Base64 string
$encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair))
# Step 3. Form the header and add the Authorization attribute to it
$headers = #{ Authorization = "Basic $encodedCredentials" }
# Step 4. Make the GET request
$responseData = Invoke-WebRequest -Uri $url -Method Get -Headers $headers
return $responseData
}
function Get-DataWithCred([string]$username, [string]$password, [string]$url)
{
$p = ConvertTo-SecureString -String $password -AsPlainText -Force
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $p
$responseData = Invoke-WebRequest -Uri $url -Method Get -Credential $Cred
return $responseData
}
The purpose is too connect through tfs with python script who failed the same way that the function Get-Data when I use the requests library.
>>> r = requests.get('https://tfs-url.com', auth=('user', 'pass'))
>>> r.status_code
401

Looks like there is a problem with $encodedCredentials.
Take a look at Choosing the right authentication mechanism
For my script who connect to TFS i use the following code :
$strUser = 'domain\userID'
$password = "YOURPASSWORD"
$strPass = ConvertTo-SecureString -String $password -AsPlainText -Force
$cred= New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($strUser, $strPass)
And than connect to the TFS as you did :
$responseData = Invoke-WebRequest -Uri $url -Method Get -Credential $cred
Or, If you would like to connect to the TFS with the user who runs the script you can use
-UseDefaultCredentials
code snippet :
$responseData = Invoke-WebRequest -Uri $url -Method Get -UseDefaultCredentials

You need to use a microsoft way to pass your credential : the ntlm protocol.
This protocol are not supported by default by requests but a library requests_ntlm extend requests by adding support to ntlm.
A simple example:
import os
import requests
from requests_ntlm import HttpNtlmAuth
def main():
user = "user"
password = "password"
session = requests.Session()
session.auth = HttpNtlmAuth(user, password)
url = "https://tfs-url.com"
response = session.get(url)
print(response)
if __name__ == "__main__":
main()

Related

How can I download a folder from a webserver with authentication?

I need a script that downloads a certain folder and all its subfolders + files to my pc from a webserver. It needs to be in powershell. I searched a bit and found this:
Invoke-WebRequest http://www.example.com/package.zip -OutFile package.zip
I get this error when I try to run it. But I can't figure out how I can pass the username and password with it. If anyone can help me that would be greatly appreciated! Also how can I specify the folder it should be saved to? Thanks in advance
Following up regarding my comment.
I ask that question because some sites require you to be specific in the credential presentation vs just one blob of stuff. For example:
$credentials = Get-Credential
$webServerUrl = 'http://SomeWebSite'
$r = Invoke-WebRequest $webServerUrl -SessionVariable my_session
$form = $r.Forms[0]
$form.fields['Username'] = $credentials.GetNetworkCredential().UserName
$form.fields['Password'] = $credentials.GetNetworkCredential().Password
$InvokeWebRequestSplat = #{
Uri = $($webServerUrl + $form.Action)
WebSession = $my_session
Method = 'GET '
Body = $form.Fields
}
$r = Invoke-WebRequest #InvokeWebRequestSplat
Update
The follow-up to the comment. This is using IE with PowerShell for site automation.
# Scrape the site to find form data
$url = 'https://pwpush.com'
($FormElements = Invoke-WebRequest -Uri $url -SessionVariable fe)
($Form = $FormElements.Forms[0]) | Format-List -Force
$Form | Get-Member
$Form.Fields
# Use the info on the site
$IE = New-Object -ComObject "InternetExplorer.Application"
$FormElementsequestURI = "https://pwpush.com"
$Password = "password_payload"
$SubmitButton = "submit"
$IE.Visible = $true
$IE.Silent = $true
$IE.Navigate($FormElementsequestURI)
While ($IE.Busy) {
Start-Sleep -Milliseconds 100
}
$Doc = $IE.Document
$Doc.getElementsByTagName("input") | ForEach-Object {
if ($_.id -ne $null){
if ($_.id.contains($SubmitButton)) {$SubmitButton = $_}
if ($_.id.contains($Password)) {$Password = $_}
}
}
$Password.value = "1234"
$SubmitButton.click()
Invoke-WebRequest is Powershell's version of curl. Its alias is even named curl.
SO, in the IVR use case, all you really need to do something like the Facebook and Linkedin examples:
$cred = Get-Credential
$login = Invoke-WebRequest 'facebook.com/login.php' -SessionVariable 'fb'
$login.Forms[0].Fields.email = $cred.UserName
$login.Forms[0].Fields.pass = $cred.GetNetworkCredential().Password
$mainPage = Invoke-WebRequest $login.Forms[0].Action -WebSession $fb -Body $login -Method Post
$cred = Get-Credential
$login = Invoke-WebRequest 'https://www.linkedin.com/uas/login?goback=&trk=hb_signin' -SessionVariable 'li'
$login.Forms[0].Fields.email = $cred.UserName
$login.Forms[0].Fields.pass = $cred.GetNetworkCredential().Password
$mainPage = Invoke-WebRequest $login.Forms[0].Action -WebSession $LI -Body $login -Method Post
Yet, notice I on the FB/LI login page, and I'd need to know that even existed before trying this. Note this is old code, That I've not used in a very long while and I don't have a FB account. I passed this on to someone who did.
$cred = Get-Credential
Invoke-WebRequest http://www.example.com/package.zip -OutFile package.zip -Credential $cred

Powershell WebRequest GET Succeeds but DELETE fails w/ 404

Very confused on this issue. Here is what I am dealing with currently.
I have an API endpoint which looks like this /subscriptions/:id. This endpoint serves as both a GET & a DELETE endpoint. When I run a GET, it returns the object as it normally does, but changing the action to a DELETE gives me back a 404 for the very same resource which was just returned in the GET, I don't know why.
Here is my Powershell code.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$user = '*********'
$pass = ConvertTo-SecureString '*********' -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
$base = "https://*********.hosted.xmatters.com/api/xm/1"
$del_path = "$base/subscriptions/********uuid***********"
$path = "$base/subscriptions"
$payload = #{
id = '********uuid***********'
description = '**** NEW DESCRIPTION ****'
}
$params = $payload | ConvertTo-Json
// **** SUCCESS
$thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method GET
// **** FAILS
$thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method DELETE
// **** FAILS
$thing = Invoke-WebRequest -Credential $cred -Uri $path -Method POST -Body $params -ContentType 'application/json'
So, like mentioned previously, I am POSITIVE that the resource exists from the API. I am able to get it when running a GET but both POST (to update) & DELETE throw 404 errors. Here is the error I get.
Invoke-WebRequest : The remote server returned an error: (404) Not Found.
At \\mmfile\ct32373$\Appsense\Desktop\Line of Business Revisions.ps1:24 char:10
+ $thing = Invoke-WebRequest -Credential $cred -Uri $del_path -Method D ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebReque
st) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Comman
ds.InvokeWebRequestCommand
The strange thing is that I am able to run the DELETE request successfully using POSTMAN, however because of the volume of data I need to process, this is not a good option

How to attach CSV file to Service Now incident via REST API using PowerShell?

I need to attach the file either xlsx or CSV to a particular incident via SNOW REST API using PowerShell script. I have tried with the below code:
if (!$script:ServiceNowCreds) {
$script:ServiceNowCreds = Get-Credential
}
$snow_url = 'https://dev652xx.service-now.com/api/now/table/incident'
$Body = #{
'number' = 'INC00xx059'
}
$result = Invoke-RestMethod -Uri $snow_url -Credential $script:ServiceNowCreds -Body $Body -ContentType "application/json"
$result.result | select sys_id, number | ForEach-Object {
$Upload_snow_url ='https://dev652xx.servicenow.com/api/now/attachment/upload'
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Content-Type','text/csv')
$headers.Add('Accept','*/*')
$sys_id = $_.sys_id
$incident_number = $_.number
$UploadBody = #{
'table_name'='incident';
'table_sys_id'=$sys_id;
'file_name' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
$uploadParam = $UploadBody | ConvertTo-JSon
Write-Host $sys_id
Write-Host $incident_number
$UploadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $script:ServiceNowCreds -Body $uploadParam -Method Post -Headers $headers
$UploadResult
}
When I execute the above script I am getting the below error:
Invoke-RestMethod : The remote server returned an error: (415) Unsupported
Media Type.
At C:\Users\suganthanraj.p\Desktop\SNOW-UploadAttachment.ps1:39 char:21
+ ... oadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $scr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Try changing you content type to "multipart/form-data"
$headers.Add('Content-Type','multipart/form-data')
$UploadBody = #{
'table_name'='incident';
'record_sys_id'=$sys_id;
'uploadFile' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
The error says "The remote server returned an error: (415) Unsupported
Media Type."
Doco on the api can be found here:
https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/integrate/inbound_rest/reference/r_AttachmentAPI-POSTmultipart.html
Your best option would be leverage the OOB Attachment API in ServiceNow. You will need to make a post call from powershell. Powershell has two options for this Invoke-RestMethod and Invoke-WebRequest. I have had better luck with the latter when trying to POST. You might also first build your rest call in Postman make sure you can get the attachment into ServiceNow, then worry about writing your PS.
$Body = #{
User = 'jdoe'
password = 'P#S$w0rd!'
}
$LoginResponse = Invoke-WebRequest 'http://www.contoso.com/login/' - SessionVariable 'Session' -Body $Body -Method 'POST'
$Session
$ProfileResponse = Invoke-WebRequest 'http://www.contoso.com/profile/' -`WebSession $Session $ProfileResponse`
Finally i found answer from the below link
https://community.servicenow.com/community?id=community_question&sys_id=d3707023dbaceb8023f4a345ca961949 and below is the code:
# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "XXX"
# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))
# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')
# Specify endpoint uri
$uri = "https://dev652XX.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=850XXXXX2200e0ef563dbb9a71c1&file_name=TreeSizeReport.csv"
# Specifiy file to attach
$fileToAttach = "C:\Users\suganthanraj.p\Desktop\TreeSizeReport.csv"
# Specify HTTP method (POST, PATCH, PUT)
$method = "POST"
# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -InFile $fileToAttach
# Print response
$response.RawContent

Invoke-RestMethod and Fiddler, can't get 200 code in return

I am trying to replicate a POST call that can be send from GUI using Invoke-RestMethod. I would like to automate it and have been trying to use powershell to do it.
It alwasy returns 202 code, have been trying it for a few hours now but can't progress. This is really the first time I am playing with invoke-restmedod and Rest so please be detailed what's wrong. Any help is highly appreciated.
So the successful call captured by Fiddler is this:
The powershell code is:
$WfManDirUserPass = "Password"
$secpasswd = ConvertTo-SecureString $WfManDirUserPass -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("admin", $secpasswd)
$active = #{
ipaddress="192.168.100.116"
Port="62805"
status="0"
}
$json = $active | ConvertTo-Json
try{
$response = invoke-restmethod -uri https://myhost/MAM/wfservice/workers/?ip="&"port="&"newStatus=Deactivating -Method POST -Body $json -Credential $cred -ContentType 'application/json'
} catch {
write-host("Sorry, it does not work")
}
This powershell code in Fiddler returns:
I can see that the JSON is not exactly the same on the attached images. However I stuck now and would really appreciate some help now.
This is a reply from 1RedOne (Reddit) user that helped me out:
For one, let's wrap your whole -URI in single quotes and remove the double quotes. Your URL is probably messed up, which isn't helping things.
$uri = 'https://myhost/MAM/wfservice/workers/?ip=&port=&newStatus=Deactivating'
$response = invoke-restmethod -uri $uri-Method POST -Body $json -Credential $cred -ContentType 'application/json'
2.
Furthermore, your call from fiddler uses basic authentication, and is probably incompatible with using a -Credential object. Try replacing your credentials with this format.
$user = "yourusername"
$pass = 'yourPassWord'
# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))
# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
Then, reference the $header object within your Invoke-RestMethod, like so.
$response = invoke-restmethod -uri $uri- Method POST `
-Body $json -Header $headers -ContentType 'application/json'
That's it. It worked like a charm!

Invoke-WebRequest equivalent in PowerShell v2

Can some one help me with the powershell v2 version of the below cmdlet.
$body =
"<wInput>
<uInputValues>
<uInputEntry value='$arg' key='stringArgument'/>
</uInputValues>
<eDateAndTime></eDateAndTime>
<comments></comments>
</wInput>"
$password = ConvertTo-SecureString $wpassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($wusername, $password)
$output = Invoke-WebRequest -Uri $URI1 -Credential $credential -Method Post -ContentType application/xml -Body $body
$URI1 = "<your uri>"
$password = ConvertTo-SecureString $wpassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($wusername, $password)
$request = [System.Net.WebRequest]::Create($URI1)
$request.ContentType = "application/xml"
$request.Method = "POST"
$request.Credentials = $credential
# $request | Get-Member for a list of methods and properties
try
{
$requestStream = $request.GetRequestStream()
$streamWriter = New-Object System.IO.StreamWriter($requestStream)
$streamWriter.Write($body)
}
finally
{
if ($null -ne $streamWriter) { $streamWriter.Dispose() }
if ($null -ne $requestStream) { $requestStream.Dispose() }
}
$res = $request.GetResponse()
Here, give this a shot. I provided some in-line comments. Bottom line, you're going to want to use the HttpWebRequest class from the .NET Base Class Library (BCL) to achieve what you're after.
$Body = #"
<wInput>
<uInputValues>
<uInputEntry value='$arg' key='stringArgument'/>
</uInputValues>
<eDateAndTime></eDateAndTime>
<comments></comments>
</wInput>
"#;
# Convert the message body to a byte array
$BodyBytes = [System.Text.Encoding]::UTF8.GetBytes($Body);
# Set the URI of the web service
$URI = [System.Uri]'http://www.google.com';
# Create a new web request
$WebRequest = [System.Net.HttpWebRequest]::CreateHttp($URI);
# Set the HTTP method
$WebRequest.Method = 'POST';
# Set the MIME type
$WebRequest.ContentType = 'application/xml';
# Set the credential for the web service
$WebRequest.Credentials = Get-Credential;
# Write the message body to the request stream
$WebRequest.GetRequestStream().Write($BodyBytes, 0, $BodyBytes.Length);
This method downloads binary content:
# PowerShell 2 version
$WebRequest=New-Object System.Net.WebClient
$WebRequest.UseDefaultCredentials=$true
#$WebRequest.Credentials=(Get-Credential)
$Data=$WebRequest.DownloadData("http://<url>")
[System.IO.File]::WriteAllBytes("<full path of file>",$Data)
# PowerShell 5 version
Invoke-WebRequest -Uri "http://<url>" -OutFile "<full path of file>" -UseDefaultCredentials -ContentType