Powershell WebRequest GET Succeeds but DELETE fails w/ 404 - rest

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

Related

Scanner API Call using PowerShell for multiple PowerBI workspaces

I'm trying to call a PowerBI GETinfo Scanner API using PowerShell. One of the requirements is to pass multiple workspaces to get the info. Here is the MS doc link :\
https://learn.microsoft.com/en-us/rest/api/power-bi/admin/workspace-info-post-workspace-info#example
However, I'm not able to pass below syntax for API body in PowerShell.
The below syntax to call multiple workspaces in API body is not working :
$auth_body =#{
"workspaces": [
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
]
}
I'm only able to pass single workspace and below syntax works :
$auth_body =#{'workspaces' ="3b7e9b1c-bdac-4e46-a39d-1b3d24a0e122"}
Please help me to form the syntax for multiple workspaces. Seems I'm not able to form key value pair inside PowerShell for multiple workspaces
Updated Code after applying MathiasR.Jessen suggestion:
$authority = 'https://login.microsoftonline.com/oauth2/'+ $tenantID
$authResult = Get-AdalToken -Authority $authority -Resource $resourceAppIdURI -ClientID $UId -Clientsecret $password -TenantID $tenantID
$Token=$authResult.AccessToken
#Write-Output "Token: $Token"
$auth_header = #{
'Accept' = "application/json";
'Authorization' = 'Bearer ' +$Token
}
$auth_body = #{
"workspaces" =
#("50c4bd8e-fc75-433e-a0cd-755f9329515e","97d03602-4873-4760-b37e-1563ef5358e3")
}
$uri = "https://api.powerbi.com/v1.0/myorg/admin/workspaces/getInfo"
$all_workspace = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $auth_body –Method Post)
And Error Message :
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
+ ... rkspace1 = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
However, It works perfectly if I provide single workspace.
You're mixing PowerShell and JSON syntax.
To define an array in PowerShell, use the #() array subexpression operator:
$auth_body = #{
"workspaces" = #(
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
)
}

Team City build step with Powershell Invoke-RestMethod fails if URI contains URL encoded value

I have a build step in TeamCity which sends an HTTP request, like this:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Token", "%TOKEN%")
$uri = 'https://host/apps/branches/%BRANCH_NAME%/builds'
$response = Invoke-RestMethod $uri -Method 'GET' -Headers $headers
Write-Host "##teamcity[setParameter name='url' value='$uri']"
It works perfectly when %BRANCH_NAME% actually contains simple branch names, like ' master', 'beta', 'dev'.
But it works not so good when %BRANCH_NAME% is release%2F2019-DEC (URL encoded value of release/2019-DEC)
I tried the same script on local Powershell, and it worked flawlessly, but when I run it as TeamCity build step I receive the following error:
Invoke-RestMethod : The remote server returned an error: (404) Not Found.
At C:\TeamCityBuildAgent4\temp\buildTmp\powershell7367326510068615884.ps1:5 char:13
+ $response = Invoke-RestMethod $uri -Method 'GET' -Headers $headers
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
##teamcity[setParameter name='url' value='https://host/app/branches/release%2F2019-DEC/']
I tried to escape the percent sign using the extra % sign as in Using the percent sign in TeamCity build scripts, but unfortunately, it returns the same error.
Any ideas?
Solved:
Seemingly issue was caused by the old version of PowerShell on Agent, which caused the behavior described in Team City build step with Powershell Invoke-RestMethod fails if URI contains URL encoded value
That means that no extra percent signs are actually needed, we can URL encode value inside the script.
So the final version will look like:
function fixuri($uri){
$UnEscapeDotsAndSlashes = 0x2000000;
$SimpleUserSyntax = 0x20000;
$type = $uri.GetType();
$fieldInfo = $type.GetField("m_Syntax", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic));
$uriParser = $fieldInfo.GetValue($uri);
$typeUriParser = $uriParser.GetType().BaseType;
$fieldInfo = $typeUriParser.GetField("m_Flags", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::FlattenHierarchy));
$uriSyntaxFlags = $fieldInfo.GetValue($uriParser);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $UnEscapeDotsAndSlashes);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $SimpleUserSyntax);
$fieldInfo.SetValue($uriParser, $uriSyntaxFlags);
}
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-API-Token", "%TOKEN%")
$branch = [System.Web.HttpUtility]::UrlEncode('release/2019-DEC1')
$uri = New-Object System.Uri -ArgumentList ("https://host/apps/branches/$branch")
fixuri $uri
$response = Invoke-RestMethod $uri -Method 'GET' -Headers $headers
Special thanks to #Peska

Problem to connect to TFS with user/password

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()

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

PowerShell Error: The Underlying connection was closed

I am trying to use the Invoke-WebRequest cmdlet (for the first time) to connect to the web interface for a Sharp printer. So far, the code I have is the following:
$cred = Get-Credential
$url = 'http://<IP address of printer>/login.html?/main.html'
$login = Invoke-WebRequest $url -SessionVariable printer -Method Get
$login.Forms[0].Fields.element10002 = $cred.UserName
$login.Forms[0].Fields.element10002 =
$cred.GetNetworkCredential().Password
$mainPage = Invoke-WebRequest -Uri ($url + $login.Forms[0].Action) `
-WebSession $printer -Body $login -Method Post
...but I keep getting this error:
Invoke-WebRequest : The underlying connection was closed: The connection
was closed unexpectedly.
At line:6 char:13
+ $mainPage = Invoke-WebRequest -Uri ($url + $login.Forms[0].Action) -W
...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:
(System.Net.HttpWebRequest
:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId :
WebCmdletWebResponseException,Microsoft.Powe
rShell.Commands.InvokeWebRequestCommand
This line of code does not cause an error:
$login = Invoke-WebRequest $url -SessionVariable printer -Method Get
But this line does:
$mainPage = Invoke-WebRequest -Uri ($url + $login.Forms[0].Action) `
-WebSession $printer -Body $login -Method Post
I am using PS version 5.1, and Tls12 on a Windows 7 box. After some Googling, it seems like this problem might have something to do with the version of Tls. but I'm not sure what to change it to.
Does anybody have any ideas? - #leah_cyberpadawan
The following two solutions have worked for me when working with endpoints that may have self-signed certificates or TLS 1.2-only supported:
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
Add-Type -TypeDefinition #'
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy
{
public bool CheckValidationResult(ServicePoint sp, X509Certificate cert, WebRequest req, int certProblem)
{
return true;
}
}
'#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object -TypeName TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}