I have the following REST URL:
https://webserviceconsume.domain.local/web/api/rest?formatType=json&opName=userAPI&opData={param0:"sample",param1:{"list":[{"name1":"sample1","value1":"sample1"},{"name2":"sample2","value2":"sample2"}]},param2:-1}
I want to write a PowerShell script to call this URI. It should basically look like this:
$response = Invoke-RestMethod -Uri 'https://webserviceconsume.domain.local/web/api/rest' -Body $body -Headers $headers -ContentType "application/json"
Here's the header:
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("accept", 'application/json')
$headers.Add("X-App-Key", 'XXXXX')
and then I want to build the $body but don't know how to do it.
Try the below variable as body.
$body = [PSCustomObject]#{
param0 = 'sample';
param1 = #{
list = #(
#{name1 = "sample1"; value1 = "sample1"};
#{name2 = "sample2"; value2 = "sample2"}
)
};
param2 = -1
} | ConvertTo-Json -Depth 3
Using Rest with PowerShell is a very common thing, with many blog posts, articles and Youtube Videos explaining the topic and showing examples.
Simple Examples of PowerShell's Invoke-RestMethod
# Simple GET example
$response = Invoke-RestMethod 'http://example.com/api/people'
# assuming the response was in this format { "items": [] }
# we can now extract the child people like this
$people = $response.items
# GET with custom headers example
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-DATE", '9/29/2014')
$headers.Add("X-SIGNATURE", '234j123l4kl23j41l23k4j')
$headers.Add("X-API-KEY", 'testuser')
$response = Invoke-RestMethod 'http://example.com/api/people/1' -Headers $headers
# PUT/POST example
$person = #{
first='joe'
lastname='doe'
}
$json = $person | ConvertTo-Json
$response = Invoke-RestMethod 'http://example.com/api/people/1' -Method Put -Body $json -ContentType 'application/json'
# DELETE example
$response = Invoke-RestMethod 'http://example.com/api/people/1' -Method Delete
I've only been using PowerShell for 3 days now so this may not be the most efficient code but it's what is working for me
$URL = ""
$Method = 'PUT'
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$Headers.Add("accept", 'application/json')
$Headers.Add("X-App-Key", 'XXXXX')
$Body = ""
$Out = ".\response.json"
$response =
#{
Uri = $URL
Method = $Method
Headers = $Headers
Body = $Body
}
Invoke-RestMethod #response | ConvertTo-Json | Out-File $Out
Related
I'm using the following code to change a Pre-shared key for MEraki, however, at the moment I'm only able to do it statically.
I'd like to automate the code so that the PSK is an actual variable.
I've tried using the " or ' however in either scenario i'm unable to recall the variable into the array, and my end goal is to automate this script so that I can just run it and poof, off it goes.
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11
function Get-RandomCharacters($length, $characters) {
$random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
$private:ofs=""
return [String]$characters[$random]
}
function Scramble-String([string]$inputString){
$characterArray = $inputString.ToCharArray()
$scrambledStringArray = $characterArray | Get-Random -Count $characterArray.Length
$outputString = -join $scrambledStringArray
return $outputString
}
$password = Get-RandomCharacters -length 5 -characters 'abcdefghiklmnoprstuvwxyz'
$password += Get-RandomCharacters -length 1 -characters 'ABCDEFGHKLMNOPRSTUVWXYZ'
$password += Get-RandomCharacters -length 1 -characters '1234567890'
$password = Scramble-String $password
$newDailyPassword = $password
$newDailyPassword
#Meraki API KEY
$api_key = "API_KEY"
#Meraki Network URL
$network_id = "NETWORK_ID"
#Base API URL
$api = #{
"endpoint" = 'https://api.meraki.com/api/v0'
}
#API URL for SSID PSK Change XXX
$api_put = #{
"endpoint" = 'https://nXXX.meraki.com/api/v0'
}
$header_org = #{
"X-Cisco-Meraki-API-Key" = $api_key
"Content-Type" = 'application/json'
}
# PSK = New password
$data = #{
"psk" = $newDailyPassword **#----> I'd like this to be the new daily password variable. Is there a way to do this?**
}
#Convert data to Json format
$jbody = ConvertTo-Json -InputObject $data
#URL Network_ID and SSID number
$api.ssid = "/networks/$network_id/ssids/2"
#Combine base api_put URL and $api.ssid
$Merakiuri = $api_put.endpoint + $api.ssid
Invoke-RestMethod -Method Put -Uri $Merakiuri -Headers $header_org -Body $jbody -Verbose
EDIT1: I've managed to resolve this, by applying the concatination of the variable string, as I was parsing unexpected query via JSON (single string).
I've done the below.
$JsonJoiner = "'"
$passwordx = -join($JsonJoiner,$password, $JSonJoiner)
$newDailyPassword = $passwordx
now, whenever I parse the
$newDailyPassword
the correct value is parsed, and i'm able to generate the PW.
I am hitting this url
https://webadmin.td90.centile-dev.com/restletrouter/v1/service/Login
Then i am getting the session and passing into the url below
https://myistra.td90.centile-dev.com/restleroute/v1/3rdParty/AdmtiveDomain.
Problem
Output
Invoke-WebRequest : Unauthorized
The request requires user authentication
You can get technical details here.
Please continue your visit at our home page.
At C:\Users\administrator\Documents\CDR.ps1:20 char:213
+ ... 'Session' | Invoke-WebRequest -Uri ("https://myistra.td90.centile-
dev ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:
(System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
thirdParty_SESSIONID=969514241160310577; _ac958=http://10.20.100.190:8078
Here is my code
$user = "SuperGabriel"
$pass = "SuperGabriel#2019"
$pair = "$($user):$($pass)"
$encodedCreds =
$basicAuthValue = "Basic $encodedCreds"
$PartOneHeaders = #{
"Authorization" = $basicAuthValue
"X-Application" = "3rdParty"
}
#test
$Headers =#{
"X-Application" = "3rdParty"
"Cookie"= "thirdParty_SESSIONID=7353595784495763113;"
}
$PartOneWebRequest = Invoke-WebRequest -Uri https://webadmin.td90.centile-
dev.com/restletrouter/v1/service/Login -Headers $PartOneHeaders -
ContentType "application/json" -Method POST -SessionVariable 'Session' |
Invoke-WebRequest -Uri ("https://myistra.td90.centile-
dev.com/restleroute/v1/3rdParty/AdmtiveDomain" ) -Headers $Headers -
Method Get
I have echoed everything out to make sure i am getting the right information and passing it into the right places.
I have tested the call in postman and it works.
Expected results
[
{
"restUri": "v1/3rdParty/AdmtiveDomain/0.",
"alias": "TopLevelAdmtiveDomain",
"rootModel": "AdmtiveDomain",
"domainName": "Top-Level",
"admtiveDomainID": "0."
},
{
"restUri": "v1/3rdParty/AdmtiveDomain/0.106.",
"alias": "AdmtiveDomainSpecific",
"rootModel": "AdmtiveDomain",
"domainName": "acd-00",
"domainType": "Enterprise",
"admtiveDomainID": "0.106."
}
]
[System.Uri]$Uri = "https://webadmin.td90.centile-dev.com/restletrouter/v1/service/Login" # Add the Uri
[System.Uri]$Uri_Get = "https://webadmin.td90.centile-dev.com/restletrouter/v1/3rdParty/AdmtiveDomain"
$ContentType = "application/json" # Add the content type
$Method = 'POST' # Add the method type
$user = "SuperGabriel"
$pass = "SuperGabriel#2019"
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds"
$Headers = #{
# Add name and value of headers
"Authorization" = $basicAuthValue
"Cookie" = "thirdParty_SESSIONID=6335513255659796064"
"X-Application" = "3rdParty"
}
$Headers_Get = #{
# Add name and value of headers
"Cookie" = "thirdParty_SESSIONID=4436753218874838616; thirdParty_SESSIONID=6335513255659796064;"
"X-Application" = "3rdParty"
"Host" = "webadmin.td90.centile-dev.com"
"Content-Type"= "$ContentType"
}
$Headers_Get2 = #{
# Add name and value of headers
"Cookie" = "thirdParty_SESSIONID=1312545750448673312"
"X-Application" = "3rdParty"
"Host" = "webadmin.td90.centile-dev.com"
"Content-Type"= "$ContentType"
}
# Splat the parameters
$props = #{
Uri = $Uri
Headers = $Headers
ContentType = $ContentType
Method = $Method
}
$props_Get = #{
Uri = $Uri_Get
Headers = $Headers_Get
ContentType = $ContentType
Method = "GET"
}
try
{
$Result= Invoke-RestMethod #props -SessionVariable sess -OutFile C:\output.json
echo $Result
$Result1= Invoke-RestMethod #props_Get -OutFile C:\"$DateStr".json -WebSession $sess
echo $Result1
}
catch [System.Net.WebException]
{
$res = $_.Exception.Response
echo $res
}
Will work as per your request.
Cheers..
i need to write a powershell script to connect to a REST API and to output into a text file stored locally. How do i write it such that if the REST API has issues and timeout without returning a response, the powershell script will trigger an email to send out when the saved text file is empty?
Also, how do i append the date to the saved text file for eg. c:\scripts\response_DDMMYYYY.txt
Below are my current powershell script. Newbie at powershell scripting. Hope someone can enlighten me.
Thanks alot!
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object
TrustAllCertsPolicy
$url = "https://someapi.com/get_info"
$token = '12345'
$header = #{Authorization = "Bearer $token" }
$body = #{code = "ABC"}
$result = Invoke-RestMethod -Method POST -Uri $url -ContentType
'application/json' -Body (ConvertTo-Json $body) -Header $header
$result | ConvertTo-Json -depth 100 | Set-Content "c:\scripts\response.txt"
Edited based on kumar's advice:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object
TrustAllCertsPolicy
$url = "https://someapi.com/get_info"
$token = '12345'
$header = #{Authorization = "Bearer $token" }
$body = #{code = "ABC"}
try {
$result = Invoke-RestMethod -Method POST -Uri $url -ContentType
'application/json' -Body (ConvertTo-Json $body) -Header $header
$time = (Get-Date).ToString("DD-MM-YYYY")
$result | ConvertTo-Json -depth 100 | Set-Content "c:\scripts\response-
"+$time+".txt"
} catch {
Write-Host "StatusCode: " $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:"
$_.Exception.Response.Status.StatusDescription
Send-MailMessage -To "ABC<abc#gmail.com>" -From "server <admin#abc.com>"
-Subject "Error with sync to server"
}
You have a few options to get the response status code of the REST call like so..
try {
Invoke-RestMethod ... your parameters here ...
} catch {
# Dig into the exception to get the Response details.
# Note that value__ is not a typo.
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
}
& Use the Send-MailMessage
Send-MailMessage -To "User01 <user01#example.com>" -From "User02 <user02#example.com>" -Subject "Test mail"
Also, how do i append the date to the saved text file for eg. c:\scripts\response_DDMMYYYY.txt
A simple and nice way is:
$time = (Get-Date).ToString("DD-MM-YYYY")
and simply
("C:\scripts\response-"+$time+".txt")
I'm still having issues with getting json working with the curl command in powershell.
even a simple request to POST something into elastic fails miserably with the error
Unexpected character ('D' (code 68)): was expecting double-quote to start field name
I've stripped the script down to the basics just to try and test curl and json and still get failures
$curlExe = "h:\powershell\esb\elastic\curl\curl.exe"
$elasticdata = #{
timereceived = "test"
timesent = "testing"
name = "anon"
status = 0
}
$curldata = $elasticdata | convertto-json -Compress
$elasticoutput = "h:\powershell\esb\elastic\elastic.txt"
$elastichost = "http://localhost:9200/newtest20/filecopy/?pretty"
$elasticheader = "content-type: application/json"
$elamethod = "POST"
$curlargs = $elastichost,
'-X',$elamethod,
'-d',$curldata,
'-H',$elasticheader
& $curlexe #curlargs
If your server is running Powershell 2.0 you will not have Invoke-webRequestbut ConvertTo-Json will also be missing.
I also encountered this issue in the past and I made these functions to workaround that issue
function Invoke-WebRequest([string] $Url, [string] $Method, $BodyObject)
{
$request = [System.Net.WebRequest]::Create($Url)
$request.Method = $Method
$request.ContentType = "application/json"
if ($Method -eq "POST")
{
try
{
$body = ConvertTo-Json20 -InputObject $BodyObject
$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() }
}
}
$response = $request.GetResponse()
if ($response.StatusCode -ne [System.Net.HttpStatusCode]::OK)
{
throw "ERROR Could not $Method url [$Url]"
}
return $response
}
function ConvertTo-Json20($InputObject){
Add-Type -Assembly System.Web.Extensions
$jsonSerializer = New-Object System.Web.Script.Serialization.JavascriptSerializer
return $jsonSerializer.Serialize($InputObject)
}
I have a question around processing some data which I am pulling from VMWARE vROPS 6.X.
Basically I wrote a script to pull metric data from the suite API. I almost have the format I want but i need to split the Metric and Timestamp column one step further.
Basically I built a foreach loop and then nested another inside but I was not getting the metrics and timestamps in the correct sequence (so I removed it from the code below).
Current output:
"resourceId","Timestamp","METRIC","value"
"ef951a38-3063-477d-af32-baa6d2744357","1466085599999 1466171999999","cpu:1|costop_summation","4.6296298710836307E-4 0.0 4.5836298710836307E-4 0.0"
"ef951a38-3063-477d-af32-baa6d2744357","1466085599999 1466171999999","mem|usage_average","12.678446789582571 15.390000343322754"
Desired output:
"resourceId","Timestamp","METRIC","value"
"ef951a38-3063-477d-af32-baa6d2744357","1466085599999","cpu:1|costop_summation","4.6296298710836307E-4 0.0"
"ef951a38-3063-477d-af32-baa6d2744357","1466171999999","cpu:1|costop_summation","4.5836298710836307E-4 0.0"
"ef951a38-3063-477d-af32-baa6d2744357","1466085599999","mem|usage_average","12.678446789582571"
"ef951a38-3063-477d-af32-baa6d2744357","1466171999999","mem|usage_average","15.390000343322754"
My Code:
#Call vROPS SUITE-API with Invoke-Rest
#Take all certs.
Add-Type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
#date
[DateTime]$StartDate = (Get-date).adddays(-5)
[DateTime]$EndDate = (Get-date)
$StartDateEpoc = Get-Date -Date $StartDate -UFormat %s
$EndDateEpoc = Get-Date -Date $EndDate -UFormat %s
#Variables
$username = "admin"
$password = "password"
$secPw = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object PSCredential -ArgumentList $username,$secPw
$ContentType = "application/xml;charset=utf-8"
$header = New-Object "System.Collections.Generic.Dictionary[[String,[String]]"
$header.Add("Accept", 'application/xml')
#intervalType=
$SECONDS = 'SECONDS'
$MINUTES = 'MINUTES'
$HOURS = 'HOURS'
$DAYS = 'DAYS'
#rollUpType=
$AVG = 'AVG'
$MAX = 'MAX'
$SUM = 'SUM'
$MIN = 'MIN'
$COUNT = 'COUNT'
Invoke-RestMethod -Method GET -uri "https://192.168.0.125/suite-api/api/resources/stats?resourceId=ef951a38-3063-477d-af32-baa6d2744357&resourceId=1ef459e5-789e-446b-9852-3dc92c43e74a&statKey=cpu|usage_average&rollUpType=$AVG&intervalType=$DAYS" -Credential $cred -ContentType $ContentType -Headers $header -OutFile d:\quickcheck.xml
[xml]$Data = Get-Content 'D:\quickcheck.XML'
$report = #()
$resources = $Data.'stats-of-resources'
$UUIDS = $Resource.'resourceId'
foreach ($Resource in $Resources.'stats-of-resource') {
foreach ($node in $Resource.'stat-list'.stat)
{
#Collection Date, not run time
$MetricName = $node.statKey.Key
$Values = #($node.data -replace '( \d\.\d) ',"`$1`n" -split "`n")
$Timestamps = #($node.timestamps -split ' ')
for ($i=0; $i -lt $Values.Count -and $i -lt $Timestamps.Count; $i++) {
$report += New-Object PSObject -Property #{
METRIC = $MetricName
resourceId = $Resource.'resourceId'
Timestamp = $Timestamps[$i]
value = $Values[$i]
}
}
}
$report | Export-Csv D:\reprop.csv -NoTypeInformation
Split $Timestamps at spaces and $Values at every second space, and create an object for each resulting pair of fragments, e.g. like this:
$Values = #($Values -split ' ')
$Timestamps = #($Timestamps -split ' ')
for ($i=0; $i -lt $Values.Count -and $i -lt $Timestamps.Count; $i++) {
$report += New-Object PSObject -Property #{
METRIC = $MetricName
resourceId = $Resource.'resourceId'
Timestamp = $Timestamps[$i]
value = $Values[$i]
}
}